0

I have a video sharing app, and when you save a video to firebase storage it works perfectly for videos that are roughly 1 minute or shorter.

The problem that I am having, is when I try to post a longer video (1 min or greater) it never saves to firebase.

The only thing that I can think of is this error that I am getting, and this error only shows up about 30 seconds after I click the save button:

[BackgroundTask] Background Task 101 ("GTMSessionFetcher-firebasestorage.googleapis.com"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this.

Here is my code to save the video to firebase.

func saveMovie(path: String, file: String, url: URL) {
    var backgroundTaskID: UIBackgroundTaskIdentifier?
    // Perform the task on a background queue.
    DispatchQueue.global().async {
        // Request the task asseration and save the ID
        backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "Finish doing this task", expirationHandler: {
            // End the task if time expires
            UIApplication.shared.endBackgroundTask(backgroundTaskID!)
            backgroundTaskID = UIBackgroundTaskIdentifier.invalid
        })
        // Send the data synchronously
        do {
            let movieData = try Data(contentsOf: url)
            self.storage.child(path).child("\(file).m4v").putData(movieData)
        } catch let error {
            fatalError("Error saving movie in saveMovie func. \(error.localizedDescription)")
        }
        //End the task assertion
        UIApplication.shared.endBackgroundTask(backgroundTaskID!)
        backgroundTaskID = UIBackgroundTaskIdentifier.invalid
    }
}

Any suggestions on how I can allow my video time to upload?

Trev347
  • 318
  • 1
  • 12
  • I don't see how Firebase Storage is involved in your code. – El Tomato Dec 04 '21 at 00:48
  • @ElTomato "firebasestorage.googleapis.com" and "`storage.child(path).child("\(file).m4v").putData(movieData)`" both point to Firebase Storage. – Frank van Puffelen Dec 04 '21 at 00:52
  • @FrankvanPuffelen Okay, thanks. But where does a guy named 'storage' come from? – El Tomato Dec 04 '21 at 01:10
  • @ElTomato Sorry I made my functions kind of confusing cause i'm a newbie. But storage is just a variable at the top that equals `Storage.storage().reference()` – Trev347 Dec 04 '21 at 01:11
  • 1
    Why are you doing this `DispatchQueue.global().async` as Firebase functions are asynchronous. But then you have this `// Send the data synchronously` but again, Firebase functions are *asynchronous*. Last question: Since you know the file path, why cast to Data when you can just [Upload The File](https://firebase.google.com/docs/storage/ios/upload-files#upload_from_a_local_file) directly with `.putFile`? Oh - for your UI, you can [Monitor Progress](https://firebase.google.com/docs/storage/ios/upload-files#monitor_upload_progress) for progress bar if needed – Jay Dec 05 '21 at 14:59
  • @Jay thanks for your response that was super helpful! I have updated my question and I am now wondering if you have any idea how to solve the new problem I am having? Thanks again Jay! – Trev347 Dec 09 '21 at 14:31

1 Answers1

0

Finally figured this out after a long time...

All you have to do is use .putFile("FileURL") instead of .putdata("Data"). Firebase documentation says you should use putFile() instead of putData() when uploading large files.

But the hard part is for some reason you can't directly upload the movie URL that you get from the didFinishPickingMediaWithInfo function and firebase will just give you an error. So what I did instead was get the data of the movie, save the movie data to a path in the file manager, and use the file manager path URL to upload directly to firebase which worked for me.

            //Save movie to Firestore
        do {
            // Convert movie to Data.
            let movieData = try Data(contentsOf: movie)
            // Get path so we can save movieData into fileManager and upload to firebase because movie URL does not work, but fileManager url does work.
            guard let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent(postId!) else { print("Error saving to file manager in addPost func"); return }
            do {
                try movieData.write(to: path)
                // Save the file manager url file to firebase storage
                Storage.storage().reference().child("Videos").child("\(postId!).m4v").putFile(from: path, metadata: nil) { metadata, error in
                    if let error = error {
                        print("There was an error \(error.localizedDescription)")
                    } else {
                        print("Video successfully uploaded.")
                    }
                    // Delete video from filemanager because it would take up too much space to save all videos to file manager.
                    do {
                        try FileManager.default.removeItem(atPath: path.path)
                    } catch let error {
                        print("Error deleting from file manager in addPost func \(error.localizedDescription)")
                    }
                }
            } catch let error {
                print("Error writing movieData to firebase \(error.localizedDescription)")
            }
        } catch let error {
            print("There was an error adding video in addPost func \(error.localizedDescription)")
        }
Trev347
  • 318
  • 1
  • 12