iosswiftiphoneswiftuinotificationcenter

Swift / SwiftUI - Executing a function before the device locks / is put in the background?


I am working on an app that records video segments (see Instagram's reels for reference), and I'm currently in the process of handling states when the application moves to the background / screen is locked.

The current issue I have is that if I move the app to the background / lock the screen DURING an on-going video recording the AVCaptureFileOutputRecordingDelegate's fileOutput method fails to save the video. I have tried adding 'required background modes' in the .plist, and I've also stumbled upon the following thread and now I am unsure of wether or not it is possible to actually save a on-going video recording when the app moves to the background, as well as if it's a good idea to do so at all if you want to adhere to privacy guidelines.

I'm wondering if there is a way to delay an app being moved to the background so that I can execute the methods that I would normally use to stop and save a video recording before the device ends up in the background (which ultimately fails the process of saving the video for me).

Note: Putting my method for saving / stopping the on-going video recording in the following observation does NOT work, it will fail as described above:

.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
                print("Moving to the background!")
            toggleRecording() <--- this normally stops and saves the recording but it fails here.
            }

Thankful for any input that can be provided!


Solution

  • The following code solved the issue in my particular case:

    When the app is put in to the background the AVCaptureFileOutputRecordingDelegate is called and the error inevitably occurs. If that happens I tell the app to look for any recorded data from the url (var activeRecordingUrl: URL?) that I generate/update when starting a recording. If there was data found (which always seem to be the case for me) I store it like I would as if the recording had been "manually" stopped by the user from the UI.

    
    extension CameraViewController: AVCaptureFileOutputRecordingDelegate {
        func fileOutput(
            _ output: AVCaptureFileOutput,
            didFinishRecordingTo outputFileURL: URL,
            from connections: [AVCaptureConnection],
            error: Error?
        ) {
            guard error == nil else {
                // --------- Start of fix ---------
                NSLog("> ERROR: Recording was interrupted: \(String(describing: error?.localizedDescription)), attempting to salvage record data from activeRecordingUrl.")
    
                
                guard let outputUrl = activeRecordingUrl else {
                    NSLog("> ERROR: found nil when unwrapping activeRecordingUrl.")
                    onRecordingFinished(false)
                    return
                }
                
                recordings.append(VideoSegment(avAssetUrl: outputUrl, cameraPosition: sessionInput.device.position, avAsset: AVAsset(url: outputUrl)))
                NSLog("Found record data from the session that was interrupted.")
                
                onRecordingFinished(true)
                // --------- End of fix ---------
                return
            }
    
            recordings.append(VideoSegment(
                avAssetUrl: outputFileURL,
                cameraPosition: sessionInput.device.position,
                avAsset: AVAsset(url: outputFileURL
            )))
    
            onRecordingFinished(true)
        }
    }