web-dev-qa-db-ja.com

Swift

位置情報サービスのバックグラウンドモードをオンにして、位置(緯度と経度)を30分ごとにサーバーに送信することを目指しています。今のところ、同じものをコンソールに出力しています。しばらく動作しているようですが、この場合、NSTimerをどのように動作させるのでしょうか。そして、どこからそれを呼ぶべきですか?

import UIKit
import CoreLocation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {

    var window: UIWindow?
    var locationManager = CLLocationManager()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    func applicationWillResignActive(application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

        self.locationManager.delegate = self
        self.locationManager.startUpdatingLocation() // I know i should be using signification location option here. this is just for testing now.
    }

    func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
        self.sendBackgroundLocationToServer(newLocation);
    }

    func sendBackgroundLocationToServer(location: CLLocation) {
        var bgTask = UIBackgroundTaskIdentifier()
        bgTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler { () -> Void in
            UIApplication.sharedApplication().endBackgroundTask(bgTask)
        }

        println(location.coordinate.latitude)

        if (bgTask != UIBackgroundTaskInvalid)
        {
            UIApplication.sharedApplication().endBackgroundTask(bgTask);
            bgTask = UIBackgroundTaskInvalid;
        }
    }

    func applicationWillEnterForeground(application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        application.beginBackgroundTaskWithExpirationHandler{}
    }

    func applicationDidBecomeActive(application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        application.beginBackgroundTaskWithExpirationHandler{}
    }

    func applicationWillTerminate(application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        application.beginBackgroundTaskWithExpirationHandler{}
    }


}

多分application.beginBackgroundTaskWithExpirationHandler{}は悪い考えですか?ここにはどのようなオプションがありますか?

15
psharma

beginBackgroundTask...のアイデアは、有限長のタスクを開始して、ユーザーがアプリを離れた場合に、バックグラウンドタスクで一定の短い期間(3分、私は信じている)実行し続けることです。時間がなくなる前に、endBackgroundTaskを呼び出す必要があります。そうしないと、アプリはすぐに終了します。

したがって、残念ながら、バックグラウンドタスクメカニズムは、意図した目的にはあまり適していません。ただし、狭い機能セット(VOIP、オーディオなど)の外部で継続的なバックグラウンド操作用に設計された特別なバックグラウンドモードの狭いセットがあります。詳細については、「 iOS用アプリプログラミングガイド:バックグラウンド実行/」の長期実行タスクの実装セクションをご覧ください。

現在、これらのバックグラウンドモードの1つは「位置情報」サービス用です。そのため、それがアプリの中心的な機能であり、適切な機能に不可欠である場合は、locationバックグラウンドモードに登録して、アプリをバックグラウンドで実行し続けることができます。そこから、ロケーションの更新を監視し、十分な時間が経過した場合は、いくつかのプロセスをトリガーできます。ただし、このバックグラウンドロケーションモードがアプリの必須機能ではない場合、Appleは、必要のないバックグラウンドモードをリクエストすることでアプリを拒否する可能性があります。


ところで、標準の位置情報サービスを開始すると、デバイスのバッテリーが消耗する可能性があることに注意してください。バッテリー効率のよい "大幅な変更"位置情報サービス の使用を検討してください。これには、ユーザーがかなりの距離を移動するたびにアプリを自動的に起動するという利点もあります(たとえば、kmで測定されます。これは、別のセルタワーに移動することによってトリガーされると思います)。

10
Rob

いくつか注意点があります。私たちは位置情報の問題と戦い、目覚めさせていないように見えるバックグラウンドアプリケーションと格闘しているからです。

  1. NSTimerは、アプリケーションが中断されていない場合にのみ有効です。確かに、それはバックグラウンドですが、iOS(APN、場所など)からの通知を受け取ることができるのはininasmuchasだけです。最終的に、BGで実行している間、タイマーは発砲を停止します。だから、あなたはあなたを蹴るのにBGモードの1つに頼っています。

  2. CLLocationManager.startUpdatingLocationを使用している場合、少し後にそれらの取得を終了することに気づくでしょう。特に電話がリラックスして眠ろうとするとき。これは、CLLocationManager.pausesLocationUpdatesAutomaticallyと呼ばれる機能が十分に文書化されていないためです。 "true"(DEFAULT設定)に設定すると、これらの送信を停止することを決定します。これを「false」に設定すると、引き続き位置情報を取得できます。これにより、アプリが確実に期待どおりの動作をするようになります。

  3. 上記のように、locationManager.didUpdateLocationsコールバックを取得したら、backgroundTaskを開始して、その情報を処理し、ネットワークデータを送信している間、アプリケーションを機能させ続ける必要があります。しかし、あなたはそれを理解しているようです。

  4. 場所の更新を「記録」するのに十分な時間だけ目を覚ますことはそれほど悪くありません。 30分の期待値を明確に満たしていない限り、ネットワークコードを生成しないようにしてください。

8
GNewc

これを試して:

  • 位置情報サービスのシングルトンを作成します。 NSNotificationに登録しました
  • AppDelegatewillEnterBackGroundでは、NSNotificationCenter経由で通知を送信します

次に、シングルトンはupdatingLocationを開始し、場所のデータを受信するとサーバーに送信します。

3
Pham Hoan