Search code examples
iosswiftnsurlsessionnsfilemanagernsurlsessionuploadtask

Swift create local file, append other local file for use with NSURLSession.uploadTask


I'm working with an API that accepts video uploads using multi-part form data. I would like to use an NSURLSession.uploadTask (plus it's delegates) for handling the upload.

My problem is that I need to alter the local video file to work with the API I'm using, I've created an example of what I would like to do:

let localVideoURL = URL(string: "file://AGoodURL/video.mov")!
let apiURL = URL(string: "https://myServer.com/upload")

func uploadVideo() {

let config = URLSessionConfiguration.background(withIdentifier: "myUploads")
let session = URLSession(configuration: config, delegate: nil, delegateQueue: nil)

var request = NSMutableURLRequest(url: apiURL!)
request.httpMethod = "POST"

// create a new file from the local file + required api data

var boundary : String {

    return "Boundary-\(UUID().uuidString)"
}

// what should be a new file and not an in memory data object, but how?
var data = Data()

// do I need to set these or will the uploadTaskWithFile class handle it?
data.append("--\(boundary)\r\n".data(using: .utf8)!)

data.append("Content-Disposition: form-data; name=\"video\"; filename=\"video.mov\"\r\n".data(using: .utf8)!)

// same question? does this need to be here?
data.append("Content-Type: video/quicktime\r\n\r\n".data(using: .utf8)!)

/** somehow get the data from the local url without loading it into memory */
// data.append(try! Data(contentsOf: localVideoURL)) /** not like this! */

data.append("\r\n".data(using: .utf8)!)
data.append("--\(boundary)--\r\n".data(using: .utf8)!)

// close the new file
// begin an uploadTask with the new file, use URLSessionDelegates.

session.uploadTask(with: request, fromFile: )

}

How would I create a new local file, add the string data as described above, append the local video file and add the rest of string data? These files can be very big so keeping it all on disk is important.


Solution

  • The solution was to use input & output streams with a new local temporary file where after the creation of the output stream I append the header data that's required for the multi-part form upload, then append the existing local file in chunks, then append the closing data (like the boundary) and close the stream.

    Then I use that file, which encapsulates the httpBody property of the request with an NSURLSession uploadTask w/file.