didEnterRegion работает на переднем плане, но не фон или другие VC

Если приложение работает и класс CLLocationManagerDelegate является передним планом (то есть видимым), то запускается didEnterRegions, и я получаю как NSLog, так и AlertView. Тем не менее, я ничего не получаю, когда приложение находится в фоновом режиме или, по сути, если на экране отображается что-либо, кроме класса делегата.

Я установил "Регистры приложений для обновлений местоположения" в "Требуемые фоновые режимы" в списке, хотя я не уверен, что это даже необходимо.

Вот то, что я считаю соответствующим кодом, хотя я могу ошибаться (и с удовольствием добавлю больше). Я должен отметить, что все в 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:

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

ОБНОВЛЕНИЕ 1: На форумах Apple (где я разместил перекрестные ссылки) кто-то упомянул, что AlertView будет отображаться только на переднем плане. Тем не менее, NSLog тоже не стреляет. Я предполагаю, что это должно работать.

4 ответа

Решение

Мой друг написал хороший учебник по использованию геозон, который может помочь решить некоторые проблемы, с которыми вы столкнулись.

Начните с геозоны

Есть много примеров в Интернете и здесь, на SO. Начните с малого и продолжайте свой путь. Как только вы начнете получать ваши обратные вызовы, вы можете начать расширять свои возможности для других ваших контроллеров представления.

ОБНОВИТЬ

Как объяснено в комментариях, преимущества создания одноэлементного класса для управления вашим менеджером местоположения и делегированием методов. Используя одноэлементный режим, вы исключаете возможность множественных вызовов методов вашего делегата. Вы можете предотвратить это путем тщательного кодирования, но использование синглтона сделает это за вас. Это также хороший класс для обработки всей работы, необходимой для выполнения ваших методов делегата.

То, что вы делаете неправильно:

  1. Фоновые режимы - приложение регистрирует обновления местоположения. Это не нужно. Это необходимо, когда вы хотите собрать информацию о значительных изменениях в местоположении и т. Д. Итак, перейдите в раздел "Цели"> "Ваше приложение"> "Возможности" и выберите нужный параметр в разделе "Фоновые режимы". Это автоматически обновит список для вас. Пока отключите его.
  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);
}

Вы можете опубликовать локальное уведомление, когда вы сделали EnterRegion.

Это покажет всплывающее окно с предупреждением, даже если вы находитесь в фоновом режиме.

Вы можете сделать простой тест:

1) Создайте локальный объект уведомления внутри вашего applicationDidEnterBackground вашего приложения-делегата с любым случайным сообщением и скажите локальному уведомлению о немедленном срабатывании.

2) Нажмите кнопку "Домой", когда вы свернете приложение, вы увидите всплывающее окно.

Я думаю, вам нужно перейти к вашему app.plist

и добавьте необходимые фоновые режимы: добавьте регистры приложения для обновления местоположения

и 1 . если ваше приложение находится в фоновом режиме, вы все равно видите стрелку сверху

и 2, если приложение убито, вы все еще можете видеть пустую стрелку наверху, ios будет контролировать регион за вас, но ограничено 20 регионами

Другие вопросы по тегам