问题
- (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
.
回答1:
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
回答2:
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:
- Don't dismiss the image picker until after the upload happens. This did not work. The background process for the S3 transfer utility was still silently dying with the "file not found" error.
- Pass a reference to the info dictionary and use it as close to the upload point as possible. I was uploading to AWS S3 so it's possible that the dereferencing of the info dictionary was still happening when S3 went to upload in the background.
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.
回答3:
To expand on and clarify the earlier answers. You need to keep a reference to the (NSDictionary<UIImagePickerControllerInfoKey,id> *)info
object, for as long as you are going to use the url. This dictionary contains a reference to a PHAsset object, which probably controls access to the url - after the asset object is unreferenced and released, the earlier url becomes unreadable.
Other workarounds for the issue, by copying the url to another temporary file within the app's own sandbox, probably work by actually using the source url immediately, while it still is valid and accessible, before the info is released and the url becomes inaccessible again.
回答4:
From what I have gathered from experiencing permissions problems in iOS 13 with this path, it is because the picker is a separate app (with its own permissions) which has become more explicit in iOS 13. So the path it gives you is within its own temporary directory rather than your app's.
For us the code was assuming the path given was our temporary directory. I switched to explicitly caching into NSTemporaryDirectory.
来源:https://stackoverflow.com/questions/57798968/didfinishpickingmediawithinfo-returns-different-url-in-ios-13