didEnterRegion工作在前台,但不是后台或其他VC

如果应用程序正在运行,并且CLLocationManagerDelegate类是前景(即可见),则会触发didEnterRegions,并同时获得NSLog和AlertView。 但是,当应用程序处于后台时,我什么也得不到,实质上,如果屏幕显示除委托类以外的任何内容。

我已经在plist的“所需的背景模式”下设置了“位置更新的应用程序寄存器”,尽pipe我不确定这是甚至是必要的。

这是我认为是相关的代码,虽然我可能是错的(并很乐意添加更多)。 我应该注意,viewDidLoad中的所有内容都包含在一个if中,以检查区域监视是否可用和启用。

- (void)viewDidLoad { NSLog(@"MapViewController - viewDidLoad"); self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; self.locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters; self.locationManager.delegate = self; [self.locationManager startMonitoringSignificantLocationChanges]; } - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region { NSLog(@"MapViewController - didEnterRegion"); NSLog(@"MVC - didEnterRegion - region.radius = %f", region.radius); UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"entered region..." message:@"You have Entered the Location." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; alert.tag = 2; [alert show]; } 

这里是我在AppDelegate.m得到被监视区域的列表:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // other code NSLog(@"LISTING ALL REGIONS MONITORED"); NSArray *regions = [self.locationManager.monitoredRegions allObjects]; if (!regions) { NSLog(@"no regions found"); } else { NSLog(@"got %d monitored regions", [regions count]); for (int i = 0; i < [regions count]; i++) { CLRegion *region = [regions objectAtIndex:i]; NSLog(@"region %d's identifier = %@", i, region.identifier); NSLog(@"region: radius: %@", region.radius); } } // other code } 

我调用startMonitoringForRegion两次,这里是主要的地方:

 - (void)doneButtonTapped { NSLog(@"doneButtonTapped"); if (self.locationIdentifier) { if ([CLLocationManager regionMonitoringEnabled] && [CLLocationManager regionMonitoringAvailable]) { // core data setup NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"LocationReminder" inManagedObjectContext:self.managedObjectContext]; fetchRequest.entity = entityDescription; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"locationIdentifier == %@", self.locationIdentifier]; fetchRequest.predicate = predicate; NSError *error; NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; if (results) { // get the LocationReminder LocationReminder *retrievedReminder = [results objectAtIndex:0]; retrievedReminder.audioURI = [[[self.audioPlayers objectAtIndex:self.selectedCell] url] absoluteString]; retrievedReminder.userRecording = nil; // start monitoring it's region NSArray *coordinateArray = [retrievedReminder.locationIdentifier componentsSeparatedByString:@", "]; CLLocationCoordinate2D coordinate = {[[coordinateArray objectAtIndex:0] doubleValue], [[coordinateArray objectAtIndex:1] doubleValue]}; CLRegion *newRegion = [[CLRegion alloc] initCircularRegionWithCenter:coordinate radius:250.0 identifier:retrievedReminder.locationIdentifier]; NSLog(@"about to monitor region with radius: %f", newRegion.radius); [self.locationManager startMonitoringForRegion:newRegion desiredAccuracy:kCLLocationAccuracyBest]; // save the LocationReminder if (![self.managedObjectContext save:&error]) { NSLog(@"hmm. no managed object context. must be something space-time going on"); } else { NSLog(@"saved locationReminder, locationIdentifier = %@", retrievedReminder.locationIdentifier); } } else { NSLog(@"ERROR: no LocationReminder retreived for predicate: %@", predicate); } } // get the mapview controller off of the navigation stack for (UIViewController *viewController in self.navigationController.viewControllers) { if ([viewController isKindOfClass:[MapViewController class]]) { MapViewController *mapVC = (MapViewController *)viewController; mapVC.audioURI = [[[self.audioPlayers objectAtIndex:self.selectedCell] url] absoluteString]; [self.navigationController popToViewController:mapVC animated:YES]; } } } 

而且因为我感觉这可能很重要,下面是locationManager的getter:

 - (CLLocationManager *)locationManager { NSLog(@"MapViewController - locationManager"); if (_locationManager) { return _locationManager; } else { _locationManager = [[CLLocationManager alloc] init]; return _locationManager; } } 

更新1:通过苹果论坛(我在哪里交叉点)有人提到AlertView将只显示在前台。 NSLog也不会触发。 我假设应该工作。

我的一个朋友写了一个关于使用geofencing的好教程,可能有助于解决您遇到的一些问题。

开始使用地理围栏

在网上有很多例子,在这里。 从小处着手,继续前进。 一旦你开始得到你的callback,你可以开始扩展到你的其他视图控制器。

UPDATE

正如在评论中解释的那样,创build一个单例类来控制你的位置pipe理器和委托方法的好处。 通过使用单例,可以防止多次调用委托方法的可能性。 你可以通过仔细的编码来防止这种情况,但是使用一个单例会为你做这件事。 这也是一个很好的类来处理委托方法需要完成的所有工作。

你做错事情:

  1. 后台模式 – 应用程序注册位置更新。 这是不需要的。 这是需要当你想收集信息的重大变化,所以,去目标>您的应用程序>function,并select所需的选项在背景模式下。 这会自动为你更新plist。 现在,禁用它。
  2. 您正尝试在用户input区域时创build警报。 虽然这个工作时,应用程序正在工作,当您的应用程序在后台警报是没有用的。 – 而不是触发本地通知或api呼叫。

例如。 通知:

  -(void)triggerLocalNotification:(CLRegion *)region{ UILocalNotification *notification = [[UILocalNotification alloc]init]; [notification setAlertBody:[NSString stringWithFormat:@"Welcome to %@", [region identifier]]]; [notification setRepeatInterval:0]; [notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:2]]; [notification setTimeZone:[NSTimeZone defaultTimeZone]]; [[UIApplication sharedApplication]scheduleLocalNotification:notification]; NSLog(@"notification triggered with notification %@", notification); } 

当您执行EnterRegion时,您可以发布本地通知。

即使您在后台,也会显示类似警报的popup窗口。

你可以做一个简单的testing:

1)在您的应用程序委托的applicationDidEnterBackground中创build一个本地通知对象,使用任何随机消息并告诉本地通知立即触发。

2)按主页button,当你的应用程序最小化,你应该看到一个popup。

我想你需要去你的app.plist

并添加所需的背景模式:添加itme应用程序寄存器以进行位置更新

和1。 如果你的应用程序在后台,你仍然可以看到顶部的箭头

和2,如果应用程序被杀害,你仍然可以看到顶部的空心箭头,ios会监视你的地区,但限于20个地区