【问题标题】:Getting user location every n minutes after app goes to background应用程序进入后台后每 n 分钟获取一次用户位置
【发布时间】:2012-05-01 09:19:03
【问题描述】:

我正在尝试实施this post 中给出的建议。

不幸的是,我不清楚这些步骤。我尝试实施这些建议,但即使在我启动和停止 locationServices 之后,backgroundTimeRemaining 也会继续减少。这就是我开发它的方式:

- (void)applicationDidEnterBackground:(UIApplication *)application {

    UIApplication*    app = [UIApplication sharedApplication];

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

    // Start the long-running task and return immediately.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // Do the work associated with the task.
        self.timer = nil;
        [self initTimer];

    });
}

初始化定时器:

- (void)initTimer {

    // Create the location manager if this object does not
    // already have one.
    if (nil == self.locationManager)
        self.locationManager = [[CLLocationManager alloc] init];

    self.locationManager.delegate = self;
    [self.locationManager startMonitoringSignificantLocationChanges];

    if (self.timer == nil) {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3
                                              target:self
                                            selector:@selector(checkUpdates:)
                                            userInfo:nil
                                             repeats:YES];
    }
}

检查更新:

- (void)checkUpdates:(NSTimer *)timer{
    UIApplication*    app = [UIApplication sharedApplication];
    double remaining = app.backgroundTimeRemaining;
    if(remaining < 580.0) {
        [self.locationManager startUpdatingLocation]; 
        [self.locationManager stopUpdatingLocation]; 
        [self.locationManager startMonitoringSignificantLocationChanges];
    }
    DbgLog(@"Reminaing %f", app.backgroundTimeRemaining);
}

是否有人对我的代码中可能存在的问题提出建议? initTimer 和 checkUpdates 都被调用,但仅限于后台执行时间(+- 10 分钟)。我希望应用程序“永远”每 n 分钟更新一次位置。

我的应用的 UIBackgroundModes 设置为位置。

更新:

我现在正在重置 didUpdateToLocation 和 didFailWithError 上的计时器。但是 backgroundTimeRemaining 仍然在不断减少:

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

NSLog(@"Did Update Location = %f / %f", [newLocation coordinate].latitude, [newLocation coordinate].longitude);

UIApplication*    app = [UIApplication sharedApplication];

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

// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // Do the work associated with the task.

    [self initTimer];

});
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {

[self.locationManager stopUpdatingLocation]; 
UIApplication*    app = [UIApplication sharedApplication];

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

// Start the long-running task and return immediately.
[self initTimer];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // Do the work associated with the task.

});

}

我也让计时器失效:

- (void)checkUpdates:(NSTimer *)timer{
UIApplication*    app = [UIApplication sharedApplication];
double remaining = app.backgroundTimeRemaining;
if(remaining < 580.0 && remaining > 570.0) {
    [self.timer invalidate];
    self.timer = nil;
    [self.locationManager startUpdatingLocation]; 
    [self.locationManager stopUpdatingLocation]; 
}
DbgLog(@"*************************Checking for updates!!!!!!!!!!! Reminaing %f", app.backgroundTimeRemaining);
}

【问题讨论】:

  • App Store 是否接受您的应用程序?我正在考虑采用相同的方法,但我需要确保我的应用不会被拒绝。谢谢顺便说一句!
  • 你让它工作了吗/?
  • @scurioni 如何在“冷却”期间移除状态栏图标(在 stopUpdatingLocation 到下一个 startUpdatingLocation 之间)?即使在调用 stopUpdatingLocation 之后它仍然存在。该图标只有在显式调用 stopUpdatingLocation (从 ViewController 或类似的东西)后才会消失

标签: ios objective-c iphone background locationmanager


【解决方案1】:

工作代码(整个逐步代码) 修改了 scurioni 的代码

第 1 步

  • 转到项目 -> 功能 -> 后台模式 -> 选择位置更新。
  • 转到项目 -> 信息 -> 添加带有可选字符串的键 NSLocationAlwaysUsageDescription。

第 2 步

将此代码添加到 AppDelegate.m

@interface AppDelegate ()<CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSTimer *timer;
@end

第 3 步 将此代码添加到 AppDelegate.m

中的 applicationDidEnterBackground 方法中
    - (void)applicationDidEnterBackground:(UIApplication *)application {
        UIApplication *app = [UIApplication sharedApplication];
        __block UIBackgroundTaskIdentifier bgTaskId =
        [app beginBackgroundTaskWithExpirationHandler:^{
            [app endBackgroundTask:bgTaskId];
            bgTaskId = UIBackgroundTaskInvalid;
        }];

        dispatch_async( dispatch_get_main_queue(), ^{
            self.timer = nil;
            [self initTimer];
            [app endBackgroundTask:bgTaskId];
            bgTaskId = UIBackgroundTaskInvalid;
        });
    }

