iOS Background Modes

关于iOS后台操作只介绍了目前公司项目需要用到的:

一、Background Fetch(后台获取)

  后台获取干的事情就是在用户打开应用之前就有机会(没错,就是有机会)执行代码来获取数据,刷新UI。这样在用户打开APP的时候,最新的内容就已经呈现在用户眼前了,而不用当APP启动后再去加载。想一下,不再是进来等待数据请求完成然后再删一下刷新界面,反正听起来是相当令人振奋人心的。

具体操作:

<1>Target -> Capabilities -> Background Modes -> Background fetch (勾选)

<2>在应用启动后调用:[[UIApplicationsharedApplication]setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];这里的时间间隔代表“在上次获取或者关闭应用之后,在这段时间内一定不会去做后台获取”。也就是说真正具体到什么时候进行后台获取完全取决于系统的心情了,我们无法控制。系统只会在一些特定情况下(比如接受到邮件,推送...)顺便帮你的应用获取一下,也有可能专门为你的应用唤醒下设备。需要注意的是:如果应用对数据即使性不是特别高的话就不要用UIApplicationBackgroundFetchIntervalMinimum,而是自定义时间,可以尽可能的减少能耗。

PS:上面加粗的那句一定要有,要不系统会自动判定为UIApplicationBackgroundFetchIntervalNever,也就是永远不进行后台获取。

<3>完成前两步之后只需要在AppDelegate里实现:-application:performFetchWithCompletionHandler:就可以了。开发者需要的就是在这个代理里请求数据然后刷新UI,并通知系统获取结束。需要注意的是系统不会给你过长的时间去做fetch,一般会少于一分钟,而且看别人的博客说fetch在绝大多数情况下是和别的应用公用网络连接的(我自己没测试过,只是感觉好有意思,这样流量会算到别人的app上吗!!!)。在获取完成后必须通知系统获取完成,调用代理里的completionHandler:(),括号里传一个叫UIBackgroundFetchResult作为参数,可以传UIBackgroundFetchResultNewData,UIBackgroundFetchResultNoData,UIBackgroundFetchResultFailed三种。分别表示获取到了新数据(此时系统将对现在的UI状态截图并更新App Switcher中你的应用的截屏),没有新数据,以及获取失败。写一个简单的🌰吧:

- (void)application:(UIApplication*)application performFetchWithCompletionHandler:(void(^)(UIBackgroundFetchResult))completionHandler{

UINavigationController *navigationController = (UINavigationController*)self.window.rootViewController;

YDMainViewController *fetchViewController = navigationController.topViewController;

if([fetchViewController respondsToSelector:@selector(fetchDataResult:)]) {

[fetchViewController fetchDataResult:^(NSError *error, NSArray *results){

if(!error) {

if(results.count !=0) {

//Update UI with results.

//Tell system all done.

completionHandler(UIBackgroundFetchResultNewData);

}else{

completionHandler(UIBackgroundFetchResultNoData);

}

}else{

completionHandler(UIBackgroundFetchResultFailed);

}

}];

}else{

completionHandler(UIBackgroundFetchResultFailed);

}

}

PS:当然,实际情况中会比这要复杂得多,用户当前的ViewController是否合适做获取,获取后的数据如何处理都需要考虑。另外要说明的是上面的代码在获取成功后直接在appDelegate里更新UI,这只是为了能在同一处进行说明,但却是不正确的结构。比较好的做法是将获取和更新UI的业务逻辑都放到fetchViewController里,然后向其发送获取消息的时候将completionHandler作为参数传入,并在fetchViewController里完成获取结束的报告。

一、Remote-Notification(远程通知)

<1>Target -> Capabilities -> Background Modes -> Remote notifications(勾选)

<2>需要设置为静默推送: aps { content-available:1 alert:{...} } ,公司用的是极光推送,他们的官方文档有介绍。说实话,极光相当不靠谱,其中的坑大家自己去体会吧!

<3>最后在Appdelegate里实现-application:didReceiveRemoteNotification:fetchCompletionHandle:,iOS10.0以上要实现- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {}

