react-native-media3-player
v3.0.0
Published
React Native Media3 Player component for Android (ExoPlayer 3 integration).
Maintainers
Readme
📽️ Media3Player
A lightweight, high-performance React Native video player powered by Android Media3 (ExoPlayer). Fully customizable with support for autoplay, mute, event handling, automatic stream type detection (DASH, HLS, MP4), and client-side ad insertion (CSAI) via Google IMA. This is an Android only package.
Table of Contents
- Installation
- Usage
- Props
- Stream Type Detection
- DRM Support (Widevine)
- IMA Ads Support (CSAI)
- Events
- TypeScript Support
- Examples
- Screenshots
- Contributing
- License
Installation
Install via npm:
npm install react-native-media3-playerOr yarn:
yarn add react-native-media3-playerRequires React Native >= 0.70
Note: To use a specific Media3 version, add or update the following in your android/build.gradle (Project-level) file:
buildscript {
ext {
media3Version = "1.4.1" // Set your desired Media3 version
}
}Be sure to sync your project after making this change.
Usage
Basic (non-DRM):
import React from 'react';
import {View} from 'react-native';
import Media3Player from 'react-native-media3-player';
export default function App() {
return (
<View style={{flex: 1}}>
<Media3Player
style={{width: '100%', height: 250}}
source={{uri: 'https://example.com/video.mp4'}}
autoplay={true}
play={true}
mute={false}
onReady={() => console.log('Player is ready')}
onEnd={() => console.log('Video ended')}
onError={error => console.log('Player error:', error.message)}
/>
</View>
);
}DRM-protected content (Widevine):
import React from 'react';
import {View} from 'react-native';
import Media3Player from 'react-native-media3-player';
export default function App() {
return (
<View style={{flex: 1}}>
<Media3Player
style={{width: '100%', height: 250}}
source={{
uri: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine/dash.mpd',
type: 'dash',
drm: {
licenseUrl: 'https://cwip-shaka-proxy.appspot.com/no_auth',
},
}}
autoplay={true}
play={true}
onReady={() => console.log('Player is ready')}
onEnd={() => console.log('Video ended')}
onError={error => console.log('Player error:', error.message)}
/>
</View>
);
}With IMA Ads (Client-Side Ad Insertion):
import React from 'react';
import {View} from 'react-native';
import Media3Player from 'react-native-media3-player';
export default function App() {
return (
<View style={{flex: 1}}>
<Media3Player
style={{width: '100%', height: 250}}
source={{
uri: 'https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
ads: {
adTagUrl:
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpreonly&ciu_szs=300x250%2C728x90&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&correlator=',
},
}}
autoplay={true}
play={true}
onReady={() => console.log('Player is ready')}
onEnd={() => console.log('Video ended')}
onError={error => console.log('Player error:', error.message)}
/>
</View>
);
}Props
| Prop | Type | Default | Description |
| ---------- | ---------------------------- | -------------------------------- | ------------------------------------------------------------------------ |
| source | Source | required | Video source object. Must include a valid uri. Supports optional drm and ads config. |
| autoplay | boolean | false | Automatically start playback when the video is ready. |
| play | boolean | false | Controls whether the player is playing. Overrides autoplay. |
| mute | boolean | false | Mutes or unmutes the video. |
| style | ViewStyle or ViewStyle[] | { width: '100%', height: 250 } | Styling for the player container. |
Source Object
| Property | Type | Required | Description |
| -------- | ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| uri | string | Yes | The URI of the media to play (MP4, DASH, HLS, etc.). |
| type | 'dash' \| 'hls' \| 'mp4' | No | Explicitly set the stream type. Defaults to 'mp4'. If omitted, the player auto-detects the type from the URI. |
| drm | DRMConfig | No | DRM configuration for protected content. |
| ads | AdsConfig | No | IMA ads configuration for client-side ad insertion. |
DRMConfig Object
| Property | Type | Required | Description |
| ------------ | --------------------------------- | -------- | ----------------------------------------------------- |
| licenseUrl | string | Yes | The Widevine license server URL. |
| headers | Array<{ key: string, value: string }> | No | Custom headers to include in the DRM license request. |
AdsConfig Object
| Property | Type | Required | Description |
| ---------- | -------- | -------- | ----------------------------------------------------------------- |
| adTagUrl | string | Yes | The VAST/VMAP ad tag URL for client-side ad insertion via IMA SDK. |
Stream Type Detection
The player supports automatic stream type detection based on the media URI. It inspects the file extension and known manifest patterns (.mpd for DASH, .m3u8 for HLS) to choose the correct media source.
You can also explicitly set the stream type using the type property in the source prop. This is useful when the URI does not contain a recognizable extension (e.g., signed URLs or token-based endpoints).
Supported Stream Types
| type Value | Format | Description |
| ------------ | ------------------- | ------------------------------------- |
| 'dash' | DASH (.mpd) | Dynamic Adaptive Streaming over HTTP |
| 'hls' | HLS (.m3u8) | HTTP Live Streaming |
| 'mp4' | Progressive (.mp4)| Standard progressive HTTP download |
Auto-Detection (Recommended)
If the URI contains a known extension, you can omit type entirely:
<Media3Player
source={{uri: 'https://example.com/stream/manifest.mpd'}}
autoplay
play
/>The player will automatically detect this as a DASH stream.
Explicit Type Override
Use type when the URI does not have a recognizable extension:
<Media3Player
source={{
uri: 'https://cdn.example.com/stream?token=abc123',
type: 'hls',
}}
autoplay
play
/>DRM Support (Widevine)
This library supports Widevine DRM for playing protected DASH streams on Android. To enable DRM, pass a drm object inside the source prop.
Basic DRM Playback
<Media3Player
source={{
uri: 'https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd',
drm: {
licenseUrl: 'https://proxy.uat.widevine.com/proxy?provider=widevine_test',
},
}}
autoplay
play
/>DRM with Custom License Headers
Some license servers require authentication tokens or custom headers. Pass them as an array of { key, value } objects:
<Media3Player
source={{
uri: 'https://example.com/protected-stream/manifest.mpd',
drm: {
licenseUrl: 'https://license.example.com/widevine',
headers: [
{key: 'Authorization', value: 'Bearer <your-token>'},
{key: 'X-Custom-Header', value: 'custom-value'},
],
},
}}
autoplay
play
onError={e => console.error('DRM error:', e.message)}
/>Notes
- DRM is currently supported on Android only (Widevine L1/L3 depending on device).
- The
source.urishould point to a DASH (.mpd) stream encrypted with Widevine. - Multi-session DRM is enabled by default for streams that require it.
- If the license request fails, the
onErrorcallback will fire with the error details.
IMA Ads Support (CSAI)
This library supports Client-Side Ad Insertion (CSAI) using the Google IMA SDK integrated via Media3's IMA extension. To enable ads, pass an ads object inside the source prop with a VAST or VMAP ad tag URL.
Basic Ad Playback
<Media3Player
source={{
uri: 'https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
ads: {
adTagUrl:
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpreonly&ciu_szs=300x250%2C728x90&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&correlator=',
},
}}
autoplay
play
/>Ads with DRM Content
You can combine ads with DRM-protected streams:
<Media3Player
source={{
uri: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine/dash.mpd',
type: 'dash',
drm: {
licenseUrl: 'https://cwip-shaka-proxy.appspot.com/no_auth',
},
ads: {
adTagUrl: 'https://your-ad-server.com/vmap-tag',
},
}}
autoplay
play
onError={e => console.error('Error:', e.message)}
/>Notes
- Ads are supported on Android only.
- The
adTagUrlshould point to a valid VAST or VMAP XML endpoint. - Both pre-roll and mid-roll ad configurations are supported via VMAP.
- The IMA ads loader is automatically initialized and released as needed when the ad tag URL changes.
- Ads play inline within the same
PlayerViewused for content playback.
Events
| Event | Callback Signature | Description |
| --------- | -------------------------------------- | -------------------------------------------------------------------------------------- |
| onReady | () => void | Fired when the player is ready to play. |
| onEnd | () => void | Fired when the video reaches the end. |
| onError | (error: { message: string }) => void | Fired when the player encounters an error. Error object includes a message property. |
TypeScript Support
This library includes TypeScript definitions. Example:
import React from 'react';
import {ViewStyle} from 'react-native';
import Media3Player, {Media3PlayerProps} from 'react-native-media3-player';
const props: Media3PlayerProps = {
source: {uri: 'https://example.com/video.mp4'},
autoplay: true,
play: true,
mute: false,
style: {width: '100%', height: 250},
onReady: () => console.log('Ready'),
onEnd: () => console.log('End'),
onError: err => console.log(err.message),
};With DRM and explicit stream type:
const drmProps: Media3PlayerProps = {
source: {
uri: 'https://storage.googleapis.com/shaka-demo-assets/angel-one-widevine/dash.mpd',
type: 'dash',
drm: {
licenseUrl: 'https://cwip-shaka-proxy.appspot.com/no_auth',
headers: [
{key: 'Authorization', value: 'Bearer my-token'},
],
},
},
autoplay: true,
play: true,
style: {width: '100%', height: 250},
onError: err => console.log('DRM Error:', err.message),
};With IMA Ads:
const adsProps: Media3PlayerProps = {
source: {
uri: 'https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
ads: {
adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?...',
},
},
autoplay: true,
play: true,
style: {width: '100%', height: 250},
onError: err => console.log('Ad Error:', err.message),
};Examples
Basic Player:
<Media3Player source={{uri: 'https://example.com/video.mp4'}} />Autoplay & Mute:
<Media3Player source={{uri: 'https://example.com/video.mp4'}} autoplay mute />Event Handling:
<Media3Player
source={{uri: 'https://example.com/video.mp4'}}
onReady={() => console.log('Ready')}
onEnd={() => console.log('End')}
onError={err => console.error(err.message)}
/>HLS Stream:
<Media3Player
source={{
uri: 'https://example.com/live/stream.m3u8',
type: 'hls',
}}
autoplay
play
/>DASH Stream (auto-detected):
<Media3Player
source={{uri: 'https://example.com/video/manifest.mpd'}}
autoplay
play
/>Widevine DRM Stream:
<Media3Player
source={{
uri: 'https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd',
type: 'dash',
drm: {
licenseUrl: 'https://proxy.uat.widevine.com/proxy?provider=widevine_test',
},
}}
autoplay
play
/>DRM with License Headers:
<Media3Player
source={{
uri: 'https://example.com/protected/manifest.mpd',
type: 'dash',
drm: {
licenseUrl: 'https://license.example.com/widevine',
headers: [
{key: 'Authorization', value: 'Bearer my-token'},
],
},
}}
autoplay
play
onError={err => console.error('DRM Error:', err.message)}
/>With IMA Ads (VMAP):
<Media3Player
source={{
uri: 'https://example.com/video.mp4',
ads: {
adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?...',
},
}}
autoplay
play
/>Ads with DRM Stream:
<Media3Player
source={{
uri: 'https://example.com/protected/manifest.mpd',
type: 'dash',
drm: {
licenseUrl: 'https://license.example.com/widevine',
},
ads: {
adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?...',
},
}}
autoplay
play
onError={err => console.error('Error:', err.message)}
/>Contributing
We welcome contributions!
- Fork the repo
- Create a branch (
git checkout -b feature/new-feature) - Commit your changes (
git commit -m 'Add feature') - Push to the branch (
git push origin feature/new-feature) - Open a Pull Request
Please follow Semantic Versioning for commits.
License
MIT © Mohammad Rehan
