You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:26:50