#ios #swift #firebase #firebase-storage
#iOS #swift #firebase #firebase-хранилище
Вопрос:
Среда: Xcode 12.0.1 (Swift 5.x) iOS 13 Firebase 6.34.0 FirebaseFirestore 1.19.0 FirebaseStorage 3.9.1 GoogleDataTransport 7.5.1 PromisesObjC 1.2.11
Проблема: я инициализирую Firebase в приложении iOS и успешно записываю данные базы данных в Cloud FireStore. Затем я загружаю связанный видеофайл в хранилище Firebase с помощью асинхронного вызова.
- Записи в базе данных Cloud Firestore ВСЕГДА работают.
- Используя индекс, сгенерированный при записи в Cloud Firestore, хранилище Firebase затем используется для загрузки видео и файла данных с именами в качестве индекса из (1) выше.
Первая загрузка первого файла всегда работает при запуске нового приложения. Вторая или любая дополнительная загрузка файла завершается ошибкой со следующей ошибкой:
ошибка загрузки видеофайлов в облачном хранилище: ошибка домена = FIRStorageErrorDomain Code =-13000 «Произошла неизвестная ошибка, пожалуйста, проверьте ответ сервера». userInfo={object=PBY7Ost7nPWD8jWWF4qG.mov, ResponseBody= Не удается завершить загрузку. Текущий размер — 1692167. Ожидаемый конечный размер — 1665242., bucket=launch-me-47860.appspot.com , data={длина = 83, байты = 0x43616e20 6e6f7420 66696e61 6c697a65 … 31363635 3234322e }, data_content_type=текст / обычный; кодировка=utf-8, NSLocalizedDescription=Произошла неизвестная ошибка, пожалуйста, проверьте ответ сервера., ResponseErrorDomain=com.google.HttpStatus, ResponseErrorCode = 400}
Я нашел похожие вопросы, опубликованные в 2016 и 2017 годах, но эта проблема с записью в Firebase выглядит иначе, поскольку начальная загрузка всегда работает, а затем при следующей попытке выполнить загрузку происходит сбой с ошибкой.
Я добавил процедуру для повторной попытки загрузки, если первая загрузка завершится неудачно. Все они терпят неудачу. Вот код загрузки:
// MARK: Write file to Firebase Cloud Storage
private func fbCloudFileWrite(indexName: String) {
let fbStorage = Storage.storage()
print("(DEBUG FB) fbCloudFileWrite: upload indexName.csv and indexName.mov")
// now upload file to cloud FireStore
let fbStorageRef = fbStorage.reference()
// Create a reference to the file you want to upload
//let LaunchMeDataRef = fbStorageRef.child("LaunchMe/" indexName ".csv")
//let LaunchMeVideoRef = fbStorageRef.child("LaunchMe/" indexName ".mov")
var LaunchMeDataRef = fbStorageRef.child(indexName ".csv")
var LaunchMeVideoRef = fbStorageRef.child(indexName ".mov")
// Upload the file to the path "images/rivers.jpg"
fbWriteAttempts = 1
DispatchQueue.main.async {
print("(DEBUG FB) ***** write attemp #: (self.fbWriteAttempts)")
if let vURL = self.videoURL, let dURL = self.dataFileURL {
let uploadVideoTask = LaunchMeVideoRef.putFile(from: vURL, metadata: nil) { metadata, err in
if let err = err {
print("(DEBUG FB) cloud storage VIDEO file upload error: (err)")
if self.fbWriteAttempts < 4 {
self.fbCloudFileWrite(indexName: indexName)
}
} else {
print("(DEBUG FB) video uploaded: (indexName)")
let uploadDataTask = LaunchMeDataRef.putFile(from: dURL, metadata: nil) { metadata, err in
if let err = err {
print("(DEBUG FB) cloud storage SENSOR file upload error: (err)")
} else {
print("(DEBUG FB) sensor data uploaded: (indexName)")
print("(DEBUG FB) set newRecording = false to prevent duplicates")
// all files successfully uploaded. Set newRecording to false
self.newRecording = false
}
} // close uploadDataTask
} // close else
} // close let uploadVideoTask
} // close vURL unwrap
else {
print("(DEBUG FB) videoURL could not be unwrapped")
}
} // close Dispatch.main.async
Комментарии:
1. Просто предположение, но это
self.videoURL!
подозрительно. Если формат videoURL искажен, это приведет к этой ошибке, и вам следует безопасно развернуть опции перед их использованием.2. Джей, это отличный момент. В этом случае для воспроизведения видео на экране должен быть действительным видеоролик, поэтому я предполагаю, что он хороший. Это отличный момент, и я его безопасно разверну. Сказав это, загадка в том, что это всегда работает при первом запуске приложения, но никогда при второй записи видео.
3. Обновлен код, чтобы правильно развернуть параметры URL. Проблема не решена. Первые загрузки хранилища всегда работают, а затем последовательные приводят к ошибке, что текущий размер не соответствует ожидаемому размеру. Пример кода был обновлен, чтобы отразить правильное необязательное разворачивание.
4. Хорошие обновления. Итак, скопируйте и вставьте свой код в проект, жестко закодируйте пути к моему хранилищу Firebase и передайте в трех файлах. Все они загружены правильно. Это говорит мне о том, что у вас проблема с путем или что-то еще приводит к неполной загрузке файлов.
5. Спасибо, Джей. Ваша помощь очень ценится, так как это сводит меня с ума. Я изменил свое приложение таким образом, чтобы каждая загрузка в хранилище представляла собой новый файл с filename_1, filename_2 и т.д. Когда я переключаюсь с одного просмотра на другой без записи нового видео, оно всегда загружается. Это соответствует тому, что вы также нашли. Когда я записываю новое видео, я снова получаю сообщение об ошибке.
Ответ №1:
Как ни странно, я смог решить эту проблему, установив переменную URL в пути к локальному каталогу movie в VideoPlayerViewController вместо того, чтобы передавать URL с предыдущего контроллера во время перехода. Для меня не имеет смысла, что это было бы необходимо, за исключением, возможно, некоторого кэширования, которое происходит за кулисами.
Я знаю, что правильный URL-адрес передается, поскольку при его передаче на экране воспроизводится правильное видео, но загрузка хранилища Firebase пытается загрузить предыдущее видео (отсюда и ожидаемая ошибка размера), когда указан тот же URL, который воспроизводил правильное видео.
В контроллере добавлена новая функция, которая устанавливает URL-адрес вместо его передачи (перед выполнением загрузки хранилища Firebase):
private func setVideoStorageURL() {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let path = "output.mov"
videoURL = paths[0].appendingPathComponent(path)
}
в то время как предыдущая реализация, которая не работала, передавала URL-адрес в контроллер:
if let destinationVC = segue.destination as? VideoPlayerViewController {
print("(DEBUG) Setting data to be passed to VideoPlayerViewController")
destinationVC.newRecording = newRecording
//now set newRecording to false if it is true
if newRecording {
newRecording = false
}
destinationVC.audioMode = audioMode
destinationVC.selectedDevice = selectedDevice
destinationVC.videoURL = passFileURL