设备从休眠状态唤醒后,后台位置更新未恢复



我遇到一个问题,应用程序正在注册后台位置更新,直到设备休眠,但在设备从休眠恢复后,位置更新不会恢复。

该应用程序非常简单,因为它是一个测试位置更新对电池寿命的影响的测试。

我使用单视图应用程序模板创建了该应用程序,并:

  • 将下面发布的代码添加到应用程序委派中(仅此而已,没有其他代码代码)
  • 添加了位置更新后台模式
  • 添加了coreLocation.framework

当我启动应用程序,然后将其移动到后台,然后didUpdateLocations:继续被连续调用约15-20分钟,getDataUsage()每隔几秒钟执行一次。

大约15-20分钟后,设备休眠(我在组织者的控制台上监视活动)。然而,在唤醒设备后,该应用程序从未收到任何didUpdateLocations:调用。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    self.timeThatDataMonitoringStarted = [NSDate date];
    self.initialDataValuesSet = NO;
    CLLocationDegrees degreesFilter = 0.1;
    [self.locationManager setHeadingFilter: degreesFilter];
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    self.locationManager.distanceFilter = 10;
    [self.locationManager startUpdatingLocation];
    [self getDataUsage];
    return YES;
}
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    NSLog(@"******************** LOCATION didUpdateLocations ***************");
    static NSDate* previousDate;
    static int count = 0;
    if (previousDate)
    {
        NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:previousDate];
        NSLog(@" LOCATION: count: %d time since last update: %f", ++count, timeInterval);
    }
    previousDate = [NSDate date];
}
- (void) getDataUsage
{
    NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate: self.timeThatDataMonitoringStarted];
    NSLog(@"********* GETTING DATA USAGE. Elapsed time: %f **************",elapsedTime);
    NSArray *data = [self getDataCounters];
    NSNumber *wifiSentSinceBoot = (NSNumber*)data[0];
    NSNumber *wifiReceivedSinceBoot = (NSNumber*)data[1];
    NSNumber *wwanSentSinceBoot = (NSNumber*)data[2];
    NSNumber *wwanReceivedSinceBoot = (NSNumber*)data[3];
    int wifiSentSinceBootAsInt      = [wifiSentSinceBoot intValue];
    int wifiReceivedSinceBootAsInt  = [wifiReceivedSinceBoot intValue];
    int wWanSentSinceBootAsInt      = [wwanSentSinceBoot intValue];
    int wWanReceivedSinceBootAsInt  = [wwanReceivedSinceBoot intValue];
    static int initialWifiSent;
    static int initialWifiReceived;
    static int initialWWanSent;
    static int initialWWanReceived;
    if (!self.initialDataValuesSet)
    {
        self.initialDataValuesSet    = YES;
        initialWifiSent     = wifiSentSinceBootAsInt;
        initialWifiReceived = wifiReceivedSinceBootAsInt;
        initialWWanSent     = wWanSentSinceBootAsInt;
        initialWWanReceived = wWanReceivedSinceBootAsInt;
    }
    int wifiSentSinceLastRetrieval     = wifiSentSinceBootAsInt - initialWifiSent;
    int wifiReceivedSinceLastRetrieval = wifiReceivedSinceBootAsInt - initialWifiReceived;
    int wWanSentSinceLastRetrieval     = wWanSentSinceBootAsInt - initialWWanSent;
    int wWanReceivedSinceLastRetrieval  = wWanReceivedSinceBootAsInt - initialWWanReceived;
    uint dataUsed = wifiSentSinceLastRetrieval + wifiReceivedSinceLastRetrieval + wWanSentSinceLastRetrieval + wWanReceivedSinceLastRetrieval;
    NSLog(@"Total data: %d", dataUsed);
    [self performSelector:@selector(getDataUsage) withObject:nil afterDelay:3];
}

- (NSArray *) getDataCounters
{
    BOOL   success;
    struct ifaddrs *addrs;
    const struct ifaddrs *cursor;
    const struct if_data *networkStatisc;
    int WiFiSent = 0;
    int WiFiReceived = 0;
    int WWANSent = 0;
    int WWANReceived = 0;
    NSString *name=[[NSString alloc]init];
    success = getifaddrs(&addrs) == 0;
    if (success)
    {
        cursor = addrs;
        while (cursor != NULL)
        {
            name=[NSString stringWithFormat:@"%s",cursor->ifa_name];
            //   NSLog(@"ifa_name %s == %@n", cursor->ifa_name,name);
            // names of interfaces: en0 is WiFi ,pdp_ip0 is WWAN
            if (cursor->ifa_addr->sa_family == AF_LINK)
            {
                if ([name hasPrefix:@"en"])
                {
                    networkStatisc = (const struct if_data *) cursor->ifa_data;
                    WiFiSent+=networkStatisc->ifi_obytes;
                    WiFiReceived+=networkStatisc->ifi_ibytes;
                    //  NSLog(@"WiFiSent %d ==%d",WiFiSent,networkStatisc->ifi_obytes);
                    //  NSLog(@"WiFiReceived %d ==%d",WiFiReceived,networkStatisc->ifi_ibytes);
                }
                if ([name hasPrefix:@"pdp_ip"])
                {
                    networkStatisc = (const struct if_data *) cursor->ifa_data;
                    WWANSent+=networkStatisc->ifi_obytes;
                    WWANReceived+=networkStatisc->ifi_ibytes;
                    //  NSLog(@"WWANSent %d ==%d",WWANSent,networkStatisc->ifi_obytes);
                    //  NSLog(@"WWANReceived %d ==%d",WWANReceived,networkStatisc->ifi_ibytes);
                }
            }
            cursor = cursor->ifa_next;
        }
        freeifaddrs(addrs);
    }
    return [NSArray arrayWithObjects:[NSNumber numberWithInt:WiFiSent], [NSNumber numberWithInt:WiFiReceived],[NSNumber numberWithInt:WWANSent],[NSNumber numberWithInt:WWANReceived], nil];
}

注意,我使用术语"休眠"不是指应用程序状态,而是指设备状态。如果您在Organizer的控制台中观察到设备活动,那么过一段时间后,设备作为一个整体开始关闭。我称之为休眠,因为我不知道iOS的实际术语是什么,我所说的休眠也不是指自动锁定和屏幕睡眠。这是一个单独的活动之后,我推测电话和GPS芯片等正在断电。无论如何,在达到这个"休眠"阶段之后,如果你在设备上恢复活动,那就是我没有得到didUpdateLocations的时候。

您需要将getDataUsage方法调用从应用程序委托方法中移动:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

至CLLocationManager代表:

- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations

由于每次位置更新(调用上述委托)时,都会调用getDataUsage。

试图使用performSelector使用伪"For循环"是一种糟糕的设计,当应用程序处于后台模式时,会导致不可预测的结果。所以你需要删除那行:

[self performSelector:@selector(getDataUsage) withObject:nil afterDelay:3];

如果你想让应用程序在后台运行,我也会确保该应用程序已注册为后台模式。

我还想在这里查看我的回答中的更多细节:iOS7核心位置未更新

最新更新