如何获取PHAsset的视频URL并在UICollectionView中展示相机胶卷所有视频
Hey,看起来你已经在做相机胶卷视频展示的功能了,我帮你把剩下的部分补全,同时解决获取PHAsset对应视频URL的问题~
1. 完善视频资源获取与UICollectionView刷新
首先你得确保已经处理了相册访问权限(这一步很容易忘!),在Info.plist里添加NSPhotoLibraryUsageDescription字段,填上向用户申请权限的理由(iOS 10+要求必须填)。
然后把你的fetchVideos方法补全,加上权限检查和UI刷新:
var videos: PHFetchResult<PHAsset>! fileprivate func fetchVideos() { print("fetch Videos") // 先请求相册访问权限 PHPhotoLibrary.requestAuthorization { [weak self] authStatus in guard authStatus == .authorized else { // 这里可以提示用户去设置开启权限,比如弹出Alert print("相册权限被拒绝,无法获取视频") return } // 回到主线程处理UI相关操作 DispatchQueue.main.async { let fetchOptions = PHFetchOptions() // 按创建时间倒序排列,最新的在最前面 fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] // 只过滤视频类型的资源 fetchOptions.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.video.rawValue) self?.videos = PHAsset.fetchAssets(with: fetchOptions) print("共获取到 \(self?.videos.count ?? 0) 个视频") self?.collectionView?.reloadData() } } }
接下来实现UICollectionView的数据源方法,展示视频缩略图:
// MARK: - UICollectionViewDataSource override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return videos?.count ?? 0 } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { // 假设你自定义了带缩略图的VideoCell,记得提前注册cell let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VideoCell", for: indexPath) as! VideoCell let videoAsset = videos[indexPath.item] // 用PHImageManager获取视频缩略图 let imageManager = PHImageManager.default() // 取消cell之前的请求,避免滑动时图片错乱 if let requestID = cell.imageRequestID { imageManager.cancelImageRequest(requestID) } cell.imageRequestID = imageManager.requestImage( for: videoAsset, targetSize: cell.thumbnailImageView.bounds.size, contentMode: .aspectFill, options: nil ) { image, _ in cell.thumbnailImageView.image = image } return cell }
注意:记得在你的自定义VideoCell里添加imageRequestID属性,用来存储图片请求的ID,方便滑动时取消未完成的请求,避免资源浪费和图片错乱。
2. 获取PHAsset对应的视频URL
要拿到视频的本地URL,我们需要用PHImageManager的requestAVAsset(forVideo:options:resultHandler:)方法,从返回的AVAsset中提取URL:
fileprivate func getVideoURL(from asset: PHAsset, completion: @escaping (URL?) -> Void) { let videoOptions = PHVideoRequestOptions() // 如果需要获取iCloud上的视频,开启这个选项 videoOptions.isNetworkAccessAllowed = true // 可以设置进度回调,比如显示加载进度 videoOptions.progressHandler = { progress, _, _, _ in print("视频加载进度:\(progress)") } PHImageManager.default().requestAVAsset(forVideo: asset, options: videoOptions) { avAsset, _, info in // 把AVAsset转成AVURLAsset才能拿到URL guard let urlAsset = avAsset as? AVURLAsset else { completion(nil) return } completion(urlAsset.url) } }
你可以在点击UICollectionViewCell的时候调用这个方法,比如:
// MARK: - UICollectionViewDelegate override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let selectedAsset = videos[indexPath.item] getVideoURL(from: selectedAsset) { videoURL in guard let url = videoURL else { print("无法获取视频URL") return } DispatchQueue.main.async { // 拿到URL后可以做很多事:比如用AVPlayer播放视频、上传到服务器等 print("视频本地URL:\(url)") } } }
额外小贴士
- 如果要处理大量视频,推荐使用
PHCachingImageManager来缓存缩略图,提升滑动流畅度。 - 记得处理权限被拒绝的情况,友好提示用户去设置里开启权限,不然用户会一脸懵。
- 如果你的App需要支持iOS 13及以下,注意
PHPhotoLibrary.requestAuthorization的回调线程,确保UI操作在主线程。
内容的提问来源于stack exchange,提问作者Sener
相关产品推荐
相关产品推荐

