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

SwiftUI如何获取本地视频路径以上传至Firebase Storage?

问题描述

我想把视频上传到Firebase Storage,上传代码需要先获取本地视频URL:

let localFile = URL(string: "path/to/video")!

然后用这段代码完成上传:

let uploadTask = riversRef.putFile(from: localFile)

现在的问题是不知道怎么获取这个视频路径。我已经做了一个自定义的图片/视频选择器,图片上传功能正常,但视频上传卡在这里,核心就是拿不到本地路径。

更新:自定义选择器代码

import SwiftUI
import PhotosUI

class ImagePickerViewModel: ObservableObject {
    // MARK: Properties
    @Published var fetchedImages: [ImageAsset] = []
    @Published var selectedImages: [ImageAsset] = []
    
    init(){
        fetchImages()
    }
    
    // MARK: Fetching Images
    func fetchImages(){
        let options = PHFetchOptions()
        // MARK: Modify As Per Your Wish
        options.includeHiddenAssets = false
        options.includeAssetSourceTypes = [.typeUserLibrary]
        options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
        PHAsset.fetchAssets(with: .image, options: options).enumerateObjects { asset, _, _ in
            let imageAsset: ImageAsset = .init(asset: asset)
            self.fetchedImages.append(imageAsset)
        }
        PHAsset.fetchAssets(with: .video, options: options).enumerateObjects { asset, _, _ in
            let imageAsset: ImageAsset = .init(asset: asset)
            self.fetchedImages.append(imageAsset)
        }
    }
}

视图代码

.popupImagePicker(show: $showPicker) { assets in
    // MARK: Do Your Operation With PHAsset
    // I'm Simply Extracting Image
    // .init() Means Exact Size of the Image
    let manager = PHCachingImageManager.default()
    let options = PHImageRequestOptions()
    
    options.isSynchronous = true
    
    DispatchQueue.global(qos: .userInteractive).async {
        assets.forEach { asset in
            manager.requestImage(for: asset, targetSize: .init(), contentMode: .default, options: options) { image, _ in
                guard let image = image else {return}
                DispatchQueue.main.async {
                    self.pickedImages.append(image)
                    
                }
            }
        }
    }
}
解决方案

相册中的视频资源受系统权限保护,不能直接用URL(string:)构造路径,需要通过系统API获取可访问的本地URL,以下是两种可行方法:

方法1:导出视频到临时文件获取URL

通过PHAssetResourceManager将视频导出到App临时目录,得到可用于Firebase上传的URL:

.popupImagePicker(show: $showPicker) { assets in
    let resourceManager = PHAssetResourceManager.default()
    
    DispatchQueue.global(qos: .background).async {
        assets.forEach { asset in
            // 区分图片和视频处理逻辑
            guard asset.mediaType == .video else {
                // 保留你原有的图片处理代码
                let manager = PHCachingImageManager.default()
                let options = PHImageRequestOptions()
                options.isSynchronous = true
                
                manager.requestImage(for: asset, targetSize: .init(), contentMode: .default, options: options) { image, _ in
                    guard let image = image else {return}
                    DispatchQueue.main.async {
                        self.pickedImages.append(image)
                    }
                }
                return
            }
            
            // 获取视频资源对象
            guard let videoResource = PHAssetResource.assetResources(for: asset).first(where: { $0.type == .video }) else { return }
            
            // 创建临时文件路径
            let tempDir = FileManager.default.temporaryDirectory
            let tempVideoURL = tempDir.appendingPathComponent("\(UUID().uuidString).mov")
            
            // 导出视频到临时文件
            let requestOptions = PHAssetResourceRequestOptions()
            requestOptions.isNetworkAccessAllowed = true // 允许从iCloud获取视频
            
            resourceManager.writeData(for: videoResource, toFile: tempVideoURL, options: requestOptions) { error in
                if let error = error {
                    print("视频导出失败:\(error.localizedDescription)")
                    return
                }
                
                // 临时URL可直接用于Firebase上传
                DispatchQueue.main.async {
                    let storageRef = Storage.storage().reference().child("videos/\(UUID().uuidString).mov")
                    let uploadTask = storageRef.putFile(from: tempVideoURL)
                    
                    // 监听上传状态
                    uploadTask.observe(.success) { _ in
                        print("视频上传成功")
                        // 上传完成后删除临时文件
                        try? FileManager.default.removeItem(at: tempVideoURL)
                    }
                    
                    uploadTask.observe(.failure) { snapshot in
                        if let error = snapshot.error as NSError? {
                            print("上传失败:\(error.localizedDescription)")
                        }
                        try? FileManager.default.removeItem(at: tempVideoURL)
                    }
                }
            }
        }
    }
}

方法2:转换为Data直接上传

如果不想处理临时文件,可将视频转为Data,用Firebase的putData方法上传:

.popupImagePicker(show: $showPicker) { assets in
    DispatchQueue.global(qos: .background).async {
        assets.forEach { asset in
            guard asset.mediaType == .video else {
                // 原有图片处理逻辑
                return
            }
            
            let videoOptions = PHVideoRequestOptions()
            videoOptions.isNetworkAccessAllowed = true
            
            PHImageManager.default().requestAVAsset(forVideo: asset, options: videoOptions) { avAsset, _, _ in
                guard let urlAsset = avAsset as? AVURLAsset else { return }
                let videoURL = urlAsset.url
                
                do {
                    let videoData = try Data(contentsOf: videoURL)
                    let storageRef = Storage.storage().reference().child("videos/\(UUID().uuidString).mov")
                    let uploadTask = storageRef.putData(videoData)
                    
                    // 监听上传状态...
                } catch {
                    print("读取视频数据失败:\(error.localizedDescription)")
                }
            }
        }
    }
}

注意事项

  • 确保App已申请相册访问权限,在Info.plist中添加NSPhotoLibraryUsageDescription(读取权限)和NSPhotoLibraryAddUsageDescription(写入权限)。
  • 若视频存储在iCloud,必须设置isNetworkAccessAllowed = true,否则无法获取资源。
  • 临时文件在上传完成后记得删除,避免占用沙盒空间。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 11:10:23