Alamofire 上传带有进度的大文件并在应用重启时显示进度

Posted

技术标签:

【中文标题】Alamofire 上传带有进度的大文件并在应用重启时显示进度【英文标题】:Alamofire uploading large files with progress and show progress on app restart 【发布时间】:2018-08-20 12:56:17 【问题描述】:

我已通过以下步骤设置项目。

    我已启用外部附件通信和后台获取 AppDelegate:
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) 
        API.sharedInstance.backgroundCompletionHandler = completionHandler
    
    这里是处理所有 api 调用的 API.swift 类
public class API: NSObject 

    var sessionManager: SessionManager
    var delegate: SessionDelegate
    public var backgroundSessionManager: Alamofire.SessionManager

    var backgroundCompletionHandler: (() -> Void)? 
        get 
            return backgroundSessionManager.backgroundCompletionHandler
        
        set 
            backgroundSessionManager.backgroundCompletionHandler = newValue
        
    

    /// access a shared instance of an API manager
    public class var sharedInstance: API 
        struct Singleton 
            static let instance = API()
        
        return Singleton.instance
    

    public required override init() 
        let configuration = URLSessionConfiguration.default
        self.sessionManager = SessionManager(configuration: configuration)
        let identifier = "com.appname.backgroundtransfer"
        self.backgroundSessionManager = Alamofire.SessionManager(configuration: URLSessionConfiguration.background(withIdentifier: identifier))
        self.sessionManager.adapter = AccessTokenAdapter()
        delegate = self.backgroundSessionManager.delegate
    

    func authHeaderWithToken() -> [String : String] 
        return [Constants.HeaderKeys.Authorization : "Bearer " + (AppManager.sharedInstance.accessToken ?? "")]
    

    func uploadFilesToServer(parameters: [String : Any], image: UIImage?, audio: Data?, video: Data?, uploadItem: Upload, progressHandle: @escaping ProgressHandler, success: @escaping SuccessJsonClosure, failed: @escaping NetworkError) 
        let URL = Constants.BASE_URL + "api_uploadFiles"

        let headers: HTTPHeaders = [
            Constants.HeaderKeys.Authorization : "Bearer " + (AppManager.sharedInstance.accessToken ?? ""),
            "Content-type": "multipart/form-data"
        ]

        self.backgroundSessionManager.upload(multipartFormData:  (multipartData) in
            // multipart setup
            if let img = image 
                multipartData.append(UIImageJPEGRepresentation(img, 1.0)!, withName: "file", fileName: "\(uploadItem.fileName!)", mimeType: "image/jpeg")
            

            if let vid = video 
                multipartData.append(vid, withName: "file", fileName: "\(uploadItem.fileName!)", mimeType: "video/mov")
            

            if let aud = audio 
                multipartData.append(aud, withName: "file", fileName: "\(uploadItem.fileName!)", mimeType: "audio/mov")
            

            for (key, value) in parameters 
                multipartData.append("\(value)".data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!, withName: key)
            


        , to: URL, method: .post, headers: headers, encodingCompletion:  encodingResult in
            // transmission closure
            switch (encodingResult) 
            // encodingResult success
            case .success(let request, let streamingFromDisk, let streamFileURL):

                // upload progress closure
                request.uploadProgress(closure:  (progress) in
                    print("upload progress: \(progress.fractionCompleted)")
                    progressHandle(progress)
                )

                // response handler
                request.responseJSON(completionHandler:  response in
                    switch response.result 
                    case .success(let jsonData):
                        // do any parsing on your request's response if needed
                        let json = try! JSON(data: response.data!)
                        let isOK = json["success"].boolValue
                        if isOK 
                            success(true, json)
                         else 
                            failed(nil, json)
                        

                    case .failure(let error):
                        failed(error, nil)
                    
                )

            // encodingResult failure
            case .failure(let error):
                failed(error, nil)

             // end encodingresult switch
        )

      

如果应用程序没有被杀死,文件会成功上传到服务器。但如果我在上传过程中终止应用程序,我将无法获得进度状态。当应用程序重新启动(杀死并打开)时,完成块不会被执行。 uploadFilesToServer 函数多次调用(例如:5 个视频上传和 5 个调用)。当应用程序重新启动时,我需要跟踪每次上传的进度。我们如何跟踪正在进行的请求?以及我们如何上传大文件并为每个请求运行完成调用。

在这里我将视频保存到文档目录并使用 url 传递数据

【问题讨论】:

【参考方案1】:

要在完成时运行操作,您需要覆盖会话的委托 sessionDidFinishEventsForBackgroundURLSession: ((URLSession) -> Void)? Alamofire doc

对于每次上传的进度,我仍在尝试寻找重新附加代理的方法,但到目前为止还没有成功。 我们一定是做错了什么

【讨论】:

以上是关于Alamofire 上传带有进度的大文件并在应用重启时显示进度的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Alamofire 4.0 中添加带有上传进度百分比的标签的进度条

如何使用 alamofire 上传多个文件并显示进度?

通过 API 将带有 Alamofire 的 STL 文件上传到 Octoprint

使用 Alamofire(多部分数据)上传带有额外参数的 .PDF 文件时出错

Alamofire 上传进度

获取分段上传 Alamofire 5 的上传进度