即使应用程序不在 Swift 中 运行 也接收位置

Receiving Location even when app is not running in Swift

对 Swift 还是很陌生。我来自 Android 背景,那里有 BroadcastReceiver,即使应用程序不是 运行。

也可以向服务提供位置信息

所以我在 iOS/Swift 中寻找类似的东西,看起来以前不可能,但现在可能了。我正在为 iOS 10 开发,但如果它向后兼容就更好了。

我找到了

startMonitoringSignificantLocationChanges

我可以执行它来开始提供位置更新,尽管这会引发一些问题。一旦我调用它并且我的应用程序不是 运行,是否仍在发送更新?应用程序将如何唤醒以做出响应?

同时重新启动 phone 并且当它 return 时,这是否意味着我仍然需要再次调用 startMonitoringSignificantLocationChanges 意味着我将不得不等待用户执行我的应用程序。还是重启后还记得设置?

仍然对如何解决这个问题感到困惑,这里是我正在尝试做的事情的简要说明。

我想更新 phone 的位置,即使应用程序不是 运行,这也会经常被发送到休息服务。

通过这种方式,在后端服务上,我可以确定某人是否也在某人的 X 米范围内,并向他们发送推送通知。

这可能是也可能不是一个好的解决方案,但如果我是你,我会同时使用 startMonitoringSignificantLocationChangesregionMonitoring

Here 是我制作的示例,与 iOS 13.

配合使用效果很好

让我们先 regionMonitoring。当应用程序处于前台状态时,我们当然没有问题,我们可以使用 CLLocationManager 的 didUpdate 委托来获取位置并将其发送到服务器。

在 AppDelegate 的 属性 中保留最新的当前位置,假设:

var lastLocation:CLLocation?

//And a location manager
var locationManager = CLLocationManager()

我们有两个UIApplicationDelegates

func applicationDidEnterBackground(_ application: UIApplication) {
    //Create a region
}

func applicationWillTerminate(_ application: UIApplication) {
    //Create a region
}

所以每当用户关闭应用程序或让应用程序进入后台时,我们当然可以在获取的最新当前位置周围创建一个区域。这是创建区域的示例。

func createRegion(location:CLLocation?) {

    if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
            let coordinate = CLLocationCoordinate2DMake((location?.coordinate.latitude)!, (location?.coordinate.longitude)!)
            let regionRadius = 50.0

            let region = CLCircularRegion(center: CLLocationCoordinate2D(
                latitude: coordinate.latitude,
                longitude: coordinate.longitude),
                                          radius: regionRadius,
                                          identifier: "aabb")

            region.notifyOnExit = true
            region.notifyOnEntry = true

            //Send your fetched location to server

            //Stop your location manager for updating location and start regionMonitoring
            self.locationManager?.stopUpdatingLocation()
            self.locationManager?.startMonitoring(for: region)
        }
        else {
            print("System can't track regions")
        }
    }

利用 RegionDelegates

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
    print("Entered Region")
}

func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
    print("Exited Region")

    locationManager?.stopMonitoring(for: region)

    //Start location manager and fetch current location
    locationManager?.startUpdatingLocation()
}

didUpdate方法中获取位置

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

    if UIApplication.shared.applicationState == .active {
    } else {
        //App is in BG/ Killed or suspended state
        //send location to server
        // create a New Region with current fetched location
        let location = locations.last
        lastLocation = location

        //Make region and again the same cycle continues.
        self.createRegion(location: lastLocation)
    }
}

这里我做了一个50m的区域半径圆。这个我测试过了,一般都是从你的中心点越过100m后调用的。

现在我可以使用第二种方法 significantLocationChanges

在使应用程序进入后台或终止时,我们可以停止位置管理器以进一步更新位置,并可以调用 startMonitoringSignificantLocationChanges

self.locationManager?.stopUpdatingLocation()
self.locationManager?.startMonitoringSignificantLocationChanges()

当应用程序被杀死时,位置是从didFinishLaunching方法的launchOptions?[UIApplicationLaunchOptionsKey.location]

中获取的
if launchOptions?[UIApplicationLaunchOptionsKey.location] != nil {
    //You have a location when app is in killed/ not running state
}

确保 BackgroundModesLocation Updates 中保持开启

还要确保使用密钥

请求 locationManager?.requestAlwaysAuthorization()
<key>NSLocationAlwaysUsageDescription</key>
    <string>Allow location</string>

在你的Info.plist

可以通过同时使用 2 个 LocationManagers 来获得第三种解决方案。

  1. 地区
  2. 重大位置变化

与使用 significantLocationChanges

Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.

按照给出的Apple Doc

所以这完全取决于您的要求,因为位置获取取决于许多因素,例如打开的应用程序数量、电池电量、信号强度等,当应用程序未运行时 运行。

另外请记住始终设置一个具有良好准确性的区域。

我知道这不会完全解决您的问题,但您会根据自己的要求获得前进的想法。