【问题标题】:How to execute alamofire background upload request?如何执行alamofire后台上传请求?
【发布时间】:2017-06-18 08:07:10
【问题描述】:

我需要将 zip 文件发送到服务器端。

有我的要求,我需要在后台工作

let configuration = URLSessionConfiguration.default
    configuration.timeoutIntervalForRequest = 10 // seconds
    alamoFireManager = Alamofire.SessionManager(configuration: configuration)

appDeligate.log.debug("request was sended")

    alamoFireManager.upload(deligate.data!,
                            to: deligate.url,
                            method: .post,
                            headers: headers)
        .uploadProgress(closure: {
            progress in
            print("Upload Progress: \(progress.fractionCompleted)")
        })
        .validate()
        .responseJSON {}

现在它可以正常工作了,但我需要在后台执行它。根据 Alamofire README 文档

https://github.com/Alamofire/Alamofire

它说

使用后台配置创建会话管理器

让配置 = URLSessionConfiguration.background(withIdentifier: "com.example.app.background")

让 sessionManager = Alamofire.SessionManager(配置:配置)

我将配置更改为对应的后台配置

现在看起来像这样

let configuration = URLSessionConfiguration.background(withIdentifier: "com.room.myApp")
configuration.timeoutIntervalForRequest = 10 // seconds
    alamoFireManager = Alamofire.SessionManager(configuration: configuration)

alamoFireManager.upload(deligate.data!,
                            to: deligate.url,
                            method: .post,
                            headers: headers)
        .uploadProgress(closure: {
            progress in
            print("Upload Progress: \(progress.fractionCompleted)")
        })
        .validate()
        .responseJSON {}

我得到错误

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Upload tasks from NSData are not supported in background sessions.'
*** First throw call stack:
(0x18ec511b8 0x18d68855c 0x18f33808c 0x18f33796c 0x18f336e68  0x100ef9218 0x100f05dc8 0x18f336dc8 0x18f3378cc 0x100255890 0x1002518e8  0x100234200 0x100234448 0x100ef9218 0x100f05dc8 0x100233fc4 0x100255290  0x10029d238 0x10029ae4c 0x10029ac34 0x10006dd78 0x100071044 0x100082708  0x10002b310 0x100ef9258 0x100ef9218 0x100f0726c 0x100f08e2c 0x100f08b78  0x18dce32a0 0x18dce2d8c)
libc++abi.dylib: terminating with uncaught exception of type NSException

我做错了什么?

是我的问题还是 lib 的问题?

欢迎提问

编辑

有发送流

这是我如何创建 zip 文件

internal func madeRequest() {
    DispatchQueue.global().async {
        if self.createZipPhotoDir() {
            self.appDeligate.log.debug("zip dir was created")
            self.serverConnection.makeServerRequest()
        } else {
            self.appDeligate.log.error("can NOT execute createZipPhotoDir()")
        }
    }
}

private func createZipPhotoDir() -> Bool {
    let withContentsOfDirectory: String! = UtilDirectory.pathToMyCurrentAvatarDir.tweak() // "/var/mobile/Containers/Data/Application/739A895E-7BCA-47A8-911F-70FBC812CEB3/Documents/default@domein.com/AvatarPackage/name/"
    let atPath: String! = UtilDirectory.tempZipPath.tweak() // "/var/mobile/Containers/Data/Application/739A895E-7BCA-47A8-911F-70FBC812CEB3/Documents/default@domein.com/tmpZipDir.zip"
    
    return SSZipArchive.createZipFile(atPath: atPath, withContentsOfDirectory: withContentsOfDirectory)
}

zip 文件创建成功

然后我发出服务器请求

required init() {
    configureAlamofireManager()
}

private func configureAlamofireManager() {
    let configuration = URLSessionConfiguration.background(withIdentifier: "com.fittingroom.newtimezone.Fitzz")
    alamoFireManager = Alamofire.SessionManager(configuration: configuration)
}

internal func makeServerRequest() {
    appDeligate.log.debug("request was sended")

    alamoFireManager.upload(deligate.data!,
                            to: deligate.url,
                            method: .post,
                            headers: headers)
        .uploadProgress(closure: {
            progress in
            print("Upload Progress: \(progress.fractionCompleted)")
        })
        .validate()
        .responseJSON {
            [weak self]
            response in
            
            self?.appDeligate.log.debug("response : \(response)")
            self?.appDeligate.log.debug(String(describing: response.timeline))
            
            switch response.result {
            case .success(let value):
                self?.appDeligate.log.debug("succes in server connection response")
                let result = self?.getStatusCodeAndData(json: JSON(value))
                self?.deligate.onSuccess(statusCode: result?.statusCode, data: result?.data)
            case .failure(let error):
                self?.appDeligate.log.error("error in UploadingRequest : \(error)")
                self?.deligate.onError()
            }
    }
}

