【问题标题】:Send location updates every 30 minutes in Swift在 Swift 中每 30 分钟发送一次位置更新
【发布时间】:2014-12-03 20:24:42
【问题描述】:

我为定位服务开启了后台模式,并打算每 30 分钟向服务器发送一次定位(纬度和经度)。现在我在控制台中打印相同的内容。它似乎工作了一段时间,但我想知道在这种情况下如何使用 NSTimer。我应该从哪里调用它?

import UIKit
import CoreLocation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {

    var window: UIWindow?
    var locationManager = CLLocationManager()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    func applicationWillResignActive(application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

        self.locationManager.delegate = self
        self.locationManager.startUpdatingLocation() // I know i should be using signification location option here. this is just for testing now.
    }

    func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
        self.sendBackgroundLocationToServer(newLocation);
    }

    func sendBackgroundLocationToServer(location: CLLocation) {
        var bgTask = UIBackgroundTaskIdentifier()
        bgTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler { () -> Void in
            UIApplication.sharedApplication().endBackgroundTask(bgTask)
        }

        println(location.coordinate.latitude)

        if (bgTask != UIBackgroundTaskInvalid)
        {
            UIApplication.sharedApplication().endBackgroundTask(bgTask);
            bgTask = UIBackgroundTaskInvalid;
        }
    }

    func applicationWillEnterForeground(application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        application.beginBackgroundTaskWithExpirationHandler{}
    }

    func applicationDidBecomeActive(application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        application.beginBackgroundTaskWithExpirationHandler{}
    }

    func applicationWillTerminate(application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        application.beginBackgroundTaskWithExpirationHandler{}
    }


}

也许打电话给application.beginBackgroundTaskWithExpirationHandler{} 是个坏主意?我在这里有什么选择?

【问题讨论】:

  • 顺便说一句,委托方法 didUpdateToLocation:fromLocation 已弃用 - 请参阅 CLLocationManagerDelegate 文档

标签: ios ios7 swift ios8 core-location


【解决方案1】:

beginBackgroundTask... 的想法是启动一个有限长度的任务,这样如果用户离开应用程序,它将在后台任务中继续运行一段短的、有限的时间(我相信是 3 分钟)。在时间用完之前,您必须致电endBackgroundTask,否则应用程序将被立即终止。

因此,遗憾的是,后台任务机制并不真正适合您想要的意图。但是,有一组狭窄的特殊背景模式设计用于在一组狭窄的功能(VOIP、音频等)之外的持续后台操作。如需更多信息,请参阅App Programming Guide for iOS: Background Execution实现长时间运行的任务部分。

现在,其中一种后台模式用于“位置”服务。因此,如果这是您的应用程序的核心功能,对于正常运行至关重要,那么您可以注册location 后台模式,您的应用程序将继续在后台运行。从那里,您可以监视位置更新,如果已经过去了足够长的时间,则触发一些过程。但是,如果这种后台定位模式不是您应用的基本功能,Apple 可能会拒绝您的应用请求它不需要的后台模式。


顺便说一句,您应该知道,启动标准位置服务可能会耗尽设备电池。您可以考虑使用电池效率高的"significant change" location service。这还具有每次用户移动相当长的距离时自动唤醒您的应用程序的优点(例如,以公里为单位;我相信它是由移动到不同的手机信号塔触发的)。

【讨论】:

  • 嘿@Rob,感谢您的回答。是的,我已经为位置启用了后台模式,并且确实位置是应用程序的核心部分。此外,此应用程序仅适用于内部用户/临时。话虽如此,您能给我举个例子或阐明我将如何在这里使用 NSTimer 吗?
  • 嘿@Rob,感谢您的回答。这很有帮助。是的,我意识到这会耗尽电池电量,但因为它是临时使用的,所以没关系:)。另外,是的,我将使用重大更改。现在,我真正帮助我测试日志。再次感谢。
  • @Rob,您描述的方法在模拟器中对我有用,但在设备上无效。知道可能出了什么问题吗?
  • 我已将位置更新设置为后台模式功能。我在 info.plist 中添加了“始终隐私位置..”。在模拟器中一切正常。但在实际设备中,handleTimer 函数永远不会被触发。我只需按主页按钮即可进入后台。我怀疑计时器是否真的在设备上工作。看看这个stackoverflow.com/questions/30630687/…。这个问题的答案错了吗? [PS-Location 是我的应用程序的核心部分]
  • 正确,计时器不起作用。您需要运行位置服务,并在收到位置更新通知后,检查自己是否已经过了足够的时间。而且,如果您不想遭受严重的电池消耗,您可能会受限于不太准确的重大更改服务。我已经相应地编辑了我的答案。
【解决方案2】:

几个注意事项,因为我们一直在与位置问题作斗争,并与似乎无法唤醒我们的后台应用程序作斗争。

  1. NSTimer 仅在您的应用程序未挂起时才有效。当然,它在后台,但只有它能够接收来自 iOS 的通知(APN,位置,...)。最终,当您在 BG 中奔跑时,您的计时器将停止触发。因此,您依靠其中一种 BG 模式来踢您。

  2. 如果您正在使用 CLLocationManager.startUpdatingLocation,您会注意到您稍后会停止获取这些内容。尤其是当手机放松并试图入睡时。这是因为一个名为 CLLocationManager.pausesLocationUpdatesAutomatically 的记录不完整的功能......它决定在设置为“true”(DEFAULT 设置)时停止发送这些功能。您可以将其设置为“false”,并且您将继续获得您的职位更新。这几乎可以确保您的应用满足您的需求。

  3. 如上所述,您必须确保在获取 locationManager.didUpdateLocations 回调时启动 backgroundTask 以在处理该信息和发送网络数据时保持应用程序正常工作。但你似乎明白这一点。

  4. 只要醒来足够长的时间来“记录”位置更新就不是那么糟糕了。只要确保您没有生成您的网络代码,除非您已明确达到您的 30 分钟预期。

【讨论】:

    【解决方案3】:

    试试这个:

    • 为定位服务创建一个单例。使用NSNotification 注册它
    • AppDelegatewillEnterBackGround 中,您通过NSNotificationCenter 发送通知

    然后,您的单例将启动 updatingLocation 并在收到位置数据时将其发送到服务器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      相关资源
      最近更新 更多