如何使alamofire下载进度运行在后台ios? [英] how to make alamofire download progress run in background ios?

查看:367
本文介绍了如何使alamofire下载进度运行在后台ios?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Alamofire 下载数据

如何使amamofire在后台运行swift?

How to make alamofire run download in background with swift?

感谢

推荐答案

基本思路如下: p>

The basic idea is as follows:


  1. 关键问题是,随着后台下载,您的应用可能会在下载进行过程中终止(例如由于内存压力而丢弃) )。幸运的是,当后台下载完成后,您的应用程序再次被启动,但您最初提供的任何级别的关闭都已经过去了。为了解决这个问题,在使用后台会话时,应该使用委托方法使用的会话级关闭。

  1. The key problem is that with background downloads, your app may actually be terminated while downloads are in progress (e.g. jettisoned due to memory pressure). Fortunately, your app is fired up again when background downloads are done, but any task-level closures you originally supplied are long gone. To get around this, when using background sessions, one should rely upon session-level closures used by the delegate methods.

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 的详细信息来识别什么要做:

  • Then I can just initiate those downloads. Note, I do not specify any task-specific closure when I initiate the download, but rather merely use the above session-level closures that use the details of the URLSessionTask to identify what to do:

    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 中,您可以捕获该关闭:

  • If your app isn't running when the downloads finish, iOS needs to know that, after it restarted your app, when you're all done and that it can safely suspend your app. So, in handleEventsForBackgroundURLSession you capture that closure:

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

    sessionDidFinishEventsForBackgroundURLSession 中使用

    两个意见:


    • 仅当您的应用程序在下载完成后没有运行时才会调用。

    • This is only called if your app was not running when the downloads finish.

    如果执行后台会话,则必须捕获此关闭,并在完成处理后台会话委托方法时调用它。

    If doing background sessions, though, you must capture this closure and call it when you're all done processing the background session delegate methods.

    所以,要总结一下背景的基本限制会话是:

    So, to recap, the basic limitations of background sessions are:


    • 您只能在应用程序处于后台时使用下载和上传任务;

    • You can only use download and upload tasks while the app is in background;

    您只能依靠会话级别的代理,因为该应用可能已被终止,因为请求被启动;和

    You can only rely upon session-level delegates because the app may have been terminated since the requests were initiated; and

    在iOS中,您必须实现 handleEventsForBackgroundURLSession ,捕获该完成处理程序,并在您的后台进程完成。

    In iOS, you must implement handleEventsForBackgroundURLSession, capture that completion handler, and call it when your background process is done.

    我还必须指出,虽然Alamofire是一个精彩的库,但实际上并没有添加批次价值(以上和以下由 URLSession 提供给本背景下载过程)。如果您只做简单的上传/下载,那么您可以考虑直接使用 URLSession 。但是,如果您在项目中使用Alamofire,或者您的请求包含更复杂的 application / x-www-form-urlencoded 请求(或任何)优点, Alamofire,那么上面概述了这个过程中涉及的关键移动部件。

    I must also point out that while Alamofire is a wonderful library, it's not actually adding a lot value (above and beyond what is provided by URLSession to this background download process). If you're doing simple uploads/downloads only, then you might consider just using URLSession directly. But if you are using Alamofire in your project already or if your requests consist of more complicated application/x-www-form-urlencoded requests (or whatever) which merit the advantages of Alamofire, then the above outlines the key moving parts involved in the process.

    这篇关于如何使alamofire下载进度运行在后台ios?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