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



如果应用程序正在运行,并且CLLocationManagerDelegate类是前台(即可见),则didEnterRegions将触发,我将获得NSLog和AlertView。然而,当应用程序在后台时,或者从本质上讲,如果屏幕上显示的不是委托类,我什么都得不到。

我已经在plist的"必需后台模式"下设置了"位置更新的应用程序寄存器",尽管我不确定这是否有必要。

以下是我认为相关的代码,尽管我可能错了(我很乐意添加更多)。我应该注意,viewDidLoad中的所有内容都封装在一个if中,该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仍然没有启动。我想这应该行得通。

我的一个朋友写了一篇关于使用地理围栏的很好的教程,这可能有助于解决你遇到的一些问题。

开始地理围栏

网上和SO上都有很多例子。从小处着手,一路向上。一旦开始获得回调,就可以开始将内容扩展到其他视图控制器。

更新

正如评论中所解释的,创建一个单例类来控制位置管理器和委托方法的好处。通过使用singleton,可以防止对委托方法进行多次调用。您可以通过仔细的编码来防止这种情况,但使用单例可以做到这一点。这也是一个很好的类,可以处理委托方法需要完成的所有工作。

你做错了什么:

  1. 后台模式-应用程序注册以进行位置更新。这是不需要的。当你想收集位置等重大变化的信息时,这是必要的。因此,转到目标>你的应用程序>能力,并在背景模式下选择所需的选项。这将自动为您更新plist。现在,禁用它
  2. 当用户进入某个区域时,您正试图创建警报。虽然这在应用程序工作时有效,但当您的应用程序处于后台时,警报没有用处Do-而是触发本地通知或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);
}

您可以在didEnterRegion时发布本地通知。

即使你在后台,这也会显示一个类似警报的弹出窗口。

你可以做一个简单的测试:

1) 在应用程序代理的应用程序DidEnterBackground中创建一个本地通知对象,带有任何随机消息,并告诉本地通知立即启动。

2) 按下主页按钮,当你应用最小化时,你应该会看到一个弹出窗口。

我想你需要转到你的应用程序.plist

并添加所需的后台模式:添加用于位置更新的itme应用程序寄存器

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

和2,如果应用程序被杀,你仍然可以看到顶部的空心箭头,ios会为你监控该区域,但限制为20个区域

最新更新