Cómo iniciar la grabación de pantalla ReplayKit en la class SpriteKit SKScene

He implementado ReplayKit en mi juego SpriteKit , pero como todo se hace dentro del GameViewController el button de grabación aparece demasiado pronto. Vea a GameViewController class de GameViewController :

 class GameViewController: UIViewController, RPPreviewViewControllerDelegate { var videoRecButton: UIButton! var videoRecImage: UIImage! override func viewDidLoad() { super.viewDidLoad() let skView = self.view as? SKView if skView?.scene == nil { skView?.showsFPS = true skView?.showsNodeCount = true skView?.showsPhysics = true skView?.ignoresSiblingOrder = false //starting the game with the Poster Scene let posterScene = PosterScene(size: skView!.bounds.size) posterScene.scaleMode = .aspectFill skView?.presentScene(posterScene) } videoRecButton = UIButton(type: .custom) videoRecImage = UIImage(named:"videoRecButton.png") videoRecButton.frame = CGRect(x:0, y: 0, width: (videoRecImage?.size.width)!, height: (videoRecImage?.size.height)!) videoRecButton.setImage(videoRecImage, for: .normal) videoRecButton.addTarget(self, action:#selector(self.videoRecButtonClicked), for: .touchUpInside) self.view.addSubview(videoRecButton) } func videoRecButtonClicked() { print("Button Clicked") startRecording() } func startRecording() { let recorder = RPScreenRecorder.shanetworking() recorder.startRecording{ [unowned self] (error) in if let unwrappedError = error { print(unwrappedError.localizedDescription) } else { self.videoRecButton.addTarget(self, action:#selector(self.stopRecording), for: .touchUpInside) } } } func stopRecording() { let recorder = RPScreenRecorder.shanetworking() recorder.stopRecording { [unowned self] (preview, error) in self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Start", style: .plain, target: self, action: #selector(self.startRecording)) if let unwrappedPreview = preview { unwrappedPreview.previewControllerDelegate = self self.present(unwrappedPreview, animated: true) } } } func previewControllerDidFinish(_ previewController: RPPreviewViewController) { dismiss(animated: true) } override var shouldAutorotate: Bool { return true } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { if UIDevice.current.userInterfaceIdiom == .phone { return .allButUpsideDown } else { return .all } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Release any cached data, images, etc that aren't in use. } override var prefersStatusBarHidden: Bool { return true } } 
  1. ¿Cómo puedo llamar a las funciones startRecording y stopRecording de una class que henetworkinga de SKScene como class GameScene ?

  2. ¿Cómo puede habilitar, deshabilitar y ocultar el button videoRecButton de la class GameScene ?

ACTUALIZAR

Según una respuesta de crashoverride777 a, coloque el siguiente código en mi class SKScene , pero la pantalla registra solo unos segundos antes de que aparezca el controller de navigation con una vista previa del video grabado. El video grabado es solo una pantalla negra y los botones cancelar y save no responden.

  func startRecording() { let recorder = RPScreenRecorder.shanetworking() if #available(iOS 10.0, *) { recorder.startRecording{ [unowned self] (error) in if let unwrappedError = error { print(unwrappedError.localizedDescription) } else { self.stopRecording() } } } else { // Fallback on earlier versions } } func stopRecording() { let recorder = RPScreenRecorder.shanetworking() recorder.stopRecording { [unowned self] (preview, error) in self.view?.window?.rootViewController?.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Start", style: .plain, target: self, action: #selector(self.startRecording)) if let unwrappedPreview = preview { unwrappedPreview.previewControllerDelegate = self self.view?.window?.rootViewController?.present(unwrappedPreview, animated: true) } } } func previewControllerDidFinish(_ previewController: RPPreviewViewController) { view?.window?.rootViewController?.dismiss(animated: true) } 

Creé un button de logging:

 let videoRecButtonSprite = SKSpriteNode(imageNamed: "videoButton") videoRecButtonSprite.position = CGPoint(x: self.frame.width/15, y: self.frame.height - self.frame.height/12) self.addChild(videoRecButtonSprite) override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for touch: AnyObject in touches { let location = touch.location(in: self) if videoRecButtonSprite.contains(location){ startRecording() } } } 

No debe crear su button en GameViewController, crearlo directamente en su SKScene. No es una buena práctica utilizar el GameViewController para la interfaz de usuario en juegos SpriteKit.

Hay muchos tutoriales sobre cómo crear botones en SpriteKit.

Con respecto a ReplayKit, puedes usarlo directamente en el SKScene que quieras, simplemente toma el código que ya tienes y muévelo a la Escena relevante.

Para presentar el controller de vista previa en un SKScene, puede decir esto

 view?.window?.rootViewController?.present(unwrappedPreview, animated: true) 

También noté que estás presentando el controller View después de que dejas de grabar. ¿Seguro que quieres hacer esto? Por lo general, tiene un button separado en el juego sobre el menu donde puede ver la grabación.

Aquí está el código general. También te recomiendo que eches un vistazo a las manzanas Juego de ejemplo DemoBots.

Personalmente utilizo una class de Singleton para la grabación del administrador, de esta manera es más fácil para el administrador llamar a todos los methods en caso de que lo necesites para diferentes escenas. Para comenzar la class, crate un nuevo file rápido y agrega este código.

  class ScreenRecoder: NSObject { /// Shanetworking instance static let shanetworking = ScreenRecorder() /// Preview controller var previewController: RPPreviewViewController? /// Private singleton init private override init() { } } 

Para comenzar a grabar, agregue este método a la class ScreenRecorder.

 func start() { let shanetworkingRecorder = RPScreenRecorder.shanetworking() // Do nothing if screen recording is not available guard shanetworkingRecorder.isAvailable else { return } // Stop previous recording if necessary if shanetworkingRecorder.isRecording { stopScreenRecording() } print("Starting screen recording") // Register as the recorder's delegate to handle errors. shanetworkingRecorder.delegate = self // Start recording if #available(iOS 10.0, *) { #if os(iOS) shanetworkingRecorder.isMicrophoneEnabled = true //shanetworkingRecorder.isCameraEnabled = true // fixme #endif shanetworkingRecorder.startRecording { [unowned self] error in if let error = error as? NSError, error.code != RPRecordingErrorCode.userDeclined.rawValue { print(error.localizedDescription) // Show alert return } } } else { // Fallback on earlier versions shanetworkingRecorder.startRecording(withMicrophoneEnabled: true) { error in if let error = error as? NSError, error.code != RPRecordingErrorCode.userDeclined.rawValue { print(error.localizedDescription) // Show alert return } } } } 

Para detener la grabación, llame a esto. Notará que aún no estoy mostrando la vista previa, simplemente la estoy almacenando para su uso posterior. Esta es la forma habitual en que lo haces.

  func stop() { let shanetworkingRecorder = RPScreenRecorder.shanetworking() // Do nothing if screen recording is not available guard shanetworkingRecorder.isAvailable else { return } // Stop recording shanetworkingRecorder.stopRecording { [unowned self] (previewViewController, error) in if let error = error { // If an error has occurnetworking, display an alert to the user. print(error.localizedDescription) // Show alert return } print("Stop screen recording") if let previewViewController = previewViewController { // Set delegate to handle view controller dismissal. previewViewController.previewControllerDelegate = self /* Keep a reference to the `previewViewController` to present when the user presses on preview button. */ self.previewViewController = previewViewController } } } 

Que cree 2 extensiones en la class ScreenRecorder conforme a los delegates de ReplayKit.

El delegado del controller de vista previa

  /// RPPreviewViewControllerDelegate extension ScreenRecorder: RPPreviewViewControllerDelegate { /// Preview controller did finish func previewControllerDidFinish(_ previewController: RPPreviewViewController) { previewController.dismiss(animated: true, completion: nil) } } 

y el delegado de grabación

 extension ScreenRecorder: RPScreenRecorderDelegate { /// Screen recoder did stop with error func screenRecorder(_ screenRecorder: RPScreenRecorder, didStopRecordingWithError error: Error, previewViewController: RPPreviewViewController?) { // Display the error the user to alert them that the recording failed. let error = error as NSError if error.code != RPRecordingErrorCode.userDeclined.rawValue { print(message: error.localizedDescription) // show alert } // Hold onto a reference of the `previewViewController` if not nil. if let previewViewController = previewViewController { self.previewViewController = previewViewController } } /// Screen recoder did change availability func screenRecorderDidChangeAvailability(_ screenRecorder: RPScreenRecorder) { // eg update your button UI etc // you can use something like delegation to pass something to your SKScenes } } 

Y, finalmente, crear un método para presentar la vista previa. Preferiblemente llama a esto a través de un button en su juego sobre el menu.

 func showPreview() { guard let previewViewController = previewViewController else { return } print("Showing screen recording preview") // `RPPreviewViewController` only supports full screen modal presentation. previewViewController.modalPresentationStyle = .fullScreen let rootViewController = UIApplication.shanetworking.keyWindow?.rootViewController rootViewController?.present(previewViewController, animated: true, completion:nil) } 

Ahora puedes llamar a los methods donde quieras en tu proyecto

 ScreenRecorder.shanetworking.start() ScreenRecorder.shanetworking.stop() ScreenRecorder.shanetworking.showPreview() // call stop before calling this 

Este código está prácticamente fuera de DemoBots.

Creo que la mejor manera de manejar la grabación de pantalla es creando un button de grabación automática en tu menu principal. Use UserDefaults para save el estado de encendido / apagado. Si está encendido, usted llama a inicioRecordar cuando comienza su juego, y la llamada deja de grabar cuando termina su juego. Que muestres un button de vista previa en tu juego sobre el menu para ver la grabación si el usuario lo desea.

Espero que esto ayude

DemoBots es difícil. Recuerde importar ReplayKit, RPPreviewViewControllerDelegate, RPScreenRecorderDelegate. ¿Puede publicar su código final en GitHub o algo así, crashoverride777. Esto es lo que escribí y no puedo get la vista previa:

 func startRecording() { let shanetworkingRecorder = RPScreenRecorder.shanetworking() // Do nothing if screen recording is not available guard shanetworkingRecorder.isAvailable else { return } // Stop previous recording if necessary if shanetworkingRecorder.isRecording { stopScreenRecording() } print("Starting screen recording") // Register as the recorder's delegate to handle errors. shanetworkingRecorder.delegate = self // Start recording shanetworkingRecorder.isMicrophoneEnabled = true //shanetworkingRecorder.isCameraEnabled = true // fixme shanetworkingRecorder.startRecording { error in if let error = error as NSError?, error.code != RPRecordingErrorCode.userDeclined.rawValue { print(error.localizedDescription) // Show alert return } } } func stopScreenRecording() { let shanetworkingRecorder = RPScreenRecorder.shanetworking() // Do nothing if screen recording is not available guard shanetworkingRecorder.isAvailable else { return } // Stop recording shanetworkingRecorder.stopRecording { [unowned self] (previewViewController, error) in if let error = error { // If an error has occurnetworking, display an alert to the user. print(error.localizedDescription) // Show alert return } print("Stop screen recording") if let previewViewController = previewViewController { // Set delegate to handle view controller dismissal. previewViewController.previewControllerDelegate = self /* Keep a reference to the `previewViewController` to present when the user presses on preview button. */ self.previewController = previewViewController } } } func previewControllerDidFinish(_ previewController: RPPreviewViewController) { view?.window?.rootViewController?.dismiss(animated: true) }