How to Save ReplayKit Video to Camera Roll with In-App Button

前端 未结 4 1867
自闭症患者
自闭症患者 2021-02-04 02:50

I am relatively new to iOS development and Swift but I have an app I\'m working on which is supposed to record the activity on the screen and save the resulting video to the cam

相关标签:
4条回答
  • 2021-02-04 03:32

    I am running into an error, when it hits:

    self.videoWriterInput.markAsFinished();
    

    It is giving me :

    -[AVAssetWriterInput markAsFinished] Cannot call method when status is 0

    0 讨论(0)
  • 2021-02-04 03:40

    I too wanted to do what you have asked, but as of now RPScreenRecorder doesn't provide any of those functionalities.

    0 讨论(0)
  • 2021-02-04 03:44

    As mentioned by Geoff H, Replay Kit 2 now allows you to record the screen and save it either within your app or to the gallery without having to use the preview.

    The documentation is sparse but after some trial and experiment the below code works in iOS 12.

    Note this only captures video and not audio, although that should be straightforward to add, and you may want to add more error checking if using it. The functions below can be triggered by UI buttons, for example.

     @objc func startRecording() {
            //Use ReplayKit to record the screen
    
            //Create the file path to write to
            let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
            self.videoOutputURL = URL(fileURLWithPath: documentsPath.appendingPathComponent("MyVideo.mp4"))
    
            //Check the file does not already exist by deleting it if it does
            do {
                try FileManager.default.removeItem(at: videoOutputURL)
            } catch {}
    
    
            do {
                try videoWriter = AVAssetWriter(outputURL: videoOutputURL, fileType: AVFileType.mp4)
            } catch let writerError as NSError {
                os_log("Error opening video file", writerError);
                videoWriter = nil;
                return;
            }
    
            //Create the video settings
            let videoSettings: [String : Any] = [
                AVVideoCodecKey  : AVVideoCodecType.h264,
                AVVideoWidthKey  : 1920,  //Replace as you need
                AVVideoHeightKey : 1080   //Replace as you need
            ]
    
            //Create the asset writer input object whihc is actually used to write out the video
            //with the video settings we have created
            videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings);
            videoWriter.add(videoWriterInput);
    
            //Tell the screen recorder to start capturing and to call the handler when it has a
            //sample 
            RPScreenRecorder.shared().startCapture(handler: { (cmSampleBuffer, rpSampleType, error) in
    
                guard error == nil else {
                    //Handle error
                    os_log("Error starting capture");
                    return;
                }
    
                switch rpSampleType {
                    case RPSampleBufferType.video:
                        os_log("writing sample....");
                        if self.videoWriter.status == AVAssetWriter.Status.unknown {
    
                            if (( self.videoWriter?.startWriting ) != nil) {
                                os_log("Starting writing");
                                self.videoWriter.startWriting()
                                self.videoWriter.startSession(atSourceTime:  CMSampleBufferGetPresentationTimeStamp(cmSampleBuffer))
                            }
                        }
    
                        if self.videoWriter.status == AVAssetWriter.Status.writing {
                            if (self.videoWriterInput.isReadyForMoreMediaData == true) {
                                os_log("Writting a sample");
                                if  self.videoWriterInput.append(cmSampleBuffer) == false {
                                    print(" we have a problem writing video")
                                }
                            }
                    }
    
                    default:
                        os_log("not a video sample, so ignore");
                }
            } )
        }
    
        @objc func stoprecording() {
            //Stop Recording the screen
            RPScreenRecorder.shared().stopCapture( handler: { (error) in
                os_log("stopping recording");
            })
    
            self.videoWriterInput.markAsFinished();
            self.videoWriter.finishWriting {
                os_log("finished writing video");
    
                //Now save the video
                PHPhotoLibrary.shared().performChanges({
                    PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: self.videoOutputURL)
                }) { saved, error in
                    if saved {
                        let alertController = UIAlertController(title: "Your video was successfully saved", message: nil, preferredStyle: .alert)
                        let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
                        alertController.addAction(defaultAction)
                        self.present(alertController, animated: true, completion: nil)
                    }
                    if error != nil {
                        os_log("Video did not save for some reason", error.debugDescription);
                        debugPrint(error?.localizedDescription ?? "error is nil");
                    }
                }
            }
    
    0 讨论(0)
  • 2021-02-04 03:48

    Yes, you can. Check this ReplayKit2 Swift 4:

    https://medium.com/@giridharvc7/replaykit-screen-recording-8ee9a61dd762

    Once you have the file, it shouldn't be too much trouble to save it to the camera roll with something along the lines of:

    static func saveVideo(url: URL, returnCompletion: @escaping (String?) -> () ) {
    
            DispatchQueue.global(qos: .userInitiated).async { 
    
                guard let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
    
                if !FileManager.default.fileExists(atPath: documentsDirectoryURL.appendingPathComponent(url.lastPathComponent).path) {
    
                    URLSession.shared.downloadTask(with: url) { (location, response, error) -> Void in
    
                        guard let location = location else { return }
    
                        let destinationURL = documentsDirectoryURL.appendingPathComponent(response?.suggestedFilename ?? url.lastPathComponent)
    
                        do {
                            try FileManager.default.moveItem(at: location, to: destinationURL)
                            PHPhotoLibrary.requestAuthorization({ (authorizationStatus: PHAuthorizationStatus) -> Void in
                                if authorizationStatus == .authorized {
                                    PHPhotoLibrary.shared().performChanges({
                                        PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: destinationURL)}) { completed, error in
                                            DispatchQueue.main.async {
                                                if completed {                                                    returnCompletion(url.lastPathComponent)
                                                } else {
                                                    returnCompletion(nil)
                                                }
                                            }
                                    }
                                }
                            })
                            returnCompletion(url.lastPathComponent)
                        } catch {
                            returnCompletion(nil)
                        }
    
                    }.resume()
    
                } else {
                    returnCompletion(nil)
                }
            }
    
        }
    
    0 讨论(0)
提交回复
热议问题