【问题标题】:imagePickerController: Save video to play again on a subsequent run of the appimagePickerController:保存视频以在应用程序的后续运行中再次播放
【发布时间】:2018-12-19 19:02:57
【问题描述】:

在我的应用中,用户使用内置的UIImagePickerController 从他们的库中选择一个视频。我可以检索 URL 并播放所选视频。这很好用。

但是,我还希望能够在用户退出并重新启动应用程序后稍后播放相同的视频,而无需用户使用选择器重新选择它。我想不出办法来做到这一点。我尝试同时使用UIImagePickerControllerReferenceURLUIImagePickerControllerMediaURL。当我立即播放视频时,它们都可以工作。我尝试将这些 URL 保存在 userDefaults 中,并在下次运行应用程序时检索它们。我正确检索了 URL,但视频无法使用 AVPlayer 播放。我预计 UIImagePickerControllerMediaURL 会出现这种行为,因为这似乎是一个临时 URL,但我没想到 UIImagePickerControllerReferenceURL 会出现这种情况。

我也尝试过使用PHAsset.fetchAssets(withALAssetURLs: <#T##[URL]#>, options: <#T##PHFetchOptions?#>),但这不会返回任何值。

如何保存对视频或视频本身的引用以供日后使用?

【问题讨论】:

标签: ios swift video uiimagepickercontroller userdefaults


【解决方案1】:

试试这个方法,对我有用:

private func loadVideo(url: URL, saveUrl: Bool = false) {
    let player = AVPlayer(url: url)
    let playerController = AVPlayerViewController()
    playerController.player = player
    present(playerController, animated: true) {
        player.play()
    }

    guard saveUrl else { return }

    UserDefaults.standard.set(url, forKey: "keyVideoUrl")
    UserDefaults.standard.synchronize()
}

要按顺序获得权限,请在Info.plist 文件中添加以下内容:

<key>NSPhotoLibraryUsageDescription</key>
<string>Message description in here</string>

现在请求权限并启动视频选择器:

PHPhotoLibrary.requestAuthorization { [weak self] (status) -> Void in
    guard status == .authorized else { return }

    let imagePicker = UIImagePickerController()
    imagePicker.delegate = self
    imagePicker.sourceType = .photoLibrary
    imagePicker.mediaTypes = [kUTTypeMovie as String]

    self?.present(imagePicker, animated: true, completion: nil)
}

最后用这个didFinishPickingMediaWithInfo方法:

extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        self.dismiss(animated: true, completion: nil)

        guard let asset = info[UIImagePickerControllerPHAsset] as? PHAsset else { return }

        PHImageManager.default().requestAVAsset(forVideo: asset, options: PHVideoRequestOptions(),
                                                resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [AnyHashable : Any]?) -> Void in
            if let urlAsset = asset as? AVURLAsset {
                self.loadVideo(url: urlAsset.url, saveUrl: true)
            }
        })
    }

}

选择视频并播放后,您可以重新启动应用并尝试重播,如下所示:

if let url = UserDefaults.standard.url(forKey: "keyVideoUrl") {
    self.loadVideo(url: url)
}

这里是完整的工作源ViewController.swift

【讨论】:

  • 问题是当我从UIImagePickerController 获得一个 URL 时,该 URL 仅在我运行应用程序的那段时间有效。下次我运行该应用程序时,该 URL 不再有效。
  • 我可以确认这是有效的,您可以将 URL 保存在 UserDefaults 中并在下次应用启动时重播视频,我创建了一个 ViewController,您可以启动并查看它,gist URL @987654322 @
【解决方案2】:

感谢来自 AamirR 和 Max9xs 的 cmets 对我的上述问题,我选择实施的解决方案是将文件从 TMP 目录移动到 Documents 目录。然后播放 Documents 目录中的视频。这也避免了每次用户使用 imagePickerController 选择新视频时,TMP 目录都会被视频填满的问题。

委托函数中的以下代码将移动文件:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

    let mediaType = info[UIImagePickerControllerMediaType] as! String
    if  mediaType == (kUTTypeMovie as String) {

        let TMPvideoURL = info[UIImagePickerControllerMediaURL] as! URL
        let TMPvideoPath = TMPvideoURL.path

        let manager = FileManager.default
        let documentsDirectory = manager.urls(for: .documentDirectory, in: .userDomainMask).last!
        let docVideoURL = documentsDirectory.appendingPathComponent("selectedLibraryVideo.mov")
        let docVideoPath = docVideoURL.path

        do {
            if manager.fileExists(atPath: docVideoPath) {
                try manager.removeItem(atPath: docVideoPath)
            }
            try manager.moveItem(atPath: TMPvideoPath, toPath: docVideoPath)
        }
        catch {
            print(error)
        }
    }

    photoLibraryPickerController?.dismiss(animated: false, completion: nil)

}

然后我可以随后通过对 Documents 文件夹中文件路径的引用来播放视频。这很好用。

        let documentsDirectory = manager.urls(for: .documentDirectory, in: .userDomainMask).last!
        let docVideoURL = documentsDirectory.appendingPathComponent("selectedLibraryVideo.mov")
        let docVideoPath = docVideoURL.path

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 2012-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-06
    相关资源
    最近更新 更多