三种方式使得iOS应用能够在后台进行数据更新和下载
三种方式使得iOS程序即使在关闭或崩溃的情况下也能够在后台持续进行一些任务,比如更新程序界面快照,下载文件等。这三个方法分别是 Background Fetch,Remote Notification和NSURLSession的backgroundSessionConfiguration
Background Fetch
开启
首先在info plist文件中开启UIBackgroundModes的Background fetch。或者手动编辑这个值
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
</array>
iOS默认不进行background fetch,需要设置一个时间的间隔
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//UIApplicationBackgroundFetchIntervalMinimum表示尽可能频繁去获取,如果需要指定至少多少时间更新一次就需要给定一个时间值
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
最后在App Delegate里实现下面的方法,这个方法只能在30秒内完成。
- (void) application:(UIApplication *)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration]; NSURL *url = [[NSURL alloc] initWithString:@"http://yourserver.com/data.json"];
NSURLSessionDataTask *task = [session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) {
completionHandler(UIBackgroundFetchResultFailed);
return;
} // 解析响应/数据以决定新内容是否可用
BOOL hasNewData = ...
if (hasNewData) {
completionHandler(UIBackgroundFetchResultNewData);
} else {
completionHandler(UIBackgroundFetchResultNoData);
}
}]; // 开始任务
[task resume];
}
测试
- 通过查看UIApplication的applicationState
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog(@"Launched in background %d", UIApplicationStateBackground == application.applicationState); return YES;
}
Remote Notification
在普通的远程通知里带上content-available标志就可以在通知用户同时在后台进行更新。通知结构如下
{
"aps" : {
"content-available" : 1
},
"content-id" : 42
}
接收一条带有content-available的通知会调用下面的方法
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(@"Remote Notification userInfo is %@", userInfo); NSNumber *contentID = userInfo[@"content-id"];
// 根据 content ID 进行操作
completionHandler(UIBackgroundFetchResultNewData);
}
利用NSURLSession进行background transfer task
使用[NSURLSessionConfiguration backgroundSessionConfiguration]创建一个后台任务,当应用退出后,崩溃或进程被关掉都还是会运行。
范例,先处理一条远程通知,并将NSURLSessionDownloadTask添加到后台传输服务队列。
- (NSURLSession *)backgroundURLSession
{
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *identifier = @"io.objc.backgroundTransferExample";
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
session = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
}); return session;
} - (void) application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(@"Received remote notification with userInfo %@", userInfo); NSNumber *contentID = userInfo[@"content-id"];
NSString *downloadURLString = [NSString stringWithFormat:@"http://yourserver.com/downloads/%d.mp3", [contentID intValue]];
NSURL* downloadURL = [NSURL URLWithString:downloadURLString]; NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
NSURLSessionDownloadTask *task = [[self backgroundURLSession] downloadTaskWithRequest:request];
task.taskDescription = [NSString stringWithFormat:@"Podcast Episode %d", [contentID intValue]];
//执行resume保证开始了任务
[task resume]; completionHandler(UIBackgroundFetchResultNewData);
}
下载完成后调用NSURLSessionDownloadDelegate的委托方法,这些委托方法全部是必须实现的。了解所有类型session task的生命周期可以参考官方文档:https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html#//apple_ref/doc/uid/10000165i-CH2-SW42
#Pragma Mark - NSURLSessionDownloadDelegate - (void) URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
NSLog(@"downloadTask:%@ didFinishDownloadingToURL:%@", downloadTask.taskDescription, location); // 必须用 NSFileManager 将文件复制到应用的存储中,因为临时文件在方法返回后会被删除
// ... // 通知 UI 刷新
} - (void) URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
} - (void) URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
}
后台的任务完成后如果应用没有在前台运行,需要实现UIApplication的两个delegate让系统唤醒应用
- (void) application:(UIApplication *)application
handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
// 你必须重新建立一个后台 seesiong 的参照
// 否则 NSURLSessionDownloadDelegate 和 NSURLSessionDelegate 方法会因为
// 没有 对 session 的 delegate 设定而不会被调用。参见上面的 backgroundURLSession
NSURLSession *backgroundSession = [self backgroundURLSession]; NSLog(@"Rejoining session with identifier %@ %@", identifier, backgroundSession); // 保存 completion handler 以在处理 session 事件后更新 UI
[self addCompletionHandler:completionHandler forSession:identifier];
} - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
NSLog(@"Background URL session %@ finished events.
", session); if (session.configuration.identifier) {
// 调用在 -application:handleEventsForBackgroundURLSession: 中保存的 handler
[self callCompletionHandlerForSession:session.configuration.identifier];
}
} - (void)addCompletionHandler:(CompletionHandlerType)handler forSession:(NSString *)identifier
{
if ([self.completionHandlerDictionary objectForKey:identifier]) {
NSLog(@"Error: Got multiple handlers for a single session identifier. This should not happen.
");
} [self.completionHandlerDictionary setObject:handler forKey:identifier];
} - (void)callCompletionHandlerForSession: (NSString *)identifier
{
CompletionHandlerType handler = [self.completionHandlerDictionary objectForKey: identifier]; if (handler) {
[self.completionHandlerDictionary removeObjectForKey: identifier];
NSLog(@"Calling completion handler for session %@", identifier); handler();
}
}
转载地址:http://www.starming.com/index.php?v=index&view=69
三种方式使得iOS应用能够在后台进行数据更新和下载的更多相关文章
- iOS字体加载三种方式
静态加载 动态加载 动态下载苹果提供的多种字体 其他 打印出当前所有可用的字体 检查某字体是否已经下载 这是一篇很简短的文章,介绍了 iOS 自定义字体加载的三种方式. 静态加载 这个可以说是最简单最 ...
- iOS --- UIWebView的加载本地数据的三种方式
UIWebView是IOS内置的浏览器,可以浏览网页,打开文档 html/htm pdf docx txt等格式的文件. safari浏览器就是通过UIWebView做的. 服务器将MIM ...
- iOS拨打电话的三种方式
iOS拨打电话的三种方式 1,这种方法,拨打完电话回不到原来的应用,会停留在通讯录里,而且是直接拨打,不弹出提示 1 2 var string = "tel:" + "1 ...
- ios网络学习------4 UIWebView的加载本地数据的三种方式
ios网络学习------4 UIWebView的加载本地数据的三种方式 分类: IOS2014-06-27 12:56 959人阅读 评论(0) 收藏 举报 UIWebView是IOS内置的浏览器, ...
- IOS 多线程,线程同步的三种方式
本文主要是讲述 IOS 多线程,线程同步的三种方式,更多IOS技术知识,请登陆疯狂软件教育官网. 一般情况下我们使用线程,在多个线程共同访问同一块资源.为保护线程资源的安全和线程访问的正确性. 在IO ...
- ios学习网络------4 UIWebView以三种方式中的本地数据
UIWebView这是IOS内置的浏览器.能够浏览网页,打开文档 html/htm pdf docx txt等待格文档类型. safari浏览器是通过UIWebView制作. server将 ...
- iOS开发 跳转场景的三种方式
iOS开发 跳转场景的三种方式 2012年10月17日, 15:32 假设A跳转到B,三种方法:1.按住ctrl键,拖动A上的控件(比如说UIButton)到B上,弹出菜单,选择Modal.不需要写任 ...
- iOS-Core Foundation框架到Foundation桥接的三种方式
温故知新.勤总结,才能生巧!这次总结一下 :Core Foundation框架到Foundation桥接的三种方式 Foundation提供OC的基础类(像NSObject).基本数据类型等. Cor ...
- iOS:延时执行的三种方式
延时执行的三种方式:performSelectorXXX方法.GCD中延时函数.创建定时器 第一种方式:NSObject分类当中的方法,延迟一段时间调用某一个方法 @interface NSObj ...
随机推荐
- ADO.net简单增删改查
嘿嘿,又到了总结了的时间,今天我们学习了ADO.net,什么是ADO.NET:ADO.NET就是一组类库,这组类库可以让我们通过程序的方式访问数据库,就像System.IO下的类操作文件一样, Sys ...
- 日历控件input框默认显示当日日期
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <script sr ...
- 洛谷 P1599 结算日
洛谷 P1599 结算日 题目描述 “不放债不借债”,贝西多么希望自己可以遵循这个忠告.她已经和她的N(1 <= N <= 100,000)个朋友有了债务关系,或者借债了,或者放债了.她的 ...
- Android Material风格的应用(一)--AppBar TabLayout
打造Material风格的Android应用 Android Material风格的应用(一)--AppBar TabLayoutAndroid Material风格的应用(二)--RecyclerV ...
- Spring拦截器和Servlet过滤器区别
http://blog.csdn.net/chenleixing/article/details/44573495
- 互信息 & 卡方 - 文本挖掘
在做文本挖掘,特别是有监督的学习时,常常需要从文本中提取特征,提取出对学习有价值的分类,而不是把所有的词都用上,因此一些词对分类的作用不大,比如“的.是.在.了”等停用词.这里介绍两种常用的特征选择方 ...
- SpringMVC实战(三种控制器方式)
1.前言 上篇博客着重说了一下SpringMVC中几种处理映射的方式,这篇博客来说一下SpringMVC中几种经常使用的控制器. 2.经常使用控制器 2.1 ParameterizableViewC ...
- iOS:实现图片的无限轮播---之使用第三方库SDCycleScrollView
SDCycleScrollView API // // SDCycleScrollView.h // SDCycleScrollView #import <UIKit/UIKit.h> ...
- [Angular] Angular Global Keyboard Handling With EventManager
If we want to add global event handler, we can use 'EventManager' from '@angular/platform-broswer'. ...
- WCF REST 基础教程
概述 Representational State Transfer(REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格. 因此REST是设计风格而不是标准,R ...