如何在背景ios中运行alamofire下载进度?

我使用Alamofire下载数据

如何使用swift使alamofire在后台运行下载?

谢谢

最佳答案
基本思路如下:

>关键问题是,通过后台下载,您的应用程序实际上可能会在下载过程中终止(例如由于内存压力而被抛弃).幸运的是,当后台下载完成时,您的应用程序会再次启动,但您最初提供的任何任务级别的关闭都很快就会消失.为了解决这个问题,在使用后台会话时,应该依赖委托方法使用的会话级闭包.

import UIKit
import Alamofire
import UserNotifications

fileprivate let backgroundIdentifier = ...
fileprivate let notificationIdentifier = ...

final class BackgroundSession {

    /// Shared singleton instance of BackgroundSession

    static let shared = BackgroundSession()

    /// AlamoFire `SessionManager`
    ///
    /// This is `private` to keep this app loosely coupled with Alamofire.

    private let manager: SessionManager

    /// Save background completion handler, supplied by app delegate

    func saveBackgroundCompletionHandler(_ backgroundCompletionHandler: @escaping () -> Void) {
        manager.backgroundCompletionHandler = backgroundCompletionHandler
    }

    /// Initialize background session
    ///
    /// This is `private` to avoid accidentally instantiating separate instance of this singleton object.

    private init() {
        let configuration = URLSessionConfiguration.background(withIdentifier: backgroundIdentifier)
        manager = SessionManager(configuration: configuration)

        // specify what to do when download is done

        manager.delegate.downloadTaskDidFinishDownloadingToURL = { _, task, location in
            do {
                let destination = try FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
                    .appendingPathComponent(task.originalRequest!.url!.lastPathComponent)
                try FileManager.default.moveItem(at: location, to: destination)
            } catch {
                print("\(error)")
            }
        }

        // specify what to do when background session finishes; i.e. make sure to call saved completion handler
        // if you don't implement this, it will call the saved `backgroundCompletionHandler` for you

        manager.delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] _ in
            self?.manager.backgroundCompletionHandler?()
            self?.manager.backgroundCompletionHandler = nil

            // if you want, tell the user that the downloads are done

            let content = UNMutableNotificationContent()
            content.title = "All downloads done"
            content.body = "Whoo, hoo!"
            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
            let notification = UNNotificationRequest(identifier: notificationIdentifier, content: content, trigger: trigger)
            UNUserNotificationCenter.current().add(notification)
        }

        // specify what to do upon error

        manager.delegate.taskDidComplete = { _, task, error in
            let filename = task.originalRequest!.url!.lastPathComponent
            if let error = error {
                print("\(filename) error: \(error)")
            } else {
                print("\(filename) done!")
            }

            // I might want to post some event to `NotificationCenter`
            // so app UI can be updated, if it's in foreground
        }
    }

    func download(_ url: URL) {
        manager.download(url)
    }
}

>然后我就可以启动这些下载.注意,我在开始下载时没有指定任何特定于任务的闭包,而只是使用上面的会话级闭包,它使用URLSessionTask的细节来识别要做的事情:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // request permission to post notification if download finishes while this is running in background

        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
            if let error = error, !granted {
                print("\(error)")
            }
        }
    }

    @IBAction func didTapButton(_ sender: Any) {
        let urlStrings = [
            "http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/s72-55482.jpg",
            "http://spaceflight.nasa.gov/gallery/images/apollo/apollo10/hires/as10-34-5162.jpg",
            "http://spaceflight.nasa.gov/gallery/images/apollo-soyuz/apollo-soyuz/hires/s75-33375.jpg",
            "http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-134-20380.jpg",
            "http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-140-21497.jpg",
            "http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-148-22727.jpg"
        ]
        let urls = urlStrings.flatMap { URL(string: $0) }

        for url in urls {
            BackgroundSession.shared.download(url)
        }
    }

}

>如果您的应用程序在下载完成后没有运行,iOS需要知道,在重新启动您的应用程序后,当您完成所有操作并且可以安全地暂停您的应用程序时.因此,在handleEventsForBackgroundURLSession中捕获该闭包:

class AppDelegate: UIResponder, UIApplicationDelegate {

    ...

    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
        BackgroundSession.shared.saveBackgroundCompletionHandler(completionHandler)
    }

}

sessionDidFinishEventsForBackgroundURLSession在步骤1中使用它.

两点意见:

>只有在下载完成后您的应用未运行时才会调用此选项.
>但是,如果要进行后台会话,则必须捕获此闭包,并在完成后台会话委托方法的处理后调用它.

因此,回顾一下,后台会话的基本限制是:

>您只能在应用程序处于后台时使用下载和上传任务;
>您只能依赖会话级代理,因为应用程序可能已在请求启动后终止;和
>在iOS中,您必须实现handleEventsForBackgroundURLSession,捕获该完成处理程序,并在后台进程完成时调用它.

我还必须指出,虽然Alamofire是一个很棒的库,但它实际上并没有增加很多价值(超出了URLSession为这个后台下载过程提供的价值).如果您只进行简单的上传/下载,那么您可以考虑直接使用URLSession.但是如果您已经在项目中使用Alamofire,或者您的请求包含更复杂的应用程序/ x-www-form-urlencoded请求(或其他),这些请求值得Alamofire的优势,那么上面概述了涉及的主要移动部件.处理.

转载注明原文:如何在背景ios中运行alamofire下载进度? - 代码日志