5

ユーザーの位置を常に追跡する必要があります(ただし、バッテリーを消耗させないでください)。アプリの終了後に更新を取得する唯一の方法は、startMonitoringSignificantLocationChanges を使用することだと理解しています。

startMonitoringSignificantLocationChanges に関する Apple の Location Awareness Programming Guide から:

このサービスを開始してからアプリケーションを終了すると、新しいイベントが到着すると、システムは自動的にアプリケーションをバックグラウンドで再起動します。このような場合、アプリケーション デリゲートの application:didFinishLaunchingWithOptions: メソッドに渡されるオプション ディクショナリには、ロケーション イベントのためにアプリケーションが起動されたことを示すキー UIApplicationLaunchOptionsLocationKey が含まれます。再起動時に、引き続きロケーション マネージャー オブジェクトを構成し、このメソッドを呼び出してロケーション イベントを受信し続ける必要があります。位置情報サービスを再起動すると、現在のイベントがデリゲートにすぐに配信されます。さらに、ロケーション サービスを開始する前であっても、ロケーション マネージャー オブジェクトのロケーション プロパティには最新のロケーション オブジェクトが取り込まれます。

誰かがコードで(例を挙げて)どのメソッドを使用すべきかを示すことができれば幸いです

次のコードでは、次のことを試みています。 - appdelegate でロケーション マネージャーを開始します。- didUpdateToLocation で stopupdating を呼び出しています - didFinishLaunchingWithOptions で、UIApplicationLaunchOptionsLocationKey を取得したかどうかを確認して、バックグラウンドにいるかどうかを確認し、重要なモニターの場所の更新のために起動しました。- もしそうなら、startMonitoringSignificantLocationChanges を再度呼び出し (理由はわかりません...)、startupdating メソッドを呼び出すために UIBackgeoundTaskIdentifier を開始します。

LocationController.m : 
+ (LocationController*)sharedInstance {
    @synchronized(self) {
        if (sharedCLDelegate == nil) {
            [[self alloc] init];
        }
    }
    return sharedCLDelegate;
}

- (id)init
{
    self = [super init];
    if (self != nil) {
        self.locationManager = [[[CLLocationManager alloc] init] autorelease];
        self.locationManager.delegate = self;
        self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
        [self.locationManager startUpdatingLocation];
        [self.locationManager startMonitoringSignificantLocationChanges];

    }
    return self;
}
- (void) startMonitoringSignificantLocationChanges
{
    [self.locationManager startMonitoringSignificantLocationChanges];
}
- (void) stopMonitoringSignificantLocationChanges
{
    [self.locationManager stopMonitoringSignificantLocationChanges];
}
-(void) start{
    [self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation{
    if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 30) {
        self.lastLocation = newLocation;
        [self updateLocation]; //sending location to server
        [self.locationManager stopUpdatingLocation];
    }
}
- (void)locationManager:(CLLocationManager*)manager
       didFailWithError:(NSError*)error{
    [self.locationManager stopUpdatingLocation];
}

AppDelegate.h : 

@interface AppDelegate : NSObject <UIApplicationDelegate> {
    UIBackgroundTaskIdentifier bgTask;
}

AppDelegate.m : 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
        id locationValue = [launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey];
        if (locationValue) {
            [[LocationController sharedInstance] startMonitoringSignificantLocationChanges];
            UIApplication *app  = [UIApplication sharedApplication];
            bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
                [app endBackgroundTask:bgTask]; 
                bgTask = UIBackgroundTaskInvalid;
            }];
            [[LocationController sharedInstance] start]; //startupdating
            return YES;
        }
    else { 
            [[LocationController sharedInstance] init];
    }
}
-(void) applicationDidEnterBackground:(UIApplication *) application
{
    NSLog(@"entered background Mode");
}

-(void) applicationDidBecomeActive:(UIApplication *) application
{
    NSLog(@"application Did Become Active");
}

ありがとうございました。

4

1 に答える 1

10

あなたのクラスを使用して、これが私がすることです。

AppDelegate.m で、アプリがフォアグラウンドまたはバックグラウンドにある場合、CLLocationManager をフォアグラウンド/バックグラウンドで実行するように移動して一致させます。私がこれを行っている理由は、アプリがバックグラウンドにあるときに CLLocationManager がバックグラウンドに移動されない場合、CLLocationManager のコールバックに場所の更新が送信されないためです。

- (void)applicationDidEnterBackground:(UIApplication *) application {
    [[LocationController sharedInstance] stop];
    [[LocationController sharedInstance] startMonitoringSignificantLocationChanges];
    NSLog(@"entered background Mode");
}

- (void)applicationDidBecomeActive:(UIApplication *) application {
    [[LocationController sharedInstance] stopMonitoringSignificantLocationChanges];
    [[LocationController sharedInstance] start];
    NSLog(@"application Did Become Active");
}

そのため、アプリがバックグラウンドに移動し、しばらくすると、iOS がメモリの使用量が多すぎると判断し、アプリを強制終了したとします。

数分後、iOS は位置情報の更新を受信し、アプリを再起動して、位置情報サービスが原因でアプリが再起動したことを通知します。その後、バックグラウンドの位置情報サービスを再起動する必要があります。これは、アプリがそうしなければならない唯一の機会になるためです。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
        [[LocationController sharedInstance] startMonitoringSignificantLocationChanges];
    }
    return YES;
}

ああ、最後にもう 1 つ変更があります。なぜあなたのlocationManager:didUpdateToLocation:fromLocation:方法で位置情報サービスを停止しているのかわかりません。停止すると、更新が行われなくなります。実行したままにしておくと、場所の変更が発生するたびに、それをサーバーに送信できます。

- (void)locationManager:(CLLocationManager *)manager 
    didUpdateToLocation:(CLLocation *)newLocation 
           fromLocation:(CLLocation *)oldLocation {

    if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 30) {
        self.lastLocation = newLocation;
        [self updateLocation]; //sending location to server

}
于 2013-03-02T05:20:20.327 に答える