【问题标题】:Background location updates not resuming after device wakes from hibernation设备从休眠状态唤醒后后台位置更新未恢复
【发布时间】:2014-05-23 01:35:55
【问题描述】:

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

该应用程序非常简单,因为它可以测量位置更新对电池寿命的影响。

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

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

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

然后大约 15-20 分钟后,设备进入休眠状态(我在 Organizer 的控制台上监控活动)。 但是,在唤醒设备后,该应用永远不会收到任何 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。

【问题讨论】:

    标签: ios core-location locationmanager


    【解决方案1】:

    您需要从 App 委托方法中移动您的 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 Core Location not updating

    【讨论】:

    • 主要问题是设备恢复后 didUpdateLocations: 根本没有被调用,因此 getDatUsage 的位置无关紧要。但是我已经删除了 performSelector 以防它可能产生一些不利的副作用,并且我正在尝试使用 pausesLocationUpdatesAutomatically
    • 你是在设备还是模拟器上测试?
    • 它在设备上。到目前为止,设置 pausesLocationUpdatesAutomatically 看起来像是在阻止(或延迟)设备休眠,但我需要等待并观察更长时间才能看到会发生什么。
    • “冬眠”这个词让我很担心。在 iOS 中,您实际上只有 2 种应用模式(前台和后台)。我不确定您所说的休眠是什么意思,但我认为除了上面的答案之外,在真实设备上进行测试将有助于查明任何其他问题。
    • 我不是在谈论应用程序和应用程序模式,而是在谈论设备。如果您在管理器的控制台中观察到设备活动,那么一段时间后,设备作为一个整体开始关闭。我称之为休眠是因为我不知道实际的 iOS 术语是什么,而且我也不是指自动锁定和屏幕休眠。无论如何,在达到此“休眠”阶段之后,如果您在设备上恢复活动,那么当我没有得到 didUpdateLocations 时。看起来 pausesLocationUpdatesAutomatically 正在阻止此设备“休眠”发生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多