4

現在、バックグラウンドで位置を確認する必要がある iOS アプリを開発中です。最初は、重要な場所の変更を使用しようとしましたが、十分に正確ではなく、十分な頻度でトリガーされませんでした。地域監視の使用を検討しましたが、オンラインで読んだところ、それも必ずしも正確ではなく、監視する地域の数が限られているという問題もあります. (最終的にはリージョン モニタリングを試す可能性があります。) ただし、現時点では、標準の位置更新を使用して、バックグラウンドでユーザーの位置を追跡しようとしています。5 分程度の間隔でチェックする予定です。 .

アプリはバックグラウンドで位置情報の更新のために登録され (「必要なバックグラウンド モード」の「位置情報の更新のためのアプリ登録」を使用)、位置情報を 1 回チェックするバックグラウンド タスクを開始し、位置情報の更新を停止してNSThread sleepForTimeInterval:から (現時点では、開発中です) タスクを 10 秒間一時停止します。その後、もう一度位置を確認し、位置の更新を停止し、10 秒間一時停止します。

これは期待どおりに動作するようです...アプリがバックグラウンドになると、10 秒ごとに位置情報が更新されたログ/通知を受け取り、アプリを再度開くと、ログ/通知が停止します。ただし、問題は、アプリが 2 度目にバックグラウンドに移行したときに、元のバックグラウンド タスクがキャンセルされていないように見え、新しいタスクが作成されたため、2 つのタスクが実行され、それぞれが 10 秒で場所を確認することです。間隔で。アプリが複数回開かれたり、バックグラウンドに送信されたりすると、それぞれのバックグラウンド タスクが開始されます。

「アプリは少なくとも 1 回はバックグラウンドに送られましたか?」というフラグを設定し、初めてバックグラウンドに送られる場合にのみタスクを実行することを考えましたが、これにより別の問題が発生するようで、(比較的新しい iOS 開発者) アプリがフォアグラウンドに入ったときにバックグラウンド タスクがキャンセルされない理由が気になります。

AppDelegate.h ファイルには次のものが含まれています...

@interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate> {
    UIWindow *window;
    UINavigationController *navigationController;

    UIBackgroundTaskIdentifier bgTask;
    BOOL inBackground;
}

AppDelegate.m ファイルには次のものが含まれています...

- (void)applicationDidEnterBackground:(UIApplication *)application {
    inBackground = YES;

    bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (inBackground == YES) {
            NSLog(@"%@", @"Check location...");
            [locationManager startUpdatingLocation];

            [NSThread sleepForTimeInterval:10];
        }

        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    });
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // 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.
    inBackground = NO;

    [[UIApplication sharedApplication] endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
}

位置情報の更新は期待どおりに機能しています。アプリがフォアグラウンドに入ったときにバックグラウンド タスクがキャンセル/終了されない理由がわかりません。と関係があるのかNSThread sleepForTimeInterval:​​ どうかはわかりませんが、そうであるかどうか、またはそれを修正する方法がわかりません(実際にそうである場合)。助けてくれてありがとう!

4

2 に答える 2

2

スリープ状態にしてから要求することによって位置情報の更新を管理することはありません。場所の更新を管理するには、「場所」を設定してUIBackgroundMode(これまでと同じように)、 を実装しCLLocationManagerDelegateます。これは とは関係ありませんbeginBackgroundTaskWithExpirationHandler:。これは、特定の操作を完了するために追加の時間 (最大約 10 分) を要求するためのものです。位置情報の更新を取得するためだけにそれを呼び出すべきではありません。

でロケーション アプリとして登録するとUIBackgroundMode、ロケーション マネージャーに指定した精度の範囲内でロケーションが変更されるたびに、自動的に更新が行われます。システムがすべての作業を行います。


あなたが説明していることは、複数の位置センサー(GPSはそのうちの1つにすぎません)を管理するOSの機能を妨げるため、実際にはバッテリー寿命を損なう可能性があります. 正確な精度を設定して必要なものを OS に伝え (大幅な変更が粗すぎる場合)、OS に任せます。GPS から本当に正確な位置を取得するにはコストがかかります。そのままにしておくよりも 5 分ごとに実行する方が安価であると考える前に、バッテリー テストを実行する必要があります。電力を維持するためにできる最善のことは、必要な精度を下げることです。粗いレベルまで下げてから、前景に来たら正確なレベルに移動します。しかし、ユーザーがどこにいるかを 5 分ごとに正確に追跡するには、コストがかかります。それを修正するのは難しいです。

ところで、ここで本当にやろうとしていることは、5 分ごとに「何か」を実行することです。iOS にはそのためのメカニズムはありません。位置情報サービスを要求することも、要求しないこともできます (さまざまな方法で構成できます)。「5分ごとに起きて…何でもしたい」と頼むことはできません。約 10 分後、電話しないと殺されますendBackgroundTask:

なぜタスクがキャンセルされないのかという質問については、How to use beginBackgroundTaskWithExpirationHandler for already running task in iOS を参照してください。私が言ったように、この「バックグラウンド タスク」は、この問題に必要なツールではありません。まったく無関係です。

于 2012-08-23T18:29:36.580 に答える
1

アプリがフォアグラウンドに戻ったときにインスタンス変数が再割り当てされていることはかなり確信しているbgTaskため、値には削除しようとしている識別子が含まれていません。NSUserDefaultsこの識別子をまたはもう少し永続的なものに保存し、後で取得することを検討してください。

于 2012-08-24T14:27:02.353 に答える