didFinishPickingMediaWithInfo在iOS 13中返回不同的URL

时间:2019-09-05 05:31:45

标签: ios swift uiimagepickercontroller ios13

- (void)videoPickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info

在iOS 13和其他iOS中返回不同的URL。

知道为什么会这样吗?

iOS 13:

file:///private/var/mobile/Containers/Data/PluginKitPlugin/0849234B-837C-43ED-BEDD-DE4F79E7CE96/tmp/trim.B8AB021D-F4B6-4E50-A93C-8B7F7FB40A1C.MOV

file:///private/var/mobile/Containers/Data/Application/5AE52A95-6A2F-49A5-8210-D70E022E9A05/tmp/5A8D81B5-FC42-4228-9514-CD998A4E7FA9.MOV

这是由于我没有PluginKitPlugin文件夹的权限而导致的错误。

在两种情况下,我都是使用imagePicker选择视频的。

5 个答案:

答案 0 :(得分:5)

该问题可能与url的生存期有关,该生存期与NSDictionary<UIImagePickerControllerInfoKey,id> *)info对象的生存期有关。如果对象被释放,则该URL无效。因此,您可以保留对对象的引用或将媒体复制到更永久的位置。在更新到iOS 13 / Xcode 11之后,我遇到了类似的问题。

注意:此答案也进行了修改,以符合@mstorsjo提供的信息,也在此线程中:https://stackoverflow.com/a/58099385/3220330

答案 1 :(得分:5)

我为此苦了几个晚上,终于解决了这个问题。

这里用例的差异之一是我将视频上传到AWS S3。这是通过后台线程中的S3传输实用程序发生的。经过一堆的试验和调试,这就是我的决定。

更改是在iOS 13中,图像选择器控制器didFinishPickingMediaWithInfo方法的info [ .mediaURL ]参数中返回的mediaURL指向“ PluginKitsPlugin ”目录。看来我们的应用很长时间无法访问此位置。

示例:file:/// private / var / mobile / Containers / Data / PluginKitPlugin / 0849234B-837C-43ED-BEDD-DE4F79E7CE96 / tmp / trim。 B8AB021D-F4B6-4E50-A93C-8B7F7FB40A1C.MOV

由于某些原因(也许有人知道),只能临时访问该URL。这里有一些理论建议关闭图像选择器控制器将取消分配URL,从而使其无效。

通过这种理论,我尝试解决这两种不同的方法:

  1. 在上载完成之前,请不要关闭图像选择器。这没有用。 S3传输实用程序的后台进程仍然默默死于“找不到文件”错误。
  2. 将参考传递给信息字典,并在离上传点尽可能近的地方使用它。我正在上载到AWS S3,因此当S3在后台上载时,信息字典的取消引用仍可能会发生。

最终解决此问题的方法是将信息[.mediaURL]复制到应用程序临时文件夹中的另一个位置。

这是我用来将信息[ .mediaURL ]复制到我应用的临时文件夹中的代码。

     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
    }

此代码将文件复制到一个临时目录(如下所示),您的应用在其生命周期内可以访问该目录: 文件:/// private / var / mobile / Containers / Data / 应用程序/5AE52A95-6A2F-49A5-8210-D70E022E9A05/tmp/5A8D81B5-FC42-4228-9514-CD998A4E7FA9.MOV

您会注意到,选择要上传的图像(信息[ .imageURL ])将返回同一目录中的文件。上传图片没有先前的问题。

借助S3传输实用程序,可以在后台线程中访问文件并完成将视频上传到S3。

答案 2 :(得分:2)

扩展并阐明先前的答案。只要您要使用url,就需要保留对(NSDictionary<UIImagePickerControllerInfoKey,id> *)info对象的引用。该词典包含对PHAsset对象的引用,该对象可能控制对URL的访问-在取消引用和释放资产对象之后,较早的URL将变得不可读。

此问题的其他解决方法是,将url复制到应用程序自己的沙箱中的另一个临时文件中,这可能是通过立即使用源url来工作的,尽管它仍然有效且可访问,但在发布信息和url之前再次无法访问。

答案 3 :(得分:2)

以下是code的Objective-C版本。最初的修复是由@Bumbleparrot快速给出的:

-(NSURL *)createTemporaryPathforVideoFile:(NSURL *)url{
    NSURL *tempURL =  [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:true];
    NSURL *tempFileURL = [tempURL URLByAppendingPathComponent:url.lastPathComponent];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    [fileManager copyItemAtURL:url.absoluteURL toURL:tempFileURL error:nil];
    return tempFileURL ;
}

答案 4 :(得分:0)

从我从具有此路径的iOS 13中遇到权限问题中收集的信息来看,这是因为选择器是一个单独的应用程序(具有自己的权限),在iOS 13中变得更加明确。因此,它给您的路径是在自己的临时目录(而不是您的应用程序)中。

对于我们来说,代码假定给定的路径是我们的临时目录。我切换到显式缓存到NSTemporaryDirectory。