Отслеживание нескольких (более 20) местоположений с помощью геозон iOS

Приложение iOS использует геозону для уведомления пользователя о предварительно определенных близлежащих местах. Приложению разрешено пропускать какое-то местоположение (пользователь не получает уведомления о соседнем местоположении), но желательно поддерживать низкий уровень пропуска.

Одним из способов реализации этого было бы начать мониторинг значительных изменений мест с startMonitoringSignificantLocationChanges и каждый раз, когда происходит событие "изменение местоположения", ищите местоположения в пределах, скажем, 500 м радиуса сообщаемого местоположения.

Что меня беспокоит, так это требование выполнять запрос для соседних регионов каждый раз, когда происходит существенное изменение местоположения и оно влияет на батарею.

Другой способ сделать это - зарегистрировать startMonitoringForRegion но Apple наложила (разумное) ограничение на количество одновременно отслеживаемых регионов, которое составляет 20, а у нас значительно больше 20 местоположений. Так что требуется какое-то динамическое обновление отслеживаемых регионов, но я все еще не уверен, каков наилучший способ сделать это.

Любые идеи о том, как это можно сделать так, чтобы он поддерживал низкий уровень заряда батареи, но также имел низкий уровень пропуска для мест?

5 ответов

Решение

Поскольку по этому вопросу было мало активности, я опишу, как мы в настоящее время решаем эту проблему.

Мы связали перезагрузку новых регионов со значительными событиями изменения местоположения (SLC). Когда происходит SLC, мы проверяем 20 соседних регионов, которые должны быть "геозоны". Чтобы найти 20 ближайших регионов, мы просто приближаем 1'' широты и долготы в соответствии со следующими формулами:

Широта: 1 градус = 110,54 км

Долгота: 1 градус = 111.320 * cos(широта) км

и просто проверьте ограничивающий квадрат текущего положения устройства для центров контролируемых областей (см.: Простые расчеты для работы с широтой / долготой + км расстояния?)

Так, например, если (10N,10E) является текущим местоположением устройства, мы начинаем с ограничивающего квадрата с вершинами в (10-1',10-1'), (X-10',10+1'), (10+1',10+1'), (10+1',10-1') (на широте (10N,10E) одна минута широты / долготы приблизительно равна 1,85 км).

Если их 20 (или почти 20) - мы регистрируем их для геозон и ждем следующего SCL. Если меньше / больше, просто увеличьте / уменьшите размер ограничивающего прямоугольника и повторите поиск.

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

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

Я думал, что добавлю еще одну опцию для использования более 20 геозон в вашем приложении. Этот способ уже давно хорошо работает в нашем приложении и использует CLLocation методы, которые являются встроенными.

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    if (locations.count > 0) {
        CLLocation *location = locations[0];

        NSMutableArray *sortedFences = [[NSMutableArray alloc] init];

        // add distance to each fence to be sorted
        for (GeofenceObject *geofence in enabledFences) {
            // create a CLLocation object from my custom object
            CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(geofence.latitude, geofence.longitude);
            CLLocation *fenceLocation = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude];
            // calculate distance from current location
            CLLocationDistance distance = [location distanceFromLocation:fenceLocation];
            // save distance so we can filter array later
            geofence.distance = distance;
            [sortedFences addObject:geofence];
        }

        // sort our array of geofences by distance and add we can add the first 20

        NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:@"distance" ascending:YES];
        NSArray *sortDescriptors = [NSArray arrayWithObject:sortByName];
        NSArray *sortedArray = [sortedFences sortedArrayUsingDescriptors:sortDescriptors];

       // should only use array of 20, but I was using hardcoded count to exit

        for (GeofenceObject *geofence in sortedArray) {
            CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(geofence.latitude, geofence.longitude);
            CLLocationDistance radius = geofence.radius;
            NSString *ident = geofence.geofenceId;

            CLCircularRegion *fenceRegion = [[CLCircularRegion alloc] initWithCenter:coordinate radius:radius identifier:ident];
            fenceRegion.notifyOnEntry = geofence.entry;
            fenceRegion.notifyOnExit = geofence.exit;
            [locationController.locationManager startMonitoringForRegion:fenceRegion];
        }
    }
}

Надеюсь, это поможет кому-то или направит их на правильный путь.

Если вы обеспокоены выполнением проверки близости при каждом значительном изменении местоположения, вы можете использовать метод пространственной индексации / поиска, например R-деревья или R*-дерево, чтобы уменьшить количество сравнений, необходимых для каждого изменения местоположения, так как эти алгоритмы поиска будут отфильтровывать (возможно большие) не имеющие отношения к пространству регионы. Это должно уменьшить время / заряд батареи, необходимые для выполнения проверки близости.

Я знаю, что этот пост старый, но для тех, кто хочет сделать что-то подобное, Skyhook предлагает возможность ограждать бесконечное количество мест.

Из их маркетинга: Skyhook Context Accelerator позволяет разработчикам приложений и рекламодателям мгновенно развертывать Infinite Geofences в любой цепочке брендов (например, CVS) или категории (например, круглосуточные магазины) через простой веб-интерфейс. Используя ту же запатентованную технологию из собственной сети локации Skyhook, Context Accelerator SDK управляет этими активными геозонами на устройстве, независимо от ограничений ОС, допускающих бесконечное геозонирование.

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