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

PHPickerViewController视频上传进度追踪及长视频上传提速问题

解决方案:大视频加载进度追踪与提速优化

一、追踪视频加载进度

PHPickerViewController的loadFileRepresentation方法没有内置进度回调,要实现进度追踪,需通过PHAsset结合PHAssetResourceManager处理,该方案支持实时获取加载进度:

func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
    picker.dismiss(animated: true)
    progressWheel.startAnimating()
    progressWheel.alpha = 1

    for result in results {
        guard let assetID = result.assetIdentifier else { continue }
        let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [assetID], options: nil)
        guard let asset = fetchResult.firstObject else { continue }
        
        let resources = PHAssetResource.assetResources(for: asset)
        guard let videoResource = resources.first(where: { $0.type == .video }) else { continue }
        
        let tempPath = NSTemporaryDirectory().appending(NSUUID().uuidString).appending(".mov")
        let tempFileURL = URL(fileURLWithPath: tempPath)
        
        let requestOptions = PHAssetResourceRequestOptions()
        // 实时回调加载进度
        requestOptions.progressHandler = { progress, _, _, _ in
            DispatchQueue.main.async {
                self.progressWheel.progress = Float(progress)
            }
        }
        
        PHAssetResourceManager.default().requestDataForAssetResource(videoResource, options: requestOptions) { data in
            // 分块写入临时文件
            if let fileHandle = try? FileHandle(forWritingTo: tempFileURL) {
                fileHandle.seekToEndOfFile()
                fileHandle.write(data)
                fileHandle.closeFile()
            }
        } completionHandler: { error in
            DispatchQueue.main.async {
                self.progressWheel.stopAnimating()
            }
            guard error == nil else {
                print("视频加载失败:\(error!)")
                return
            }
            // 加载完成,执行上传
            self.uploadVideo(videoURL: tempFileURL)
        }
    }
}

二、提速优化方案

1. 移除冗余操作与不必要的文件复制

你的代码中重复调用了两次loadFileRepresentation,这会导致重复加载视频,直接删除其中一次即可。另外,若videoURL本身是可直接访问的本地文件(绝大多数场景下都是),可直接传入Firebase上传,跳过临时文件复制步骤,减少IO开销:

result.itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { videoURL, error in
    guard let videoURL = videoURL, error == nil else {
        print(error!)
        return
    }
    DispatchQueue.main.async {
        self.uploadVideo(videoURL: videoURL)
        self.progressWheel.stopAnimating()
    }
}

2. 直接用Firebase Storage的PHAsset上传API

Firebase Storage支持直接从PHAsset上传,跳过本地文件下载/复制环节,大幅提升大视频处理效率:

import FirebaseStorage

func uploadAssetToFirebase(asset: PHAsset) {
    let storageRef = Storage.storage().reference().child("videos/\(NSUUID().uuidString).mov")
    let metadata = StorageMetadata()
    metadata.contentType = "video/quicktime"
    
    storageRef.putFile(from: asset, metadata: metadata) { metadata, error in
        guard error == nil else {
            print("上传失败:\(error!)")
            return
        }
        // 获取下载URL
        storageRef.downloadURL { url, error in
            guard let downloadURL = url else { return }
            print("上传完成:\(downloadURL)")
        }
    }
}

调用时直接传入之前获取到的PHAsset即可,Firebase会自动处理资源加载,无需手动操作文件。

3. 后台任务保障大文件操作

对于超5分钟的视频,建议将加载和上传放到后台队列执行,同时启动后台任务,避免APP进入后台后被系统终止:

var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid

// 开始操作前启动后台任务
backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "VideoUpload") {
    UIApplication.shared.endBackgroundTask(self.backgroundTaskID)
    self.backgroundTaskID = .invalid
}

// 操作完成后结束后台任务
DispatchQueue.main.async {
    UIApplication.shared.endBackgroundTask(self.backgroundTaskID)
    self.backgroundTaskID = .invalid
}

4. 修复错误处理隐患

代码中使用try!会导致复制失败时直接崩溃,替换为do-catch安全处理:

do {
    try FileManager.default.copyItem(at: videoURL, to: copiedURLFile)
} catch {
    print("文件复制失败:\(error)")
    return
}

内容的提问来源于stack exchange,提问作者EAO123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 06:06:08