iOS background执行详解

2017-09-24  本文已影响0人  twoJoh

       大家都知道,当用户点击iPhone的Home键时,iOS会把当前的app转移到background状态,在background状态停留短暂的时间再转移到suspended,这样做iOS能节省系统资源,提高电池的使用周期。但是如果我们需要在后台执行一些任务呢?需要保持app在background状态?别担心,iOS已经为我们提供了三种策略:
1、当app需要在后台执行有限长度的任务时
2、当app需要支持在后台下载文件时
3、app需要在background执行长时间特定类型的人去

app需要在后台执行有限长度的任务

       当app从background进入到suspended,需要执行耗时不长的任务,比如保存数据之类的,可以调用UIApplication对象的beginBackgroundTaskWithName:expirationHandler:或者beginBackgroundTaskWithExpirationHandler:方法,请求额外的时间执行任务,下面看demo:

//this is Swift
func applicationDidEnterBackground(_ application: UIApplication) {
   bgTask = application.beginBackgroundTask(withName: "myTask") {                        
        print("超过执行最长时间...")
        application.endBackgroundTask(self.bgTask!)
        self.bgTask = UIBackgroundTaskInvalid
    }
    DispatchQueue.global().async {
        print("后台执行任务.....")
        DispatchQueue.global().asyncAfter(deadline: .now() + 12) {
            print("任务完成")
            application.endBackgroundTask(self.bgTask!)
            self.bgTask = UIBackgroundTaskInvalid
        }
   }
}
//执行结果
后台执行任务.....
任务完成

       每一次调用beginBackgroundTaskWithName:expirationHandler: 或 beginBackgroundTaskWithExpirationHandler: 方法都会生成独特的token关联这个任务,当完成任务,必须使用相应的token调用endBackgroundTask: 方法,让系统知道这个任务执行完成,如果在一定的时间没有调用endBackgroundTask: ,系统将调用expirationHandler给app最后一次机会结束任务

在Background状态下载内容

       要支持在后台下载内容,app必须用NSURLSession对象下载,这样系统才能在app被suspended或terminated时,控制下载进程。app使用NSURLSession并配置了后台下载,当app被终止,系统将接管下载任务,在下载完成时或需要app关注时,系统将在后台唤醒app。
为了支持Background传输,需要对NSURLSession对象进行配置,demo如下:

//配置session支持后台下载
let configuration = URLSessionConfiguration.background(withIdentifier: "background downloading")
configuration.sessionSendsLaunchEvents = true
configuration.isDiscretionary = true
var session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)

配置好后,URLSession对象会在合适的时间把上传下载任务转交给系统。

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
        let configuration = URLSessionConfiguration.background(withIdentifier: identifier)
        configuration.sessionSendsLaunchEvents = true
        configuration.isDiscretionary = true
        var session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
}

实现长时间执行任务

       如果需要更长执行时间,app需要请求特殊的权限在background执行而不进入suspended状态,在iOS,只有几种特殊类型的app才允许运行在后台:

声明app支持的背景任务

       在TARGETS选中项目,点击Capabilities页,开启Background Modes,选择相应的model,如下图选择了Audio and AirPlay


选择相应的类型服务

因为篇幅有限,这里只给大家举一个例子,有兴趣的同学可自行研究

追踪用户的位置信息

       一款跑步软件,在跑步时需要记录用户的位置信息,并实时的更新时长和公里数,就需要app能在后台长时间的运行,demo如下:

locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.activityType = .fitness
if #available(iOS 9.0, *) {
    //允许app在后台执行位置更新
    locationManager.allowsBackgroundLocationUpdates = true
 }
 locationManager.distanceFilter = 10.0
 locationManager.startUpdatingLocation()
 locationManager.delegate = self

       只有在allowsBackgroundLocationUpdates为true和Capabilities页开启Background Modes,选择了Location updates,才能在后台运行,并在delegate执行相应的逻辑

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        
        for location in locations {
            let howRecent = location.timestamp.timeIntervalSinceNow
            
            //筛选loaction(10秒前的坐标位置不要)
            if abs(howRecent) >= 10 {
                continue;
            }
            
            //筛选loaction(精度不达标的位置信息不要)
            if location.horizontalAccuracy < kCLLocationAccuracyNearestTenMeters * 3 && location.horizontalAccuracy > 0   {
                if !self.locations.isEmpty{
                    //计算跑步的距离
                    distance += location.distance(from: self.locations.last!)
                }
                self.locations.append(location)
            } 
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读