下面介绍下一些限制和应用🌰(在CSDN上看到的,未亲测,目前这个还在开发当中)

  因为一旦推送成功,用户的设备将被唤醒,因此这类推送不可能不受到限制。Apple将限制此类推送的频率,当频率超过一定限制后,带有content-available标志的推送将会被阻塞,以保证用户设备不被频繁唤醒。按照Apple的说法,这个频率在一小时内个位数次的推送的话不会有太大问题。

  Apple给出了几个典型的应用情景,比如一个电视节目类的应用,当用户标记某些剧目为喜爱时,当这些剧有更新时,可以给用户发送静默的唤醒推送通知,客户端在接到通知后检查更新并开始后台下载(后台还在研究当中)。下载完成后发送一个本地推送告知用户新的内容已经准备完毕。这样在用户注意到推送并打开应用的时候,所有必要的内容已经下载完毕,UI也将切换至用户喜爱的剧目,用户只需要点击播放即可开始真正使用应用,这绝对是无比顺畅和优秀的体验。另一种应用情景是文件同步类,比如用户标记了一些文件为需要随时同步,这样用户在其他设备或网页服务上更改了这些文件时,可以发送静默推送然后使用后台传输来保持这些文件随时是最新。

  总的来说,其实后台获取和静默推送在很多方面是很类似的,特别是实现和处理的方式,但是它们适用的情景是完全不同的。后台获取更多地使用在泛数据模式下,也即用户对特定数据并不是很关心,数据应该被更新的时间也不是很确定,典型的有社交类应用和天气类应用;而静默推送或者是推送唤醒更多地应该是用户感兴趣的内容发生更新时被使用,比如消息类应用和内容型服务等。根据不同的应用情景,选择合适的后台策略(或者混合使用两者),以带给用户绝佳体验。

三、后台传输(Background Transfer Service)

iOS6.0及以下的我不太清楚,其实我解除iOS的时候就已经到8.0以上了。目前后台传输必须要使用到iOS7.0的网络连接新类,NSURLSession,这是iOS7用来替代以前的NSURLConnection的。多的不说直接贴开启后台任务的代码:

NSURLSessionConfiguration *configure = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.company.appname.BackgroundSession"];

NSURLSession *session = [NSURLSession sessionWithConfiguration:configure delegate:self delegateQueue:nil];

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"yourDownloadUrl"]];

NSURLSessionTask *task = [session downloadTaskWithRequest:request];

[task resume];

//下面是AFNetworking的后台任务的初始化,其他的大家应该都知道的(因为我没发现不用AFNetworking的,所以顺便贴一下)

//AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.company.appname.BackgroundSession"]];

  最后在AppDelegate中实现application:handleEventsForBackgroundURLSession:completionHandler:

-(void)application:(UIApplication*)applicationhandleEventsForBackgroundURLSession:(NSString*)identifiercompletionHandler:(void(^)())completionHandler{

//Check if all transfers are done, and update UI

//Then tell system background transfer over, so it can take new snapshot to show in App Switcher

 completionHandler();

//self.backTaskCompletionHandle = completionHandle;//建议用法,下面有介绍

//You can also pop up a local notification to remind the user}

NSURLSession和对应的NSURLSessionTask有以下重要的delegate方法可以使用:

-(void)URLSession:(NSURLSession*)sessiondownloadTask:(NSURLSessionDownloadTask*)downloadTaskdidFinishDownloadingToURL:(NSURL*)location;

-(void)URLSession:(NSURLSession*)sessiontask:(NSURLSessionTask*)taskdidCompleteWithError:(NSError*)error;

当后台传输的状态发生变化(包括正常结束和失败)的时候,应用将被唤醒并运行appDelegate中的回调,接下来NSURLSessionTask的委托方法将在后台被调用。虽然上面的例子中直接在appDelegate中call了completionHandler,但是实际上更好的选择是在appDelegate中暂时持有completionHandler,即上面注释掉的代码,然后在NSURLSessionTask的delegate方法中检查是否确实完成了传输并更新UI后,再调用appDelegate.completionHandler(),记得释放掉。另外,你的应用到现在为止只是在后台运行,想要提醒用户传输完成的话,也许你还需要在这个时候发送一个本地推送(记住在这个时候你的应用是可以执行代码的,虽然是在后台),这样用户可以注意到你的应用的变化并回到应用,并开始已经准备好数据和界面。

PS:网上有看到一些限制条件,但是目前还没有测试出来,如有大神知道的请一定要留言告诉我,谢谢!还有现在在做静默推送,恳请大神们指导下。

最后,如果收到通知,但是没有点击通知,而是通过点击icon进入,求获取消息内容的方法。目前我们是用当app再次进入前台的时候去请求后台存的推送,当然要和本地数据库最新一条比对一下。再次跪求有没有其他的方法......

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容