我正在尝试将视频从我的媒体库上传到应用程序中的Firebase存储,但似乎导致错误。如果已使用UIImagePicker捕获了视频,则不会发生这种情况,仅当用户选择了已经拍摄的视频时才发生。我正在使用XCode 11.0 beta (11M336w)
和iOS 13 beta 3
。
我的ImagePicker类:
import UIKit
import AVFoundation
import CropViewController
public protocol ImagePickerDelegate: class {
func didSelect(image: UIImage?)
func didSelect(fileUrl: URL)
}
open class ImagePicker: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate, CropViewControllerDelegate {
private let pickerController: UIImagePickerController
private weak var presentationController: UIViewController?
private weak var delegate: ImagePickerDelegate?
private var editing = false
private var croppingStyle: CropViewCroppingStyle!
public init(presentationController: UIViewController, delegate: ImagePickerDelegate, editing: Bool, croppingStyle: CropViewCroppingStyle, mediaTypes: [String]?) {
self.pickerController = UIImagePickerController()
super.init()
self.presentationController = presentationController
self.delegate = delegate
self.pickerController.delegate = self
self.editing = editing
self.croppingStyle = croppingStyle
if let mediaTypes = mediaTypes {
self.pickerController.mediaTypes = mediaTypes
} else if let mediaTypes = UIImagePickerController.availableMediaTypes(for: .camera) {
self.pickerController.mediaTypes = mediaTypes
}
self.pickerController.sourceType = .camera
self.pickerController.showsCameraControls = true
self.pickerController.videoQuality = .typeHigh
self.pickerController.navigationBar.titleTextAttributes = nil
self.pickerController.navigationItem.rightBarButtonItem?.setTitleTextAttributes(nil, for: .normal)
self.pickerController.navigationItem.rightBarButtonItem?.setTitleTextAttributes(nil, for: .highlighted)
}
private func action(for type: UIImagePickerController.SourceType, title: String) -> UIAlertAction? {
guard UIImagePickerController.isSourceTypeAvailable(type) else {
return nil
}
return UIAlertAction(title: title, style: .default) { [unowned self] _ in
self.pickerController.sourceType = type
self.presentationController?.present(self.pickerController, animated: true)
}
}
public func present(from sourceView: UIView) {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
if let action = self.action(for: .camera, title: "Take photo or video") {
alertController.addAction(action)
}
if let action = self.action(for: .photoLibrary, title: "Choose from library") {
alertController.addAction(action)
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
cancel.setValue(UIColor.red, forKey: "titleTextColor")
alertController.addAction(cancel)
if UIDevice.current.userInterfaceIdiom == .pad {
alertController.popoverPresentationController?.sourceView = sourceView
alertController.popoverPresentationController?.sourceRect = sourceView.bounds
alertController.popoverPresentationController?.permittedArrowDirections = [.down, .up]
}
self.presentationController?.present(alertController, animated: true)
}
private func pickerController(_ controller: UIImagePickerController, didSelect image: UIImage?) {
self.delegate?.didSelect(image: image)
controller.dismiss(animated: true, completion: nil)
}
private func pickerController(_ controller: UIImagePickerController, didSelectVideo videoUrl: URL) {
self.delegate?.didSelect(fileUrl: videoUrl)
controller.dismiss(animated: true, completion: nil)
}
public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
self.pickerController(picker, didSelect: nil)
}
var picker: UIImagePickerController!
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let videoUrl = info[.mediaURL] as? URL {
self.pickerController(picker, didSelectVideo: videoUrl)
return
}
if let image = info[.originalImage] as? UIImage {
if editing {
let cropViewController = CropViewController(croppingStyle: croppingStyle, image: image)
cropViewController.delegate = self
self.picker = picker
self.presentationController?.present(cropViewController, animated: true, completion: nil)
} else {
self.pickerController(picker, didSelect: image)
}
} else {
self.pickerController(picker, didSelect: nil)
}
}
public func cropViewController(_ cropViewController: CropViewController, didCropToImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
self.pickerController(picker, didSelect: image)
}
}
我在UITableView类中为viewcontroller提供了以下功能(当按下按钮时才调用此功能):
func choose() {
let imagePicker = ImagePicker(presentationController: self, delegate: self, editing: false, croppingStyle: .default, mediaTypes: nil)
imagePicker.present(from: view)
}
然后在图像选择器委托中,我使用以下代码:
func didSelect(image: UIImage?) {
//
}
func didSelect(fileUrl: URL) {
let uuid = NSUUID().uuidString
let path = uuid + "." + fileUrl.pathExtension
let uploadTask = Storage.storage().reference(withPath: "message_videos/\(path)").putFile(from: fileUrl, metadata: nil) { (metadata, error) in
if let error = error {
print(error)
return
}
print("success!")
}
}
执行后,将导致以下控制台打印:
2019-07-05 23:41:31.967623+0200 APPLICATION_NAME[9491:1007368] Failed to issue sandbox extension for file file:///private/var/mobile/Containers/Data/PluginKitPlugin/8B54AF9B-6618-4341-85DE-2EAC29198B17/tmp/trim.FEF41C1D-7D43-4E95-84A1-36AC99FEDE14.MOV, errno = 1
2019-07-05 23:41:31.982082+0200 APPLICATION_NAME[9491:1007368] Task <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1> finished with error [-1] Error Domain=NSURLErrorDomain Code=-1 "unknown error" UserInfo={NSErrorFailingURLStringKey=https://firebasestorage.googleapis.com/v0/b/XXXXXXXXXXXXXXXXXXXXXXX.appspot.com/o/message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV?uploadType=resumable&name=message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV&upload_id=AEnB2UqDOZNKSdC1TCdzQB4OV3ZS74snMqsQ4tPZRZy3iYUjO47TrpnMOrDz6HUq-_KFRAdfqhahEJsefrXe_N8T-jF8MS05cA&upload_protocol=resumable, NSErrorFailingURLKey=https://firebasestorage.googleapis.com/v0/b/XXXXXXXXXXXXXXXXXXXXXXX.appspot.com/o/message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV?uploadType=resumable&name=message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV&upload_id=AEnB2UqDOZNKSdC1TCdzQB4OV3ZS74snMqsQ4tPZRZy3iYUjO47TrpnMOrDz6HUq-_KFRAdfqhahEJsefrXe_N8T-jF8MS05cA&upload_protocol=resumable, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundUploadTask <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1>"
), _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundUploadTask <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1>, NSLocalizedDescription=unknown error}
Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, please check the server response." UserInfo={bucket=XXXXXXXXXXXXXXXXXXXXXXX.appspot.com, _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundUploadTask <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1>, object=message_videos/BB2CB773-982B-4800-9398-B2F96ED91B6D.MOV, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundUploadTask <D08D778E-B5DD-4182-9FFE-69E892DA8EDE>.<1>"
), NSLocalizedDescription=An unknown error occurred, please check the server response., ResponseErrorDomain=NSURLErrorDomain, NSErrorFailingURLStringKey=https://firebasestorage.googleapis.com/v0/b/XXXXXXXXXXXXXXXXXXXXXXX.appspot.com/o/message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV?uploadType=resumable&name=message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV&upload_id=AEnB2UqDOZNKSdC1TCdzQB4OV3ZS74snMqsQ4tPZRZy3iYUjO47TrpnMOrDz6HUq-_KFRAdfqhahEJsefrXe_N8T-jF8MS05cA&upload_protocol=resumable, NSErrorFailingURLKey=https://firebasestorage.googleapis.com/v0/b/XXXXXXXXXXXXXXXXXXXXXXX.appspot.com/o/message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV?uploadType=resumable&name=message_videos%2FBB2CB773-982B-4800-9398-B2F96ED91B6D.MOV&upload_id=AEnB2UqDOZNKSdC1TCdzQB4OV3ZS74snMqsQ4tPZRZy3iYUjO47TrpnMOrDz6HUq-_KFRAdfqhahEJsefrXe_N8T-jF8MS05cA&upload_protocol=resumable, ResponseErrorCode=-1}
有没有办法解决这个问题?
答案 0 :(得分:1)
因此,我可以通过将视频转换为Data
并使用Firebase Storage API中的putData
函数上传视频来解决此问题。
我不确定为什么在iOS 13上需要进行此更改,但是我希望这会有所帮助。
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//ensure user picked a video and you have the URL
guard let mediaType = info[.mediaType] as? String, mediaType == "public.movie", let movieURL = info[.mediaURL] as? URL else {
dismiss(animated: true)
return
}
uploadVideo(url: movieURL)
//continue code your here...
}
private func uploadVideo(url: URL) {
do {
//convert video to Data
let videoData = try Data(contentsOf: movieURL)
//build storage "path"
let uniqueID = UUID().uuidString
let path = "message_videos/" + uniqueID
let storageRef = Storage.storage().reference().child(path)
//use metadata to specify it's a video
let uploadMetadata = StorageMetadata()
uploadMetadata.contentType = "video/quicktime"
//upload via putData
let uploadTask = storageRef.putData(videoData, metadata: uploadMetadata) { (metadata, error) in
if let error = error {
//handle upload error
} else {
//successful upload
}
} catch {
//handle video -> Data error
}
}
}