我遇到一个问题,应用程序正在注册后台位置更新,直到设备休眠,但在设备从休眠恢复后,位置更新不会恢复。
该应用程序非常简单,因为它是一个测试位置更新对电池寿命的影响的测试。
我使用单视图应用程序模板创建了该应用程序,并:
- 将下面发布的代码添加到应用程序委派中(仅此而已,没有其他代码代码)
- 添加了位置更新后台模式
- 添加了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核心位置未更新