feat: enhance react-native-video plugins [Plugins API Breaking] (#4366)

* feat: allow plugins for providing custom DRM manager

This will allow plugins to provide DRM manger to create custom implementations, eg. using SKD from DRM providers

* chore(example): fix drm example on android

* chore: lint code

* fix: remove platform player logic & dependency from `RNVPlugin`

* chore: change warning to debug msg

* chore: lint code

* chore(example/bare): update Podfile.lock

* refactor: reorganize ReactNativeVideoManager plugin registration methods

* refactor: add helpers & clean code

* docs: update documentation

* lint code

* add comment

* docs: update plugins section
This commit is contained in:
Krzysztof Moch
2025-03-12 14:13:46 +01:00
committed by GitHub
parent b5103743e8
commit 6e6f91517c
18 changed files with 600 additions and 151 deletions
+27 -27
View File
@@ -1024,7 +1024,7 @@ PODS:
- React-jsi (= 0.73.2)
- React-logger (= 0.73.2)
- React-perflogger (= 0.73.2)
- ReactNativeHost (0.5.0):
- ReactNativeHost (0.5.3):
- glog
- RCT-Folly (= 2022.05.16.00)
- React-Core
@@ -1213,43 +1213,43 @@ SPEC CHECKSUMS:
FBReactNativeSpec: 86de768f89901ef6ed3207cd686362189d64ac88
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0
RCT-Folly: cd21f1661364f975ae76b3308167ad66b09f53f5
RCTRequired: 9b1e7e262745fb671e33c51c1078d093bd30e322
RCTTypeSafety: a759e3b086eccf3e2cbf2493d22f28e082f958e6
React: 805f5dd55bbdb92c36b4914c64aaae4c97d358dc
React-callinvoker: 6a697867607c990c2c2c085296ee32cfb5e47c01
React-Codegen: 39377d8c90c3fc0792753c9af53b788abfe5850b
React-Core: 943d6097aaf381b1e7c7e105eecd5a27b51c4e17
React-CoreModules: 710e7c557a1a8180bd1645f5b4bf79f4bd3f5417
React-cxxreact: 0f0b3933c36dfe4ed10638a33398533f90ab78d3
React-Codegen: ea685412377744d2e2108adb131fce2f040ddd14
React-Core: d9a7e296b2e7b57f27d81b62a7d293d06527268a
React-CoreModules: 399f72f0892befe0fde5d415703c0b9b356762e7
React-cxxreact: beb7cb8adddd4b25d4262f55927dcd1d3577e99d
React-debug: f1637bce73342b2f6eee4982508fdfb088667a87
React-Fabric: ba7d74992ed878fdbf91f8b49eb725b310786980
React-FabricImage: e7457fb89db50cb1b51d0546b5ff002b91026efe
React-graphics: dd5af9d8b1b45171fd6933e19fed522f373bcb10
React-ImageManager: c5b7db131eff71443d7f3a8d686fd841d18befd3
React-Fabric: cb2eba1fd764229f9a5737fa7b339695d4949848
React-FabricImage: b86bf7e1c6560bf82ade361dac6f3281e68453ee
React-graphics: 87ba141b72379824c7835224c1a87993683151a8
React-ImageManager: 1bc92d558d4d5de07c6c1a7244d33ad2a872728e
React-jsc: 94234736a90ea29f017f2ee76e5f358a6ba076a9
React-jserrorhandler: 97a6a12e2344c3c4fdd7ba1edefb005215c732f8
React-jsi: 0cd661b6ea862c104706311f8265050ee3ecf5e4
React-jsiexecutor: 94f6026bc4054b413f0ac5e210691c2916d99d1b
React-jserrorhandler: 0b1476485be6d79f09a8f0548c355b1cc14e8f21
React-jsi: dbfd3bab7712367d4c2aced271d794dde76f0d68
React-jsiexecutor: 368e562638c31174479c00434d37fd67b761c15b
React-jsinspector: 03644c063fc3621c9a4e8bf263a8150909129618
React-logger: 66b168e2b2bee57bd8ce9e69f739d805732a5570
React-Mapbuffer: 9ee041e1d7be96da6d76a251f92e72b711c651d6
react-native-video: 6e6a4c453879c646d8a2e5c16ff0903af33daadd
React-nativeconfig: d753fbbc8cecc8ae413d615599ac378bbf6999bb
React-NativeModulesApple: 22c25a1baa4b0d0d4845dad2578fc017b0805589
React-NativeModulesApple: 0c22e17930a2de06bbd4d49a149351a5151283dc
React-perflogger: 29efe63b7ef5fbaaa50ef6eaa92482f98a24b97e
React-RCTActionSheet: 69134c62aefd362027b20da01cd5d14ffd39db3f
React-RCTAnimation: 3b5a57087c7a5e727855b803d643ac1d445488f5
React-RCTAppDelegate: 842870b97f47de7255908ba1ca8786aef877b0b8
React-RCTBlob: 1fa011b5860c9a70802fab986ad334b458387b7a
React-RCTFabric: c8f86a85501d70c8a77d71f22273e325ffb63fa0
React-RCTImage: 27b27f4663df9e776d0549ed2f3536213e793f1b
React-RCTLinking: 962880ce9d0e2ea83fd182953538fc4ed757d4da
React-RCTNetwork: 73a756b44d4ad584bae13a5f1484e3ce12accac8
React-RCTSettings: 6d7f8d807f05de3d01cfb182d14e5f400716faac
React-RCTText: 73006e95ca359595c2510c1c0114027c85a6ddd3
React-RCTVibration: 599f427f9cbdd9c4bf38959ca020e8fef0717211
React-rendererdebug: f2946e0a1c3b906e71555a7c4a39aa6a6c0e639b
React-RCTAnimation: ed774e28e707ce47b1e2dc6aa7f8f3267b815061
React-RCTAppDelegate: b3312577f20a1c3aaf58ff6d561f3119c74b95b4
React-RCTBlob: 8c173ce722daff128efb38f29a390984800f9302
React-RCTFabric: a0a76ccfa863b02382cb74e04450e9f69cd1cf49
React-RCTImage: 1f75f5d0539b381f70981386b1459fbb2c21eb9b
React-RCTLinking: febd566d57a9cb05a02f39771ccc8c20f8432e89
React-RCTNetwork: d427de729372fd50d7cb601db64d0fcd9ea9a514
React-RCTSettings: 73594c6c8c334c7d958cf98ac72335f3e4df9bf5
React-RCTText: f1079c24f45cec6ddb6363c12ad87f9a940b2ddb
React-RCTVibration: 62420b57a47482d1b88dde64ba88d333f2625aab
React-rendererdebug: a474ec4cdfed75211dce6c3828de8391cc5c4280
React-rncore: 74030de0ffef7b1a3fb77941168624534cc9ae7f
React-runtimeexecutor: 2d1f64f58193f00a3ad71d3f89c2bfbfe11cf5a5
React-runtimescheduler: 6517c0cdfae3ea29b599759e069ae97746163248
@@ -1260,8 +1260,8 @@ SPEC CHECKSUMS:
ReactTestApp-Resources: 857244f3a23f2b3157b364fa06cf3e8866deff9c
RNCPicker: d2ac37457765e0066fe17c93f536eae024b6e53a
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047
Yoga: 13c8ef87792450193e117976337b8527b49e8c03
PODFILE CHECKSUM: 4f0c2a9ecae3454d8a3aae9fd7fdd7724fa2138a
COCOAPODS: 1.15.2
COCOAPODS: 1.16.2
+3
View File
@@ -97,6 +97,9 @@ const DRMExample = () => {
newSource.drm = {
type: DRMType.WIDEVINE,
licenseServer: widevineLicense,
headers: {
'x-drm-userToken': token,
},
};
newSource.uri = dash;
} else {
@@ -5,14 +5,14 @@ import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.util.EventLogger
import com.brentvatne.common.toolbox.DebugLog
import com.brentvatne.react.RNVPlugin
import com.brentvatne.exoplayer.RNVExoplayerPlugin
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
class VideoPluginSampleModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext), RNVPlugin, Player.Listener {
ReactContextBaseJavaModule(reactContext), RNVExoplayerPlugin, Player.Listener {
private val debugEventLogger = EventLogger("RNVPluginSample")
@@ -35,16 +35,12 @@ class VideoPluginSampleModule(reactContext: ReactApplicationContext) :
}
override fun onInstanceCreated(id: String, player: Any) {
if (player is ExoPlayer) {
player.addAnalyticsListener(debugEventLogger)
player.addListener(this)
}
override fun onInstanceCreated(id: String, player: ExoPlayer) {
player.addAnalyticsListener(debugEventLogger)
player.addListener(this)
}
override fun onInstanceRemoved(id: String, player: Any) {
if (player is ExoPlayer) {
player.removeAnalyticsListener(debugEventLogger)
}
override fun onInstanceRemoved(id: String, player: ExoPlayer) {
player.removeAnalyticsListener(debugEventLogger)
}
}
@@ -3,7 +3,7 @@ import AVFoundation
import AVKit
@objc(VideoPluginSample)
class VideoPluginSample: NSObject, RNVPlugin {
class VideoPluginSample: RNVAVPlayerPlugin {
private var _playerRateChangeObserver: NSKeyValueObservation?
private var _playerCurrentItemChangeObserver: NSKeyValueObservation?
private var _playerItemStatusObserver: NSKeyValueObservation?
@@ -16,6 +16,10 @@ class VideoPluginSample: NSObject, RNVPlugin {
ReactNativeVideoManager.shared.registerPlugin(plugin: self)
}
deinit {
ReactNativeVideoManager.shared.unregisterPlugin(plugin: self)
}
@objc(withResolver:withRejecter:)
func setMetadata(resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
@@ -25,23 +29,16 @@ class VideoPluginSample: NSObject, RNVPlugin {
/*
* Handlers called on player creation and destructon
*/
func onInstanceCreated(id: String, player: Any) {
if player is AVPlayer {
let avPlayer = player as! AVPlayer
NSLog("plug onInstanceCreated")
_playerRateChangeObserver = avPlayer.observe(\.rate, options: [.old], changeHandler: handlePlaybackRateChange)
_playerCurrentItemChangeObserver = avPlayer.observe(\.currentItem, options: [.old], changeHandler: handleCurrentItemChange)
}
override func onInstanceCreated(id: String, player: AVPlayer) {
NSLog("plug onInstanceCreated")
_playerRateChangeObserver = player.observe(\.rate, options: [.old], changeHandler: handlePlaybackRateChange)
_playerCurrentItemChangeObserver = player.observe(\.currentItem, options: [.old], changeHandler: handleCurrentItemChange)
}
func onInstanceRemoved(id: String, player: Any) {
if player is AVPlayer {
let avPlayer = player as! AVPlayer
NSLog("plug onInstanceRemoved")
_playerRateChangeObserver?.invalidate()
_playerCurrentItemChangeObserver?.invalidate()
}
override func onInstanceRemoved(id: String, player: AVPlayer) {
NSLog("plug onInstanceRemoved")
_playerRateChangeObserver?.invalidate()
_playerCurrentItemChangeObserver?.invalidate()
}
/**