如何使用静默推送通知按需更新用户位置?iOS系统

Ton*_*rmi 6 core-location apple-push-notifications appdelegate swift ios8.3

我只想按需跟踪用户当前位置。我只需要初始位置,不需要持续更新。我认为最好的方法是向用户发送静默通知,以便一次获取用户的当前位置。接收静默通知效果很好,但 LocationManager 无法对位置进行初始修复。我的位置管理器委托类正常实例化,但在调用位置管理器方法 startUpdatingLocation() 后的任何时候都不会触发 didUpdateLocations 函数。当应用程序从 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

我首先尝试仅使用以下行:

LocManager.locationMngr.startUpdatingLocation()
Run Code Online (Sandbox Code Playgroud)

但当它不起作用时,我添加了后台任务和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
    }
Run Code Online (Sandbox Code Playgroud)

和后台管理器类:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

接收到的远程推送的JSON:

"aps" : {
        "sound" : "",
        "content-available" : 1,
        "priority" : 5
    }
Run Code Online (Sandbox Code Playgroud)

我在项目功能:后台模式中启用了所有必需的 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>
    ...
Run Code Online (Sandbox Code Playgroud)

我疯狂地浏览了类似的问题,但找不到任何帮助的解决方案,包括这个问题:

IOS - 使用 swift 运行后台任务来更新用户位置

定期 iOS 后台位置更新

iOS 8.3 Xcode 6.3.1 中未调用核心位置委托方法

Swift:从后台返回时位置未更新

SS.*_*SS. 2

我遇到了同样的问题,并按照OP的步骤进行了操作,但没有成功。最终我发现我只请求了CLLocationManager.requestWhenInUseAuthorization()仅当应用程序位于前台时提供位置。我必须请求CLLocationManager.requestAlwaysAuthorization()才能让应用程序在后台请求位置。还要确保您NSLocationAlwaysUsageDescription在文件中有条目Info.plist。通过这些更改,我能够CLLocationManager.startUpdatingLocation()直接使用并能够在后台接收位置更新。