- (void)videoPickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info
returns different URLs in iOS 13 and the other iOSs.
Any idea why this might be happening?
iOS 13:
file:///private/var/mobile/Containers/Data/PluginKitPlugin/0849234B-837C-43ED-BEDD-DE4F79E7CE96/tmp/trim.B8AB021D-F4B6-4E50-A93C-8B7F7FB40A1C.MOV
< iOS 13:
file:///private/var/mobile/Containers/Data/Application/5AE52A95-6A2F-49A5-8210-D70E022E9A05/tmp/5A8D81B5-FC42-4228-9514-CD998A4E7FA9.MOV
This caused me to have an error since I don’t have permissions to the PluginKitPlugin
folder.
In both cases, I’m selecting a video using the imagePicker
.
I struggled with this for a few nights and finally resolved the issue.
One of the differences in use case here is that I was uploading the video to AWS S3. This happens via the S3 transfer utility in a background thread. With a bunch of experimenting and debugging, Here's what I determined.
The change is that in iOS 13, the mediaURL returned in the info[.mediaURL] parameter from the image picker controller didFinishPickingMediaWithInfo method points to a temporary folder under the "PluginKitsPlugin" directory. It seems like our app doesn't have access to this location for very long.
Example: file:///private/var/mobile/Containers/Data/PluginKitPlugin/0849234B-837C-43ED-BEDD-DE4F79E7CE96/tmp/trim.B8AB021D-F4B6-4E50-A93C-8B7F7FB40A1C.MOV
For some reason (maybe someone else knows) access to that URL is only available temporarily. Some theories here suggest that dismissing the image picker controller will de-allocate the URL thus making it invalid.
With this theory I tried to work around this 2 different ways:
What ended up solving the issue was copying the info[.mediaURL] to another place available in my App's temporary folder.
Here's the code I used to copy the info[.mediaURL] to my App's temporary folder.
This function will copy a video file to a temporary location so that it remains accessbile for further handling such as an upload to S3.
- Parameter url: This is the url of the media item.
- Returns: Return a new URL for the local copy of the vidoe file.
*/
func createTemporaryURLforVideoFile(url: NSURL) -> NSURL {
/// Create the temporary directory.
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
/// create a temporary file for us to copy the video to.
let temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(url.lastPathComponent ?? "")
/// Attempt the copy.
do {
try FileManager().copyItem(at: url.absoluteURL!, to: temporaryFileURL)
} catch {
print("There was an error copying the video file to the temporary location.")
}
return temporaryFileURL as NSURL
}
This code copies to the file to a temp directory like one below where your app has access during its lifecycle: file:///private/var/mobile/Containers/Data/Application/5AE52A95-6A2F-49A5-8210-D70E022E9A05/tmp/5A8D81B5-FC42-4228-9514-CD998A4E7FA9.MOV
You will notice that selecting images (info[.imageURL]) to upload will return a file in the same directory. There were no prior issues uploading images.
With that the S3 transfer utility was able to access the file in a background thread and finish the video upload to S3.
The issue may be connected to the lifetime of the url, which is extant with the lifetime of NSDictionary<UIImagePickerControllerInfoKey,id> *)info
object. If the object is deallocated, the url is invalidated. So you can keep a reference to the object or copy the media to a more permanent location. I had a similar issue after the update to iOS 13 / Xcode 11.
Note: this answer was modified to conform with the information provided by @mstorsjo, also in this thread: https://stackoverflow.com/a/58099385/3220330
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With