SwiftUI通过UIImagePickerController上传视频到Firebase Storage报-13000错
SwiftUI项目上传视频到Firebase Storage报错-13000解决方案
问题描述
在SwiftUI项目中实现选中视频后上传到Firebase Storage的功能,核心实现代码如下:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { guard let uid = Firebase.Auth.auth().currentUser?.uid else {return} let ref = Storage.storage().reference(withPath: uid) if let url = info[.mediaURL] as? URL { ref.putFile(from: url, metadata: nil) { metadata, error in if error != nil{ print(error) return }else{ print("Succes") } } } picker.dismiss(animated: true) }
运行代码执行上传时,抛出如下错误:
Error Domain=FIRStorageErrorDomain Code=-13000 "发生未知错误,请检查服务端返回结果"
错误附带信息:
- 存储桶:skidays-d2cc1.appspot.com
- 失败任务类型:后台上传任务
- 错误域:NSURLErrorDomain
- 对应请求地址:Firebase Storage分块上传接口
- 响应错误码:-1
核心诱因
这个错误90%以上的场景是代码逻辑问题导致的:
- 发起
putFile上传请求后,代码立刻执行了picker.dismiss关闭图片选择器。UIImagePickerController返回的mediaURL是临时目录下的文件URL,选择器被销毁后系统会自动回收该临时路径下的文件,Firebase的后台上传任务还没来得及读取文件内容,源文件就已经被删除,直接触发上传失败。 - 剩余小概率诱因包括:Firebase Storage安全规则未给当前登录用户开放对应路径的写入权限、测试网络拦截了Firebase存储请求、Info.plist未配置必要的网络访问权限。
修复方案
- 调整代码执行逻辑,不要在发起上传后立刻关闭选择器,先将选择器返回的临时视频文件拷贝到应用沙盒的持久化临时路径,再用沙盒内的文件URL发起上传,等上传回调触发后再关闭选择器、清理临时文件。
修复后的代码参考:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { // 未登录状态直接关闭选择器 guard let uid = Auth.auth().currentUser?.uid else { picker.dismiss(animated: true) return } // 未获取到媒体URL直接关闭选择器 guard let mediaURL = info[.mediaURL] as? URL else { picker.dismiss(animated: true) return } // 生成沙盒内的持久化临时路径 let sandboxTempURL = FileManager.default.temporaryDirectory .appendingPathComponent(UUID().uuidString) .appendingPathExtension("mov") do { // 路径下存在旧文件先删除 if FileManager.default.fileExists(atPath: sandboxTempURL.path) { try FileManager.default.removeItem(at: sandboxTempURL) } // 将选择器返回的临时文件拷贝到沙盒路径 try FileManager.default.copyItem(at: mediaURL, to: sandboxTempURL) // 按用户uid+文件名生成存储路径,避免同一路径文件覆盖 let storageRef = Storage.storage().reference() .child(uid) .child(sandboxTempURL.lastPathComponent) // 用沙盒路径发起上传 storageRef.putFile(from: sandboxTempURL, metadata: nil) { [weak self] _, error in // 无论上传成功失败,最后都关闭选择器、清理沙盒临时文件 defer { picker.dismiss(animated: true) try? FileManager.default.removeItem(at: sandboxTempURL) } if let error = error { print("上传失败:\(error.localizedDescription)") return } print("上传成功") } } catch { print("文件预处理失败:\(error.localizedDescription)") picker.dismiss(animated: true) } }
- 检查Firebase Storage安全规则,确认当前登录用户有目标路径的写入权限,测试阶段可以先用如下规则验证逻辑是否正常:
rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /{userId}/{allPaths=**} { allow read, write: if request.auth != null && request.auth.uid == userId; } } }
- 确认测试设备网络可以正常访问Firebase服务,Info.plist中已配置网络访问权限,没有代理、防火墙拦截存储接口请求。
内容的提问来源于stack exchange,提问作者Michał Michalik
相关产品推荐
相关产品推荐

