AVPlayer播放错误:FireStorage缓存视频偶发播放非目标内容问题
问题根因定位
这种偶现的播放错误缓存视频的问题,通常是以下几个原因导致的:
- 不同视频的本地缓存路径重复,导致新下载的视频覆盖了旧的缓存文件
- 后台并发下载未做线程控制,多个写入任务同时操作同一个文件导致内容错乱
- 播放逻辑同时使用自定义缓存组件和原生AVAsset,出现缓存资源复用错误
- 页面复用/旧播放实例未销毁,导致前一个视频的播放资源被复用
修复方案
1. 确保本地缓存路径唯一
检查filePathURL(for:)方法的实现,不要只用imageFileName作为唯一标识,拼接Exercise的唯一ID避免重名,示例修改:func filePathURL(for exercise: Exercise) -> URL? { let fileName = "\(exercise.id)_\(exercise.imageFileName)" // 拼接业务唯一ID避免重名 let documentsDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] return URL(fileURLWithPath: documentsDir).appendingPathComponent(fileName) }2. 下载队列改为串行避免并发写冲突
你当前使用全局并发队列执行下载,同一时间多个下载任务同时写文件会导致内容错乱,自定义串行下载队列替换全局队列:// 全局定义串行下载队列 private let videoDownloadQueue = DispatchQueue(label: "com.yourApp.videoDownloadSerialQueue", qos: .background) // 修改getFileWith里的队列调用 func getFileWith(with url: URL, saveTo saveFilePathURL: URL) { videoDownloadQueue.async { // 替换原来的DispatchQueue.global().async print(saveFilePathURL.path) if let videoData = NSData(contentsOf: url) { try? videoData.write(to: saveFilePathURL, options: .atomic) } else { DispatchQueue.main.async { let error = NSError(domain: "SomeErrorDomain", code: -2001, userInfo: ["description": "Can't download video"]) print(error.debugDescription) } } } }3. 修复播放逻辑的资源冲突
你当前的播放代码同时初始化了CachingPlayerItem和原生AVPlayerItem,两个实例会同时读取同一资源,容易出现缓存冲突,直接用CachingPlayerItem初始化播放器,同时优先读取本地缓存文件:func startPlayingVideoOnDemand(url : URL, exercise: Exercise? = nil) { activityIndicatorView.startAnimating() activityIndicatorView.isHidden = false // 优先使用本地缓存文件url var targetUrl = url if let exercise = exercise, let localPath = filePathURL(for: exercise), FileManager.default.fileExists(atPath: localPath.path) { targetUrl = localPath } print(targetUrl) let cachingPlayerItem = CachingPlayerItem(url: targetUrl) cachingPlayerItem.delegate = self cachingPlayerItem.download() let player = AVPlayer(playerItem: cachingPlayerItem) player.automaticallyWaitsToMinimizeStalling = false // 播放前先销毁旧的播放器实例避免资源复用 if let existingPlayer = self.player { existingPlayer.replaceCurrentItem(with: nil) } self.player = player initializeVideoLayer(for: player) }4. 新增缓存有效性校验
下载完成后比对本地文件大小和服务器返回的文件大小,不一致则删除损坏缓存,避免读取错误内容:可以在写入文件前通过URLSession的dataTask获取响应头的Content-Length,写入完成后读取本地文件大小做比对,校验失败就删除本地文件触发重新下载。
内容的提问来源于stack exchange,提问作者user9261559
相关产品推荐
相关产品推荐

