在后台会话中下载 AlamoFire

AlamoFire Download in Background Session

我在新应用程序中使用 Alamofire(基于 Alamofire 的下载管理器示例) 我需要一些关于使用后台会话下载文件的说明。 我需要覆盖 SessionDelegate 才能让它工作吗? 或者只是 backgroundCompletionHandler?

通常情况下,使用 Alamofire 在后台处理下载的步骤是什么? 以及如何处理我的应用程序重新启动且下载量不断变化的情况。

更新

基于this amazing tutorial, I have put together an example project available on GitHub。它有一个后台会话管理的例子。

根据 Apple 的 URL Loading System Programming Guide

In both iOS and OS X, when the user relaunches your app, your app should immediately create background configuration objects with the same identifiers as any sessions that had outstanding tasks when your app was last running, then create a session for each of those configuration objects. These new sessions are similarly automatically reassociated with ongoing background activity.

显然,通过使用适当的后台会话配置实例,您的下载将永远不会 "in flux"。

我还发现 this answer 很有帮助。

原回答

来自 Alamofire 的 GitHub page

Applications can create managers for background and ephemeral sessions, as well as new managers that customize the default session configuration, such as for default headers (HTTPAdditionalHeaders) or timeout interval (timeoutIntervalForRequest).

默认情况下,顶级方法使用具有默认会话配置的共享 Manager 实例。但是,您可以创建一个具有后台会话配置的管理器,如下所示:

let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("com.example.app.background")
let manager = Alamofire.Manager(configuration: configuration)

然后您可以使用此 Manager 实例发出请求。

manager.startRequestsImmediately = true
let request = NSURLRequest(URL: NSURL(string: "your.url.here")!)
manager.request(request)

通过查看它的实现,它还有一个叫做backgroundCompletionHandler的属性,所以你可以添加一个完成块:

manager.backgroundCompletionHandler = {
        // do something when the request has finished
    }

编辑

对于 Alamofire 5,这不再可能,请参阅发行说明:

Using a URLSessionConfiguration with a background identifier is not possible any more. We're explicitly ensuring Alamofire isn't used with background sessions, in order to prevent ongoing issues around support and surprise on the part of the user.

旧答案,如果您使用 Alamofire 4 仍然有效

使用 Alamofire 实际上非常简单:

1) 您的 Alamofire.Manager 应配置后台会话标识符:

class NetworkManager {
    ...
    private lazy var backgroundManager: Alamofire.SessionManager = {
        let bundleIdentifier = ...
        return Alamofire.SessionManager(configuration: URLSessionConfiguration.background(withIdentifier: bundleIdentifier + ".background"))
    }()
    ...
}

2) 在 App Delegate 中实现 application(_:handleEventsForBackgroundURLSession:completionHandler: 并将完成处理程序传递给 Alamofire.SessionManager.backgroundCompletionHandler.

在我的例子中,应用程序委托方法看起来像

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
    NetworkManager.default.backgroundCompletionHandler = completionHandler
}

我的网络管理员有一个这样的计算 属性 来设置管理员 属性:

var backgroundCompletionHandler: (() -> Void)? {
    get {
        return backgroundManager.backgroundCompletionHandler
    }
    set {
        backgroundManager.backgroundCompletionHandler = newValue
    }
}

我一直在寻找解决方案。直到阅读了上面提到的文章。我的问题是 - 我必须启用 外部附件通信

其他的都按照上面的描述完成。 AppDelegate:

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
        BackendAPIManager.sharedInstance.backgroundCompletionHandler = completionHandler
    }

单例:

import Alamofire

class BackendAPIManager: NSObject {
    static let sharedInstance = BackendAPIManager()

    var alamoFireManager : Alamofire.SessionManager!

    var backgroundCompletionHandler: (() -> Void)? {
        get {
            return alamoFireManager?.backgroundCompletionHandler
        }
        set {
            alamoFireManager?.backgroundCompletionHandler = newValue
        }
    }

    fileprivate override init()
    {
        let configuration = URLSessionConfiguration.background(withIdentifier: "com.url.background")
        configuration.timeoutIntervalForRequest = 200 // seconds
        configuration.timeoutIntervalForResource = 200
        self.alamoFireManager = Alamofire.SessionManager(configuration: configuration)
    }
}

调用方式如下:

BackendAPIManager.sharedInstance.alamoFireManager.upload(multipartFormData: { (multipartFormData) in ...