- (void)initTimer {
    if (nil == self.locationManager)
        self.locationManager = [[CLLocationManager alloc] init];

    self.locationManager.delegate = self;
    [self.locationManager requestAlwaysAuthorization];
    [self.locationManager startMonitoringSignificantLocationChanges];
    if (self.timer == nil) {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3
                                                      target:self
                                                    selector:@selector(checkUpdates:)
                                                    userInfo:nil
                                                     repeats:YES];
    }
}

- (void)checkUpdates:(NSTimer *)timer{
    UIApplication *app = [UIApplication sharedApplication];
    double remaining = app.backgroundTimeRemaining;
    if(remaining < 580.0) {
        [self.locationManager startUpdatingLocation];
        [self.locationManager stopUpdatingLocation];
        [self.locationManager startMonitoringSignificantLocationChanges];
    }
}

- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation {
    NSLog(@"Did Update Location = %f / %f", [newLocation coordinate].latitude, [newLocation coordinate].longitude);
    [self updateLocationWithLatitude:[newLocation coordinate].latitude andLongitude:[newLocation coordinate].longitude];
    UIApplication*    app = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier bgTask =
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self initTimer];
    });
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    [self.locationManager stopUpdatingLocation];
    UIApplication *app = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier bgTask =
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    [self initTimer];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // Do the work associated with the task
    });
}

-(void)updateLocationWithLatitude:(CLLocationDegrees)latitude
                     andLongitude:(CLLocationDegrees)longitude{
//Here you can update your web service or back end with new latitude and longitude
}

【讨论】:

  • 无法正常工作.. 未调用位置的委托方法。
【解决方案2】:

在尝试了所有可能的解决方案几天后,我终于能够让它发挥作用。这是我的解决方案中的问题:

  • 我需要设置 2 UIBackgroundTaskIdentifiers,一个用于计时器,另一个用于 locationManager

在我的解决方案中,只需添加:

UIApplication *app = [UIApplication sharedApplication];

bgTask2 = [app beginBackgroundTaskWithExpirationHandler:^{ 
[app endBackgroundTask:bgTask2]; 
bgTask2 = UIBackgroundTaskInvalid; }];

self.locationManager.delegate = self; 
[self.locationManager startUpdatingLocation]; 

【讨论】:

  • 您将这些行添加到哪种方法中?
  • @scurioni 你能发布你的完整工作代码吗?
  • 您能分享一下您的应用程序委托的工作代码吗?我们遇到了同样的问题。
【解决方案3】:

对于那些想解决这个问题的人来说,我有一个简单的解决方案。

  1. 研究raywenderlich.com 中的示例。示例代码完美运行,但不幸的是在后台定位期间没有计时器。这将无限期地运行。
  2. 使用这段代码sn-p添加定时器:

    -(void)applicationDidEnterBackground {
      [self.locationManager stopUpdatingLocation];
    
      UIApplication* app = [UIApplication sharedApplication];
    
      bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
      }];
    
      self.timer = [NSTimer scheduledTimerWithTimeInterval:intervalBackgroundUpdate
                                                    target:self.locationManager
                                                  selector:@selector(startUpdatingLocation)
                                                  userInfo:nil
                                                   repeats:YES];
    }
    
  3. 别忘了在 info.plist 中添加“用于位置更新的应用注册”。

【讨论】:

  • bgTask 来自哪里?
  • 属性(非原子)UIBackgroundTaskIdentifier bgTask;在标题类中
  • @HelmiB: 它在 iOS 7 中不工作,你能提出其他建议吗,我需要在后台启动 locationmanger。
  • 在 iOS 8 上你可以检查这个方法:stackoverflow.com/a/28373247/2102779 它应该也适用于 iOS 7
  • 如何在“冷却”期间移除状态栏图标(在 stopUpdatingLocation 到下一个 startUpdatingLocation 之间)?即使在调用 stopUpdatingLocation 之后它仍然存在。该图标只有在显式调用 stopUpdatingLocation (从 ViewController 或类似的东西)后才会消失
【解决方案4】:

进入后台后,您只能有 10 分钟的额外时间。没有办法扩展它。您应该改用位置后台服务。

【讨论】:

  • 这些服务还没有基于时间的版本,而是在每次更新或重大位置变化时触发
  • 但是阅读我链接的帖子,似乎人们能够这样做。您认为与我实现的代码以及他们所做的代码有何不同?
  • 他们使用的方法(一目了然)是使用全功率后台定位服务(因此您不断获得更新,但每 X 分钟才处理一次)。这会起作用,但你的电池每晚都会没电
  • 我找到了另一篇文章中引用的讨论:devforums.apple.com/thread/146398?start=0&tstart=0
  • a quote "当 10 分钟快到时,它可以调用 startUpdatingLocation 并使用 CLLocationManager 委托回调(didFail.. 或 didUpdate...)来设置下一个 10 分钟的后台任务。如果已达到所需的时间间隔,此时它会连接到服务器并发送必要的数据。如果是 60 分钟周期中的 40 分钟,则它不连接到服务器并继续设置正常启动新的后台任务 - 没问题。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-02
  • 2011-11-09
  • 1970-01-01
  • 2018-05-25
  • 2016-08-11
相关资源
最近更新 更多