从库中选择时,视频上传错误

时间:2019-07-05 21:48:27

标签: ios swift iphone firebase firebase-storage

我正在尝试将视频从我的媒体库上传到应用程序中的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}

有没有办法解决这个问题?

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
        }
    }
}