fix(ios): call PictureInPicture callbacks with native controls (#3603)

* fix(ios): call PictureInPictureStatusChanged callback with native controls

We add RCTPlayerObserver as playerViewController delegate to be notified with PiP lifecycle
should partially fix #3602

* fix(ios): call onRestoreUserInterfaceForPictureInPictureStop callback with native controls

should partially fix #3602
This commit is contained in:
Gaëtan Kueny 2024-04-04 15:08:48 +02:00 committed by GitHub
parent 2a858df8bc
commit 051e884c8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 55 additions and 2 deletions

View File

@ -27,11 +27,14 @@ protocol RCTPlayerObserverHandler: RCTPlayerObserverHandlerObjc {
func handleViewControllerOverlayViewFrameChange(overlayView: UIView, change: NSKeyValueObservedChange<CGRect>)
func handleTracksChange(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<[AVPlayerItemTrack]>)
func handleLegibleOutput(strings: [NSAttributedString])
func handlePictureInPictureEnter()
func handlePictureInPictureExit()
func handleRestoreUserInterfaceForPictureInPictureStop()
}
// MARK: - RCTPlayerObserver
class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate, AVPlayerItemLegibleOutputPushDelegate {
class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate, AVPlayerItemLegibleOutputPushDelegate, AVPlayerViewControllerDelegate {
weak var _handlers: RCTPlayerObserverHandler?
var player: AVPlayer? {
@ -105,6 +108,7 @@ class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate, AVPla
private var _playerLayerReadyForDisplayObserver: NSKeyValueObservation?
private var _playerViewControllerOverlayFrameObserver: NSKeyValueObservation?
private var _playerTracksObserver: NSKeyValueObservation?
private var _restoreUserInterfaceForPIPStopCompletionHandler: ((Bool) -> Void)?
deinit {
if let _handlers {
@ -192,11 +196,14 @@ class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate, AVPla
options: [.new, .old],
changeHandler: _handlers.handleViewControllerOverlayViewFrameChange
)
playerViewController.delegate = self
}
func removePlayerViewControllerObservers() {
_playerViewControllerReadyForDisplayObserver?.invalidate()
_playerViewControllerOverlayFrameObserver?.invalidate()
playerViewController?.delegate = nil
}
func addPlayerLayerObserver() {
@ -288,4 +295,34 @@ class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate, AVPla
NotificationCenter.default.removeObserver(_handlers)
}
}
func playerViewControllerDidStartPictureInPicture(_: AVPlayerViewController) {
guard let _handlers else { return }
_handlers.handlePictureInPictureEnter()
}
func playerViewControllerDidStopPictureInPicture(_: AVPlayerViewController) {
guard let _handlers else { return }
_handlers.handlePictureInPictureExit()
}
func playerViewController(
_: AVPlayerViewController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
guard let _handlers else { return }
_handlers.handleRestoreUserInterfaceForPictureInPictureStop()
_restoreUserInterfaceForPIPStopCompletionHandler = completionHandler
}
func setRestoreUserInterfaceForPIPStopCompletionHandler(_ restore: Bool) {
guard let _restoreUserInterfaceForPIPStopCompletionHandler else { return }
_restoreUserInterfaceForPIPStopCompletionHandler(restore)
self._restoreUserInterfaceForPIPStopCompletionHandler = nil
}
}

View File

@ -128,6 +128,18 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
onPictureInPictureStatusChanged?(["isActive": NSNumber(value: false)])
}
func handlePictureInPictureEnter() {
onPictureInPictureStatusChanged?(["isActive": NSNumber(value: true)])
}
func handlePictureInPictureExit() {
onPictureInPictureStatusChanged?(["isActive": NSNumber(value: false)])
}
func handleRestoreUserInterfaceForPictureInPictureStop() {
onRestoreUserInterfaceForPictureInPictureStop?([:])
}
func isPipEnabled() -> Bool {
return _pictureInPictureEnabled
}
@ -606,7 +618,11 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
@objc
func setRestoreUserInterfaceForPIPStopCompletionHandler(_ restore: Bool) {
#if os(iOS)
if _pip != nil {
_pip?.setRestoreUserInterfaceForPIPStopCompletionHandler(restore)
} else {
_playerObserver.setRestoreUserInterfaceForPIPStopCompletionHandler(restore)
}
#endif
}