iOS选取iCloud视频生成缩略图报无权限查看文件错误如何解决
问题根因
- 你从PHImageManager拿到的AVURLAsset对应的URL是系统相册的临时安全URL,仅在
requestAVAsset的回调闭包作用域内持有访问权限,你把AVAsset丢到全局后台异步队列执行的时候,临时权限已经被系统回收,所以访问URL时报权限错误。 - 你能成功读取
Data(contentsOf: url)是因为这个操作在回调的作用域内执行,权限还没失效,但后续生成缩略图的操作在异步闭包里,已经过了权限有效期。
你之前查的关闭沙盒的解决方案是macOS应用的配置,iOS应用没有该选项,也不需要关闭沙盒,你遇到的权限问题和沙盒无关,是临时访问URL的有效期问题。
解决方案
方案1:使用PHImageManager原生方法生成缩略图(推荐)
系统原生的requestImage方法天生支持iCloud资源,自动处理权限和网络下载,比自行实现AVAssetImageGenerator稳定性高很多,示例代码:
let requestOptions = PHImageRequestOptions() requestOptions.isNetworkAccessAllowed = true // 允许下载iCloud资源 requestOptions.deliveryMode = .highQualityFormat // targetSize可根据需要的缩略图尺寸自定义填写 PHImageManager.default().requestImage(for: phAsset, targetSize: CGSize(width: 600, height: 600), contentMode: .aspectFit, options: requestOptions) { image, info in guard let thumbnail = image else { print("生成缩略图失败") return } // 拿到缩略图后可直接使用 }
方案2:修改现有AVAssetImageGenerator实现
如果确实需要自定义生成逻辑,不要把生成操作丢到外部异步队列,直接在requestAVAsset的回调作用域内执行,或提前把视频数据拷贝到应用沙盒目录后再生成缩略图,修改后的代码示例:
let options = PHVideoRequestOptions() options.isNetworkAccessAllowed = true options.progressHandler = { (progress, error, stop, info) in print("progress: \(progress)") } PHImageManager.default().requestAVAsset(forVideo: phAsset, options: options) { (avAsset, mix, info) in // 直接在回调内执行缩略图生成,不切队列避免权限失效 let assetImgGenerate = AVAssetImageGenerator(asset: avAsset) assetImgGenerate.appliesPreferredTrackTransform = true let time = CMTime(seconds: 0.0, preferredTimescale: 600) do { let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil) let thumbnail = UIImage(cgImage: img) // 拿到缩略图后如果有耗时操作再切到后台队列 DispatchQueue.global(qos: .background).async { // 后续处理缩略图的逻辑放此处 } } catch { print(error.localizedDescription) } // 读取视频数据的操作也放在当前作用域内执行 if let urlAsset = avAsset as? AVURLAsset { do { let videoData = try Data(contentsOf: urlAsset.url) // 视频数据处理逻辑 } catch { print("读取视频数据失败") } } }
内容的提问来源于stack exchange,提问作者John Xavier
相关产品推荐
相关产品推荐

