I have a working Alamofire upload request using the following:
Alamofire.upload(multipartFormData: { multipartFormData in
...
}
Now I want the request to be launched in background, as it's embedded in a Share extension.
Looking at Alamofire page, I simply added:
let configuration = URLSessionConfiguration.background(withIdentifier: "com...")
let sessionManager = Alamofire.SessionManager(configuration: configuration)
sessionManager.upload(multipartFormData: { multipartFormData in
...
}
Now when executed I instantly get:
Operation couldn't complete. NSURLErrorDomain error -995
I can't find any reference to this error and what it means. Any ideas? Thanks a lot!
Related
I am using Alamofire for my uploads. I need to upload multiple images and videos to my server.I need to upload images and videos to in background session even
let bundleIdentifier = Bundle.main.bundleIdentifier
let configuration = URLSessionConfiguration.background(withIdentifier: bundleIdentifier!)
configuration.timeoutIntervalForRequest = 200 // seconds
configuration.timeoutIntervalForResource = 200
self.alamoFireManager = Alamofire.SessionManager(configuration: configuration)
I am using above code setup alamofire for background configuration.
alamoFireManager?.upload(data!, with: (router))
.uploadProgress { progress in // main queue by default
print("Upload Progress: \(progress.fractionCompleted)")
}.validate()
.responseJSON { [weak self] response in
}
but my app is crash when i went to background with SIGABRT
let me know what i am doing wrong,
This is a limitation of Apple's NSUrlSession implementation. Apple doesn't allow usage of NSData for background sessions. But uploading files are allowed. So as a workaround, you can try writing the data to a file and upload that file instead. You can follow the implementation here:
https://stackoverflow.com/a/22107789/1921759
In a class my project is using have a var to store the alamofire manager:
var alamoManager: Manager!
A method is called repeatedly in the app to config this manager like so:
func configAlamoManager() {
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 20
//ETC
alamoManager = Alamofire.Manager(configuration: configuration)
}
I have a HTTP call in my app that is ocasiaonally returning a 999 canceled error code. I suspect this is because the manager currently trying to perform the request is replaced by another one from the configAlamoManager() method. Is there any way to just change the config settings in the manager without creating a new instance? alamoManager.session.configuration has no setter. Any pointers on this would be really appreciated! Thanks
Instead of changing the configuration and creating a new Manager, you should override the configuration in the actual NSURLRequest.
let urlRequest = NSURLRequest(url: url)
urlRequest.timeoutInterval = 20
Alamofire.request(urlRequest).responseJSON { response in
debugPrint(response)
}
For more info on what you can override using an NSURLRequest, I'd check out the docs.
If I run the following code and let the app in background, the download is still continuing. Finally, when the download is finished, I can get the right callback.
let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(SessionProperties.identifier)
let backgroundSession = NSURLSession(configuration: configuration, delegate: self.delegate, delegateQueue: nil)
let url = NSURLRequest(URL: NSURL(string: data[1])!)
let downloadTask = backgroundSession.downloadTaskWithRequest(url)
downloadTask.resume()
But I have a requirement, that is I have to judge what the server returns to me, if it is a json, I don't do the download, so I want to get the response header first, then if it needs to download, I change the data task to download task, so I did as the following code
let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(SessionProperties.identifier)
let backgroundSession = NSURLSession(configuration: configuration, delegate: self.delegate, delegateQueue: nil)
let url = NSURLRequest(URL: NSURL(string: data[1])!)
//I change the downloadTaskWithRequest to dataTaskWithRequest
let downloadTask = backgroundSession.dataTaskWithRequest(url)
downloadTask.resume()
Then I can get the response header in the callback, and if it needs to download file, I can change the data task to download task, as following
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
if let response = response as? NSHTTPURLResponse {
let contentType = response.allHeaderFields["Content-Type"] as! String
if contentType == "image/jpeg" {
//change the data task to download task
completionHandler(.BecomeDownload)
return
}
}
completionHandler(.Allow)
}
So far so good. When I run the app in the foreground, the effect is like what I thought. But after the app runs in background, the download is stoped, then when I open the app, the console says "Lost connection to background transfer service".
I thought Apple is so smart, he gives us many useful callbacks, but now, I didn't know where I am wrong, and I also see the source code about the AFNetworking and Alamofire, but I didn't find the referring thing.
I also think it is a common requirement, but I can't find any helpful information on the internet, it is too odd.
So hope you can help me out, thanks a billion.
Enable Background Mode in
Xcode->Target->Capabilities->On Background Mode and select the option Background Fetch.
The main issue I see is that you're calling the completionHandler twice. You need to return out of your content-type conditional like so:
if contentType == "image/jpeg" {
//change the data task to download task
completionHandler(.BecomeDownload)
return
}
Otherwise it appears that you are using the logic correctly. Hope that helps.
The problem is evident from your own answer. It's not a bug, you simply couldn't use data tasks for background transfers just download tasks.
Here is the correct full answer.
I try to download images from Amazon S3 server via AlamofireImage framework.
The Images on the S3 server, save with 'Content-Type' = 'binary/octet-stream'.
In the beginning I got the Error:
Failed to validate response due to unacceptable content type.
So, I tried to change/update the HTTP Header's request in order to support with binary/octet-stream'
I updated the method:
private func URLRequestWithURL(URL: NSURL) -> NSURLRequest
In the UIImageView+AlamofireImage.swift file to:
private func URLRequestWithURL(URL: NSURL) -> NSURLRequest {
let mutableURLRequest = NSMutableURLRequest(URL: URL)
mutableURLRequest.addValue("binary/octet-stream", forHTTPHeaderField: "Content-Type")
return mutableURLRequest
}
And is still not working, Just after I added the:
let contentTypes: Set<String> = ["Content-Type", "binary/octet-stream"]
Request.addAcceptableImageContentTypes(contentTypes)
The problem was solved, But I really don't like the fact that I changed a private method in the AlamofireImage framework.
I wonder if there is an elegant way to solve this problem, given I can't change the images 'Content-Type' in the S3 server.
Thanks
Doing Request.addAcceptableImageContentTypes(["binary/octet-stream"]) should be all that you need to get it to work.
If you were using af_setImageWithURL, there was a bug that it wasn't using the acceptableImageContentTypes. AlamofireImage 2.2.0 fixes that.
In Swift 3.2 it's slightly different.
let request = URLRequest(url: URL)
DataRequest.addAcceptableImageContentTypes(["binary/octet-stream"])
AlamoDownloader.shared.imageDownloader.download(request){ response in
DataRequest is an Alamofire public class.
Adhoc deployed app on a device, the app runs fine with wifi, but does not work with 3g connection. Any idea what i'm missing?
Din't get much help from google.
And also the app installed does not show in the Use Mobile Data For : list
Code :
//To handle time out issue with 3g
configuration.timeoutIntervalForResource = 60
// Mark using Alamofire to do the downloads
self.alamofireManager = Alamofire.Manager(configuration:configuration)
self.alamofireManager!.request(.GET, jsonUrl).responseJSON(){
(_, _, JSON, _) in
println("printing json :\(JSON)")
if JSON != nil {
let imageInfos = (JSON!.valueForKey("image") as [NSDictionary]).map {
ImageInfo(id: $0["id"] as String, url: $0["url"] as String)
}
self.tableData.addObjectsFromArray(imageInfos)
}
Error log:
I get a
(Error Domain = NSURLErrorDomain Code = -1004 )
no matter how much i increase the timeoutInterval. Tried both with Resource and Request
Forgot to mention that the server was a Raspberry Pi, and i could not access the server outside the LAN so that was causing the problem. Thanks for the help. timeout was very helpful in handling server faults.
there wan't be any issue with app working on wifi or 3G. the only problem with request timeout. the issue related to internet bandwidth.
Please use following code for change request time out may be help to you.
var alamofireManager : Alamofire.Manager?
func getCallToServer(){
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForResource = 10 // seconds
self.alamofireManager = Alamofire.Manager(configuration: configuration)
self.alamofireManager!.request(.GET, "http://example.com/")
.response { (request, response, data, error) in
}
}