iOS 后台位置更新的最佳实践

3

概述

我的公司要求我发布一个应用程序,可以每两个小时检查设备的位置。该应用程序将通过TCP/IP套接字发送这些位置数据到我的服务器,然后根据这些数据接收相应的信息(立即,并通过同一TCP/IP套接字)。因此,我并不试图使我的应用程序在后台模式下持续运行(实际上,在iOS中似乎是一个热门话题,而且也不适合我的项目)。

问题

为了保证可靠性,实现这个功能的最佳实践是什么?因此,我想知道:

  • 由于我的应用程序已挂起(=不活动状态),苹果是否允许在didUpdateToLocation唤醒时打开套接字以发送位置?
  • 我有多长时间可以通过我的套接字执行发送/接收任务?
  • 我应该使用beginBackgroundTaskWithExpirationHandler创建一个真正的后台任务,并使用Cocoa允许的10分钟来执行我的发送/接收任务吗?
  • 是否可能(并且被苹果允许)每2小时请求10分钟的后台任务,而无需人工交互(即用户应重新打开应用程序等)?

我已经实现/发现的内容

  • 我在我的Info.plist中添加了location键,以便在我的应用程序不活动时运行didUpdateToLocation处理程序。
  • 当我的应用程序处于前台(=活动状态)时,我能够通过打开的套接字发送和接收数据。
  • 我尝试在调用didUpdateToLocation时检查backgroundTimeRemaining。我得到了一个非常大的结果数字,这似乎是正常的,因为此时applicationState不在UIApplicationStateBackground而在UIApplicationStateActive中。

官方文档对这些问题并不是很清楚,我没有找到与我的特定情况相关的主题。

感谢您的帮助。


1
beginBackgroundTaskWithExpirationHandler 不会创建后台任务,而是将当前线程标记为希望在应用程序转入后台时继续运行的东西。 - progrmr
1
@user1382094:请记得将正确的答案标记为已接受的答案,以防它对您有所帮助。谢谢! - veducm
1个回答

5
根据苹果文档,你可以通过使用与您描述的非常相似的方法来实现这些功能。我会做类似于mindsizzlers的这篇文章中所解释的内容。
  • As a recommendation, turn on significant location updates when the app enters in background, so you save battery. You can do this when the app goes to background:

    - (void) applicationDidEnterBackground:(UIApplication *) application
    {
        // Create the location manager if you do not already have one.
        if (nil == locationManager)
            locationManager = [[CLLocationManager alloc] init];
    
        locationManager.delegate = self;
        [locationManager startMonitoringSignificantLocationChanges];
    }
    

    Then, the system will wake your app when location changes, as explained in the documentation.

    If you leave this service running and your app is subsequently suspended or terminated, the service automatically wakes up your app when new location data arrives. At wake-up time, your app is put into the background and given a small amount of time to process the location data. Because your app is in the background, it should do minimal work and avoid any tasks (such as querying the network) that might prevent it from returning before the allocated time expires. If it does not, your app may be terminated.

    In order to avoid the action of sending the new location to the server from being highly unreliable (it may work sometimes) you should tell iOS in advance that you are doing a background task that should be allowed to run to completion.

  • Change your location manager delegate (didUpdateToLocation) to handle background location updates.

    - (void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation
    fromLocation:(CLLocation *)oldLocation
    {
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
            // Send the new location to your server in a background task
            // bgTask is defined as an instance variable of type UIBackgroundTaskIdentifier
            bgTask = [[UIApplication sharedApplication] 
            beginBackgroundTaskWithExpirationHandler:
            ^{
                [[UIApplication sharedApplication] endBackgroundTask:bgTask];
            }];
    
            // Make a SYNCHRONOUS call to send the new location to our server
    
            // Close the task
            if (bgTask != UIBackgroundTaskInvalid) {
                [[UIApplication sharedApplication] endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
            }
    
        } else {
                // Handle location updates in the normal way
        }   
    }
    
这样,您就不需要启动计时器了。每当位置发生显着变化时,您将自动唤醒并将更新后的位置发送到服务器。
当然,如果您想确保在特定时间间隔内执行此操作,仍然可以采用设置计时器的方法来开始接收位置更新,并在收到更新后立即将其发送到服务器。请参考iOS中的后台模式(部分:接收位置更新)以及这个答案其他问题,详细了解如何实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接