Как обновить местоположение пользователя по запросу с помощью тихих push-уведомлений? iOS

Я хочу отслеживать текущее местоположение пользователей только по запросу. Мне нужно только начальное местоположение, а не постоянные обновления. Я подумал, что лучший способ сделать это - отправить пользователю тихое уведомление, чтобы один раз получить текущее местоположение пользователя. Получение тихого уведомления работает нормально, но LocationManager не получает первоначального исправления местоположения. Мой класс Delegate диспетчера местоположений обычно создает экземпляр, но не запускает функцию didUpdateLocations в любой момент после вызова метода startUpdatingLocation() диспетчера местоположений. Когда приложение запускается нормально из AppDelegate:didFinishLaunchingWithOptions, LocationManager без проблем обновляет местоположение пользователей.

Я разрабатываю Xcode 6.3.2 для iOS 8.3.

Мой AppDelegate:DidReceiveRemoteNotification выглядит так:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler handler: (UIBackgroundFetchResult) -> Void) {

    var bgTask = bgManager()
    bgTask.registerBackgroundTask()
    LocManager.locationMngr.startUpdatingLocation() // LocManager is global variable

    let delayInSeconds = 8.0
    let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delayInSeconds * Double(NSEC_PER_SEC)))
    dispatch_after(popTime, dispatch_get_main_queue()) {
            println(LocManager.updated)
            bgTask.endBackgroundTask()
            handler(UIBackgroundFetchResult.NewData)
    }
}

Сначала я пробовал только со строкой:

LocManager.locationMngr.startUpdatingLocation()

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

Вот класс LocationManager:

class LocationManager: NSObject, CLLocationManagerDelegate {
let locationMngr:CLLocationManager
var coord:CLLocationCoordinate2D
var updated:Bool
    override init() {
        locationMngr = CLLocationManager()
        coord = CLLocationCoordinate2D()
        updated = false
        super.init()
        locationMngr.delegate = self
        locationMngr.desiredAccuracy = kCLLocationAccuracyHundredMeters

        locationMngr.startUpdatingLocation() //Should call didUpdateLocations after some time
    }

    //Doesn't get called in AppDelegate remoteNotifications method
    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
    {
        var loc:CLLocation = locations.first as! CLLocation
        self.coord = loc.coordinate
        locationMngr.stopUpdatingLocation()
        updated = true
    }

и класс фонового менеджера:

class bgManager:NSObject{
    var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
    override init(){
        super.init()
    }
    func registerBackgroundTask() {
        backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler {
        [unowned self] in
        self.endBackgroundTask()
        }
    }

    func endBackgroundTask() {
        UIApplication.sharedApplication().endBackgroundTask(backgroundTask)
        backgroundTask = UIBackgroundTaskInvalid
    }
}

JSON полученного удаленного push-уведомления:

"aps" : {
        "sound" : "",
        "content-available" : 1,
        "priority" : 5
    }

У меня есть все необходимые ключи plist.info и фоновые режимы для получения, уведомлений и определения местоположения, включенные в проекте «Возможности: фоновые режимы». Фрагмент plist.info:

<dict>
    <key>UIRequiredDeviceCapabilities</key>
    <array>
        <string>location-services</string>
        <string></string>
        <string></string>
    </array>
    <key>UIBackgroundModes</key>
    <array>
        <string>remote-notification</string>
        <string>fetch</string>
        <string>location</string>
    </array>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Your location is needed for this app.</string>
    ...

Я яростно просматривал SO для подобной проблемы и не смог найти никакого решения, включая этот вопрос:

IOS — запуск фоновой задачи для обновления местоположения пользователя с помощью swift< /а>

Периодические фоновые обновления местоположения iOS

Основное местоположение методы делегирования не вызываются в iOS 8.3 Xcode 6.3.1

Swift: местоположение не обновляется при возврате из фона


person Toni Nurmi    schedule 15.07.2015    source источник
comment
Я чувствую, что это почти наверняка приведет к отклонению вашего приложения.   -  person endy    schedule 15.07.2015
comment
Какое приложение вы делаете? Зачем вам это нужно?   -  person the_pantless_coder    schedule 16.07.2015
comment
@endy Если я найду другой способ добиться той же функциональности, я сделаю это. Какие-либо предложения? :)   -  person Toni Nurmi    schedule 16.07.2015
comment
@the_pantless_coder Я хочу получать адреса определенных пользователей по запросу. Мне нужно получать местоположения других пользователей только один раз, а не на постоянной основе. Чтобы не спамить видимыми уведомлениями, я хочу делать это тихо.   -  person Toni Nurmi    schedule 16.07.2015
comment
Вы можете использовать API навигации, чтобы ваше приложение оставалось открытым в фоновом режиме. Их навигационная панель будет работать, используя ваше местоположение в фоновом режиме. Но как только они полностью закроют ваше приложение, вы не сможете узнать их местоположение. Это сделано намеренно. Я знаю, что не хотел бы, чтобы случайное приложение знало, где я нахожусь, когда создатель хочет знать.   -  person endy    schedule 16.07.2015
comment
Вы нашли решение?   -  person jithin    schedule 10.12.2015


Ответы (2)


Я столкнулся с той же проблемой и безрезультатно выполнил те же действия, что и OP. В конце концов я понял, что запросил только CLLocationManager.requestWhenInUseAuthorization(), который предоставляет местоположение только тогда, когда приложение находится на переднем плане. Мне пришлось запросить CLLocationManager.requestAlwaysAuthorization(), чтобы приложение запрашивало местоположение в фоновом режиме. Также убедитесь, что у вас есть запись NSLocationAlwaysUsageDescription в файле Info.plist. Благодаря этим изменениям я смог напрямую использовать CLLocationManager.startUpdatingLocation() и получать обновления местоположения в фоновом режиме.

person SS.    schedule 14.11.2016
comment
Можете ли вы опубликовать рабочий пример вашего кода? Я пытаюсь сделать что-то похожее на OP. - person DookieMan; 28.07.2017

Когда приложение запускается в фоновом режиме, у меня сработал вызов startMonitoringSignificantLocationChanges() до startUpdatingLocation().

Не забудьте позвонить stopMonitoringSignificantLocationChanges() и stopUpdatingLocation(), когда закончите.

person Luis Valdés    schedule 01.12.2016