Xamarin.iOS 中的后台传输和 NSURLSession
后台传输是通过配置后台 NSURLSession
和排队上传或下载任务来启动的。 如果在应用程序处于后台、暂停或终止状态时完成任务,iOS 将通过调用应用程序 AppDelegate 中的完成事件处理器来通知应用程序。 下图演示了此操作的实际应用:
配置后台会话
要创建后台会话,请使用 NSUrlSessionConfiguration
对象创建新的 NSUrlSession
并对其进行配置。
配置对象决定了会话可以执行的操作及可运行的任务类型。
使用 CreateBackgroundSessionConfiguration
方法配置的会话将在单独的进程中运行,并执行任意 (WiFi) 传输以保护数据和电池寿命。
下面的代码示例演示了如何使用 CreateBackgroundSessionConfiguration
方法和唯一字符串标识符正确设置后台传输会话:
public partial class SimpleBackgroundTransferViewController : UIViewController
{
NSUrlSession session = null;
NSUrlSessionConfiguration configuration =
NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration ("com.SimpleBackgroundTransfer.BackgroundSession");
session = NSUrlSession.FromConfiguration
(configuration, new MySessionDelegate(), new NSOperationQueue());
}
除了配置对象以外,会话还需要会话委托和队列。 队列确定了任务完成的顺序。 会话委托则监督传输过程,并处理身份验证、缓存和其他与会话相关的问题。
使用任务和委托
配置后台会话后,让我们启动任务来处理传输。 可以使用名为会话委托的 NSUrlSessionDelegate
实例跟踪这些任务。 会话委托负责在后台唤醒已终止或挂起的应用程序来处理身份验证、错误或完成传输。
提供了 NSUrlSessionDelegate
以下用于检查传输状态的基本方法:
- DidFinishEventsForBackgroundSession - 完成所有任务且传输完成时将调用此方法。
- DidReceiveChallenge - 在需要授权时调用此方法以请求凭据。
- DidBecomeInvalidWithError - 如果
NSURLSession
失效,则调用它。
后台会话需要更专门的委托,具体取决于正在运行的任务类型。 后台会话限制为两种类型的任务:
- 上传任务 - 类型为
NSUrlSessionUploadTask
任务将会使用实现INSUrlSessionDelegate
的INSUrlSessionTaskDelegate
接口。 这提供了用于跟踪上传进度、处理 HTTP 重定向等的其他方法。 - 下载任务 - 类型为
NSUrlSessionDownloadTask
的任务将会使用实现INSUrlSessionDelegate
和INSUrlSessionTaskDelegate
的INSUrlSessionDownloadDelegate
接口。 这提供了用于上传任务的所有方法,以及特定于下载的方法,可用于跟踪下载进度并确定下载任务何时恢复或完成。
以下代码定义了可用于从 URL 下载图像的任务。 该任务通过调用后台会话上的 CreateDownloadTask
并传入 URL 请求来启动:
const string DownloadURLString = "http://xamarin.com/images/xamarin.png"; // or other hosted file
public NSUrlSessionDownloadTask downloadTask;
NSUrl downloadURL = NSUrl.FromString (DownloadURLString);
NSUrlRequest request = NSUrlRequest.FromUrl (downloadURL);
downloadTask = session.CreateDownloadTask (request);
接下来,创建新的会话下载委托,以跟踪此会话中的所有下载任务。 委托类应继承 NSObject
并实现所需的接口:
public class MySessionDelegate : NSObject, INSUrlSessionDownloadDelegate
{
public void DidWriteData (NSUrlSession session, NSUrlSessionDownloadTask downloadTask, long bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite)
{
Console.WriteLine (string.Format ("DownloadTask: {0} progress: {1}", downloadTask, progress));
InvokeOnMainThread( () => {
// update UI with progress bar, if desired
});
}
...
}
要了解下载任务的进度,请替代跟踪进度 DidWriteData
方法,甚至更新 UI。 如果应用程序位于前台,或将在下次打开应用程序时等待用户,则 UI 更新将立即显示。
会话委托 API 提供广泛的工具包来与任务交互。 有关会话委托方法的完整列表,请参阅 NSUrlSessionDelegate
API 文档。
重要
后台会话在后台线程上启动,因此必须通过调用 InvokeOnMainThread
在 UI 线程上显式运行更新 UI 的任何调用,以避免 iOS 终止应用。
处理传输完成
最后一步是告知应用程序与会话关联的所有任务都已完成,并处理新内容。
在 AppDelegate
中订阅 HandleEventsForBackgroundUrl
事件。 当应用程序进入后台且传输会话正在运行时,将会调用此方法,并且系统将向我们传递完成事件处理器:
public System.Action backgroundSessionCompletionHandler;
public void HandleEventsForBackgroundUrl (UIApplication application, string sessionIdentifier, System.Action completionHandler)
{
this.backgroundSessionCompletionHandler = completionHandler;
}
使用完成事件处理器告知 iOS 应用程序何时完成处理。
回想一下,会话可以生成多个任务来处理传输。 最后一个任务完成后,挂起或终止的应用程序将重新启动到后台。 然后,应用程序将使用唯一会话标识符重新连接到 NSURLSession
,并调用会话委托上的 DidFinishEventsForBackgroundSession
。 此方法是应用程序处理新内容的机会,包括更新 UI 以反映传输结果:
public void DidFinishEventsForBackgroundSession (NSUrlSession session) {
// Handle new information, update UI, etc.
}
完成新内容处理后,调用完成事件处理器,以告知系统可以安全地拍摄应用程序的快照并返回到睡眠状态:
public void DidFinishEventsForBackgroundSession (NSUrlSession session) {
var appDelegate = UIApplication.SharedApplication.Delegate as AppDelegate;
// Handle new information, update UI, etc.
// call completion handler when you're done
if (appDelegate.backgroundSessionCompletionHandler != null) {
NSAction handler = appDelegate.backgroundSessionCompletionHandler;
appDelegate.backgroundSessionCompletionHandler = null;
handler.Invoke ();
}
}
本演练介绍了在 iOS 7 及更高版本中实现后台传输服务的基本步骤。