有一种方法可以让我发送数据

internal var data: Data {
    var data = Data()
    let filePath = UtilDirectory.tempZipPath.tweak()
    
    if let result = UtilFile.exists(path: filePath), result.isFileExist == true, result.whatIsIt == .file {
        if let fileData = FileManager.default.contents(atPath: filePath) {
            data = fileData
            appDeligate.log.debug("*** DATA : \(data) ***")
        } else {
            print("Could not parse the file")
        }

    } else {
        appDeligate.log.error("some ERROR here: file not exist")
    }

    return data
}

【问题讨论】:

  • 也许尝试其他类型的上传?如果您有文件,请发送 fileURL?
  • @muescha 是的,我做到了。在我当前的示例中,我通过 Data() 并且它失败了,并且我也将 URL(string: path) 传递给了 zip 文件并且也失败了 ((
  • @AlekseyTimoshchenko stackoverflow.com/questions/29852431/… 看看这个话题,也许你会想出一些关于如何处理问题的新想法。 :)

标签: swift xcode alamofire


【解决方案1】:

使用下面的代码一次,它对我有用

导入 Alamofire

var sessionManager: Alamofire.SessionManager
var backgroundSessionManager: Alamofire.SessionManager 
self.sessionManager = Alamofire.SessionManager(configuration: URLSessionConfiguration.default)
self.backgroundSessionManager = Alamofire.SessionManager(configuration: URLSessionConfiguration.background(withIdentifier: "com.youApp.identifier.backgroundtransfer"))


backgroundSessionManager.upload(multipartFormData: blockFormData!, usingThreshold: UInt64.init(), to: url, method: .post, headers: APIManager.headers(), encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
    upload.uploadProgress {
        (progress) in
        let p = progress.fractionCompleted * 100
        uploadProgress(p)
    }
    upload.responseJSON { response in
        switch(response.result) {
        case .success(let JSON):
            DispatchQueue.main.async {
                    print(JSON)
            }
        case .failure(let error):
            DispatchQueue.main.async {
                print(error)
            }
        }
    }
case .failure(let error):
    DispatchQueue.main.async {
        print(error)
    }
}
})

【讨论】:

    【解决方案2】:

    来自Background Transfer Considerations

    仅支持从文件上传任务(从数据对象或流上传将在程序退出后失败)。

    这意味着它是来自 NSURLSession 的限制 - 您需要从文件上传,然后尝试使用文件解决其他错误

    更新

    appDeligate.log.debug("request was sended")
    
    let tempZipFilePath = UtilDirectory.tempZipPath.tweak()
    
    alamoFireManager.upload(tempZipFilePath,
                            to: deligate.url,
                            method: .post,
                            headers: headers)
    

    【讨论】:

    • 我没有完全理解你的想法。有我的情况 - 我有 5 张照片,然后我将它们放在 zip 文件中并需要发送......我如何从文件上传?你什么意思?
    • 您是否已经创建了 zip 文件? zip 文件是否存在?请在您如何制作 zip 文件的问题中添加一个新部分。或开始在后台发送图像。一步步。但由于 alamofire 使用 NSURLSession 你只能发送文件引用let fileURL = Bundle.main.url(forResource: "MyImage", withExtension: "jpg")
    • 为问题添加了描述
    • 据我了解,URLSession 不能将其作为数据处理(如果您查看上传的 alamofire 实现:如果数据太大,那么他们无论如何都会将其写入文件并使用文件引用发送)。这就是为什么尝试使用deligate.data!,但只使用文件引用(文件路径)filePath = UtilDirectory.tempZipPath.tweak()
    • 上传请求获取 URL,我这样设置 URL(string: tempZipFilePath)! ,但无论如何我得到了同样的错误。您如何看待,错误可能是由于某种许可引起的?也许我需要在项目中设置权限?
    【解决方案3】:

    你看到这个部分了吗Open Radars:

    打开雷达

    以下雷达对 Alamofire 的当前实施有一些影响。

    rdar://26870455 - 后台 URL 会话配置在模拟器中不起作用

    【讨论】:

    • 是的,但我在真实设备上尝试了此代码。不是模拟器
    猜你喜欢
    • 2015-10-23
    • 1970-01-01
    • 2019-06-14
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    • 2017-03-05
    • 1970-01-01
    相关资源
    最近更新 更多