Plugin
Since version 6.4.0
, it is possible to create plugins for analytics management and potentially more.
A sample plugin is available in the repository: example/react-native-video-plugin-sample (opens in a new tab).
Commercial Plugins
We at The Widlarz Group have created a set of plugins for comprehensive offline video support. If you are interested, check out our Offline Video SDK (opens in a new tab). If you need additional plugins (analytics, processing, etc.), let us know.
Using or recommending our commercial software helps support the maintenance of this open-source project. Thank you!
Plugins for Analytics
Most analytics systems that track player data (e.g., bitrate, errors) can be integrated directly with ExoPlayer or AVPlayer.
This plugin system allows for non-intrusive analytics integration with react-native-video
. It should be implemented in native languages (Kotlin/Swift) to ensure efficiency.
The goal is to enable easy analytics integration without modifying react-native-video
itself.
Warnings & Considerations
This is an experimental API and may change over time. The API is simple yet flexible enough to implement analytics systems. If additional metadata is needed, you should implement a setter in your custom package.
Since the API is flexible, misuse is possible. The player handle should be treated as read-only. Modifying player behavior may cause unexpected issues in react-native-video
.
General Setup
First, create a new React Native package:
npx create-react-native-library@latest react-native-video-custom-analytics
Both Android and iOS implementations expose an RNVPlugin
interface.
Your react-native-video-custom-analytics
package should implement this interface and register itself as a plugin for react-native-video
.
Plugin Types
There are two types of plugins you can implement:
- Base Plugin (
RNVPlugin
): For general-purpose plugins that don't need specific player implementation details. - Player-Specific Plugins:
RNVAVPlayerPlugin
for iOS: Provides type-safe access to AVPlayer instancesRNVExoplayerPlugin
for Android: Provides type-safe access to ExoPlayer instances
Choose the appropriate plugin type based on your needs. If you need direct access to player-specific APIs, use the player-specific plugin classes.
Android Implementation
1. Create the Plugin
You can implement either the base RNVPlugin
interface or the player-specific RNVExoplayerPlugin
interface.
Base Plugin
class MyAnalyticsPlugin : RNVPlugin {
override fun onInstanceCreated(id: String, player: Any) {
// Handle player creation
}
override fun onInstanceRemoved(id: String, player: Any) {
// Handle player removal
}
}
ExoPlayer-Specific Plugin
class MyExoPlayerAnalyticsPlugin : RNVExoplayerPlugin {
override fun onInstanceCreated(id: String, player: ExoPlayer) {
// Handle ExoPlayer creation with type-safe access
}
override fun onInstanceRemoved(id: String, player: ExoPlayer) {
// Handle ExoPlayer removal with type-safe access
}
}
The RNVPlugin
interface defines two functions:
/**
* Function called when a new player is created
* @param id: a random string identifying the player
* @param player: the instantiated player reference
*/
fun onInstanceCreated(id: String, player: Any)
/**
* Function called when a player should be destroyed
* when this callback is called, the plugin shall free all
* resources and release all reference to Player object
* @param id: a random string identifying the player
* @param player: the player to release
*/
fun onInstanceRemoved(id: String, player: Any)
2. Register the Plugin
To register the plugin within the main react-native-video
package, call:
ReactNativeVideoManager.getInstance().registerPlugin(plugin)
In the sample implementation, the plugin is registered in the createNativeModules
entry point.
Once registered, your module can track player updates and report analytics data.
Extending Core Functionality via Plugins
In addition to analytics, plugins can also be used to modify or override core behavior of react-native-video
.
This allows native modules to deeply integrate with the playback system - for example:
- replacing the media source factory,
- modifying the media item before playback starts (e.g., injecting stream keys),
- disabling caching dynamically per source.
These capabilities are available through the advanced Android plugin interface: RNVExoplayerPlugin
.
⚠️ These extension points are optional — if no plugin provides them, the player behaves exactly as it did before.
Plugin Extension Points (Android)
If your plugin implements RNVExoplayerPlugin
, you can override the following methods:
1. overrideMediaItemBuilder
Allows you to modify the MediaItem.Builder
before it’s used. You can inject stream keys, cache keys, or override URIs.
override fun overrideMediaItemBuilder(
source: Source,
mediaItemBuilder: MediaItem.Builder
): MediaItem.Builder? {
// Return modified builder or null to use default
}
2. overrideMediaDataSourceFactory
Lets you replace the data source used by ExoPlayer. Useful for implementing read-only cache or request interception.
override fun overrideMediaDataSourceFactory(
source: Source,
mediaDataSourceFactory: DataSource.Factory
): DataSource.Factory? {
// Return your custom factory or null to use default
}
3. shouldDisableCache
Enables dynamic disabling of the caching system per source.
override fun shouldDisableCache(source: Source): Boolean {
return true // your own logic
}
Once implemented, react-native-video
will automatically invoke these methods for each <Video />
instance.
iOS Implementation
1. Podspec Integration
Your new module must have access to react-native-video
. Add it as a dependency in your Podspec file:
s.dependency "react-native-video"
2. Create the Plugin
You can implement either the base RNVPlugin
class or the player-specific RNVAVPlayerPlugin
class.
Base Plugin
class MyAnalyticsPlugin: RNVPlugin {
override func onInstanceCreated(id: String, player: Any) {
// Handle player creation
}
override func onInstanceRemoved(id: String, player: Any) {
// Handle player removal
}
}
AVPlayer-Specific Plugin
class MyAVPlayerAnalyticsPlugin: RNVAVPlayerPlugin {
override func onInstanceCreated(id: String, player: AVPlayer) {
// Handle AVPlayer creation with type-safe access
}
override func onInstanceRemoved(id: String, player: AVPlayer) {
// Handle AVPlayer removal with type-safe access
}
}
The RNVPlugin
class defines two methods:
/**
* Function called when a new player is created
* @param id: a random string identifying the player
* @param player: the instantiated player reference
*/
open func onInstanceCreated(id: String, player: Any) { /* no-op */ }
/**
* Function called when a player should be destroyed
* when this callback is called, the plugin shall free all
* resources and release all reference to Player object
* @param id: a random string identifying the player
* @param player: the player to release
*/
open func onInstanceRemoved(id: String, player: Any) { /* no-op */ }
3. Register the Plugin
To register the plugin in react-native-video
, call:
ReactNativeVideoManager.shared.registerPlugin(plugin: plugin)
In the sample implementation, the plugin is registered inside the VideoPluginSample
file within the init
function:
import react_native_video
...
override init() {
super.init()
ReactNativeVideoManager.shared.registerPlugin(plugin: self)
}
Once registered, your module can track player updates and report analytics data to your backend.
Custom DRM Manager
You can provide a custom DRM manager through your plugin to handle DRM in a custom way. This is useful when you need to integrate with a specific DRM provider or implement custom DRM logic.
Android Implementation
1/ Create custom DRM manager
Create a class that implements the DRMManagerSpec
interface:
class CustomDRMManager : DRMManagerSpec {
@Throws(UnsupportedDrmException::class)
override fun buildDrmSessionManager(uuid: UUID, drmProps: DRMProps): DrmSessionManager? {
// Your custom implementation for building DRM session manager
// Return null if the DRM scheme is not supported
// Throw UnsupportedDrmException if the DRM scheme is invalid
}
}
2/ Register DRM manager in your plugin
Implement getDRMManager()
in your ExoPlayer plugin to provide the custom DRM manager:
class CustomVideoPlugin : RNVExoplayerPlugin {
private val drmManager = CustomDRMManager()
override fun getDRMManager(): DRMManagerSpec? {
return drmManager
}
override fun onInstanceCreated(id: String, player: ExoPlayer) {
// Handle player creation
}
override fun onInstanceRemoved(id: String, player: ExoPlayer) {
// Handle player removal
}
}
iOS Implementation
1/ Create custom DRM manager
Create a class that implements the DRMManagerSpec
protocol:
class CustomDRMManager: NSObject, DRMManagerSpec {
func createContentKeyRequest(
asset: AVContentKeyRecipient,
drmProps: DRMParams?,
reactTag: NSNumber?,
onVideoError: RCTDirectEventBlock?,
onGetLicense: RCTDirectEventBlock?
) {
// Initialize content key session and handle key request
}
func handleContentKeyRequest(keyRequest: AVContentKeyRequest) {
// Process the content key request
}
func finishProcessingContentKeyRequest(keyRequest: AVContentKeyRequest, license: Data) throws {
// Finish processing the key request with the obtained license
}
func handleError(_ error: Error, for keyRequest: AVContentKeyRequest) {
// Handle any errors during the DRM process
}
func setJSLicenseResult(license: String, licenseUrl: String) {
// Handle successful license acquisition from JS side
}
func setJSLicenseError(error: String, licenseUrl: String) {
// Handle license acquisition errors from JS side
}
}
2/ Register DRM manager in your plugin
Implement getDRMManager()
in your AVPlayer plugin to provide the custom DRM manager:
class CustomVideoPlugin: RNVAVPlayerPlugin {
override func getDRMManager() -> DRMManagerSpec? {
return CustomDRMManager()
}
override func onInstanceCreated(id: String, player: AVPlayer) {
// Handle player creation
}
override func onInstanceRemoved(id: String, player: AVPlayer) {
// Handle player removal
}
}
Important notes about DRM managers:
- Only one plugin can provide a DRM manager at a time. If multiple plugins try to provide DRM managers, only the first one will be used.
- The custom DRM manager will be used for all video instances in the app.
- If no custom DRM manager is provided:
- On iOS, the default FairPlay-based implementation will be used
- On Android, the default ExoPlayer DRM implementation will be used
- The DRM manager must handle all DRM-related functionality:
- On iOS: key requests, license acquisition, and error handling through AVContentKeySession
- On Android: DRM session management and license acquisition through ExoPlayer's DrmSessionManager