react-native-media3-player 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mohammad Rehan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,153 @@
1
+ # 📽️ Media3Player
2
+
3
+ > A lightweight, high-performance React Native video player powered by Android Media3 (ExoPlayer). Fully customizable and supports autoplay, mute, and event handling. This is **Android** only package.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+ - [Installation](#installation)
9
+ - [Usage](#usage)
10
+ - [Props](#props)
11
+ - [Events](#events)
12
+ - [TypeScript Support](#typescript-support)
13
+ - [Examples](#examples)
14
+ - [Screenshots](#screenshots)
15
+ - [Contributing](#contributing)
16
+ - [License](#license)
17
+
18
+ ---
19
+
20
+ ## Installation
21
+
22
+ **Install via npm:**
23
+ ```bash
24
+ npm install react-native-media3-player
25
+ ```
26
+
27
+ **Or yarn:**
28
+ ```bash
29
+ yarn add react-native-media3-player
30
+ ```
31
+
32
+ > Requires **React Native >= 0.70**
33
+
34
+ ---
35
+
36
+ ## Usage
37
+
38
+ ```jsx
39
+ import React from 'react';
40
+ import { View } from 'react-native';
41
+ import Media3Player from 'react-native-media3-player';
42
+
43
+ export default function App() {
44
+ return (
45
+ <View style={{ flex: 1 }}>
46
+ <Media3Player
47
+ style={{ width: '100%', height: 250 }}
48
+ source={{ uri: 'https://example.com/video.mp4' }}
49
+ autoplay={true}
50
+ play={true}
51
+ mute={false}
52
+ onReady={() => console.log('Player is ready')}
53
+ onEnd={() => console.log('Video ended')}
54
+ onError={(error) => console.log('Player error:', error.message)}
55
+ />
56
+ </View>
57
+ );
58
+ }
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Props
64
+
65
+ | Prop | Type | Default | Description |
66
+ |------------|-----------------------------|----------|-------------|
67
+ | `source` | `{ uri: string }` | required | Video source object. Must include a valid URI. |
68
+ | `autoplay` | `boolean` | `false` | Automatically start playback when the video is ready. |
69
+ | `play` | `boolean` | `false` | Controls whether the player is playing. Overrides autoplay. |
70
+ | `mute` | `boolean` | `false` | Mutes or unmutes the video. |
71
+ | `style` | `ViewStyle` or `ViewStyle[]` | `{ width: '100%', height: 250 }` | Styling for the player container. |
72
+
73
+ ---
74
+
75
+ ## Events
76
+
77
+ | Event | Callback Signature | Description |
78
+ |------------|----------------------------------|-------------|
79
+ | `onReady` | `() => void` | Fired when the player is ready to play. |
80
+ | `onEnd` | `() => void` | Fired when the video reaches the end. |
81
+ | `onError` | `(error: { message: string }) => void` | Fired when the player encounters an error. Error object includes a `message` property. |
82
+
83
+ ---
84
+
85
+ ## TypeScript Support
86
+
87
+ This library includes TypeScript definitions. Example:
88
+
89
+ ```ts
90
+ import React from 'react';
91
+ import { ViewStyle } from 'react-native';
92
+ import Media3Player, { Media3PlayerProps } from 'react-native-media3-player';
93
+
94
+ const props: Media3PlayerProps = {
95
+ source: { uri: 'https://example.com/video.mp4' },
96
+ autoplay: true,
97
+ play: true,
98
+ mute: false,
99
+ style: { width: '100%', height: 250 },
100
+ onReady: () => console.log('Ready'),
101
+ onEnd: () => console.log('End'),
102
+ onError: (err) => console.log(err.message),
103
+ };
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Examples
109
+
110
+ **Basic Player:**
111
+ ```jsx
112
+ <Media3Player source={{ uri: 'https://example.com/video.mp4' }} />
113
+ ```
114
+
115
+ **Autoplay & Mute:**
116
+ ```jsx
117
+ <Media3Player
118
+ source={{ uri: 'https://example.com/video.mp4' }}
119
+ autoplay
120
+ mute
121
+ />
122
+ ```
123
+
124
+ **Event Handling:**
125
+ ```jsx
126
+ <Media3Player
127
+ source={{ uri: 'https://example.com/video.mp4' }}
128
+ onReady={() => console.log('Ready')}
129
+ onEnd={() => console.log('End')}
130
+ onError={(err) => console.error(err.message)}
131
+ />
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Contributing
137
+
138
+ We welcome contributions!
139
+
140
+ 1. Fork the repo
141
+ 2. Create a branch (`git checkout -b feature/new-feature`)
142
+ 3. Commit your changes (`git commit -m 'Add feature'`)
143
+ 4. Push to the branch (`git push origin feature/new-feature`)
144
+ 5. Open a Pull Request
145
+
146
+ > Please follow [Semantic Versioning](https://semver.org/) for commits.
147
+
148
+ ---
149
+
150
+ ## License
151
+
152
+ MIT © [Mohammad Rehan](https://github.com/mdRehan991)
153
+
@@ -0,0 +1,37 @@
1
+ apply plugin: "com.android.library"
2
+ apply plugin: "org.jetbrains.kotlin.android"
3
+
4
+ android {
5
+ namespace "com.rnmedia3playerdemo"
6
+ compileSdkVersion 35
7
+
8
+ defaultConfig {
9
+ minSdkVersion 24
10
+ targetSdkVersion 34
11
+ }
12
+
13
+ compileOptions {
14
+ sourceCompatibility JavaVersion.VERSION_17
15
+ targetCompatibility JavaVersion.VERSION_17
16
+ }
17
+
18
+ kotlinOptions {
19
+ jvmTarget = "17"
20
+ }
21
+ }
22
+
23
+ dependencies {
24
+ // Required for React Native bridge
25
+ implementation "com.facebook.react:react-native:+"
26
+
27
+ // Kotlin standard lib
28
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.0"
29
+
30
+ // ✅ Media3 dependencies
31
+ implementation "androidx.media3:media3-exoplayer:1.4.1"
32
+ implementation "androidx.media3:media3-ui:1.4.1"
33
+ implementation "androidx.media3:media3-common:1.4.1"
34
+
35
+ // Useful Android extensions
36
+ implementation "androidx.core:core-ktx:1.13.1"
37
+ }
@@ -0,0 +1,39 @@
1
+ # Project-wide Gradle settings.
2
+
3
+ # IDE (e.g. Android Studio) users:
4
+ # Gradle settings configured through the IDE *will override*
5
+ # any settings specified in this file.
6
+
7
+ # For more details on how to configure your build environment visit
8
+ # http://www.gradle.org/docs/current/userguide/build_environment.html
9
+
10
+ # Specifies the JVM arguments used for the daemon process.
11
+ # The setting is particularly useful for tweaking memory settings.
12
+ # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13
+ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14
+
15
+ # When configured, Gradle will run in incubating parallel mode.
16
+ # This option should only be used with decoupled projects. More details, visit
17
+ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18
+ # org.gradle.parallel=true
19
+
20
+ # AndroidX package structure to make it clearer which packages are bundled with the
21
+ # Android operating system, and which are packaged with your app's APK
22
+ # https://developer.android.com/topic/libraries/support-library/androidx-rn
23
+ android.useAndroidX=true
24
+
25
+ # Use this property to specify which architecture you want to build.
26
+ # You can also override it from the CLI using
27
+ # ./gradlew <task> -PreactNativeArchitectures=x86_64
28
+ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
29
+
30
+ # Use this property to enable support to the new architecture.
31
+ # This will allow you to use TurboModules and the Fabric render in
32
+ # your application. You should enable this flag either if you want
33
+ # to write custom TurboModules/Fabric components OR use libraries that
34
+ # are providing them.
35
+ newArchEnabled=true
36
+
37
+ # Use this property to enable or disable the Hermes JS engine.
38
+ # If set to false, you will be using JSC instead.
39
+ hermesEnabled=true
@@ -0,0 +1,2 @@
1
+ rootProject.name = 'react-native-media3-player'
2
+ include ':react-native-media3-player'
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.rnmedia3playerdemo">
3
+ </manifest>
@@ -0,0 +1,14 @@
1
+ package com.rnmedia3playerdemo
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.uimanager.ViewManager
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+
8
+ class Media3Package : ReactPackage {
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> = emptyList()
10
+
11
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
12
+ return listOf(Media3PlayerViewManager(reactContext))
13
+ }
14
+ }
@@ -0,0 +1,116 @@
1
+ package com.rnmedia3playerdemo
2
+
3
+ import android.content.Context
4
+ import android.net.Uri
5
+ import android.util.Log
6
+ import android.widget.FrameLayout
7
+ import androidx.media3.common.MediaItem
8
+ import androidx.media3.common.Player
9
+ import androidx.media3.common.PlaybackException
10
+ import androidx.media3.exoplayer.ExoPlayer
11
+ import androidx.media3.ui.PlayerView
12
+ import com.facebook.react.bridge.ReactContext
13
+ import com.facebook.react.uimanager.events.RCTEventEmitter
14
+ import com.facebook.react.bridge.Arguments
15
+
16
+ /**
17
+ * Media3PlayerView
18
+ *
19
+ * Handles ExoPlayer playback and exposes events to React Native:
20
+ * - onReady
21
+ * - onEnd
22
+ * - onError
23
+ */
24
+ class Media3PlayerView(context: Context) : FrameLayout(context) {
25
+ private var exoPlayer: ExoPlayer? = null
26
+ private var playerView: PlayerView
27
+ private var sourceUri: String? = null
28
+ private var autoplay: Boolean = false
29
+ private var play: Boolean = false
30
+ private var mute: Boolean = false
31
+
32
+ init {
33
+ playerView = PlayerView(context)
34
+ playerView.layoutParams = LayoutParams(
35
+ LayoutParams.MATCH_PARENT,
36
+ LayoutParams.MATCH_PARENT
37
+ )
38
+ addView(playerView)
39
+ }
40
+
41
+ private fun initializePlayer() {
42
+ if (exoPlayer == null) {
43
+ exoPlayer = ExoPlayer.Builder(context).build()
44
+ playerView.player = exoPlayer
45
+
46
+ exoPlayer?.addListener(object : Player.Listener {
47
+ override fun onPlaybackStateChanged(state: Int) {
48
+ when (state) {
49
+ Player.STATE_READY -> {
50
+ sendEvent("onReady")
51
+ if (autoplay) {
52
+ exoPlayer?.playWhenReady = true
53
+ exoPlayer?.play()
54
+ Log.d("Media3Player", "Autoplay triggered when player became ready")
55
+ }
56
+ }
57
+ Player.STATE_ENDED -> {
58
+ sendEvent("onEnd")
59
+ }
60
+ }
61
+ }
62
+
63
+ override fun onPlayerError(error: PlaybackException) {
64
+ sendEvent("onError", error.message ?: "Unknown error")
65
+ }
66
+ })
67
+ }
68
+ }
69
+
70
+ fun setSource(uriString: String?) {
71
+ if (uriString.isNullOrEmpty()) return
72
+ sourceUri = uriString
73
+
74
+ initializePlayer()
75
+
76
+ val item = MediaItem.fromUri(Uri.parse(uriString))
77
+ exoPlayer?.setMediaItem(item)
78
+ exoPlayer?.prepare()
79
+ }
80
+
81
+ fun setAutoplay(value: Boolean) {
82
+ autoplay = value
83
+ }
84
+
85
+ fun setPlay(value: Boolean) {
86
+ play = value
87
+ // if you want to disable autoplay with play (prop) -
88
+ // if (exoPlayer?.playbackState == Player.STATE_READY)
89
+ if (play) {
90
+ exoPlayer?.play()
91
+ } else {
92
+ exoPlayer?.pause()
93
+ }
94
+ // }
95
+ }
96
+
97
+ fun setMute(value: Boolean) {
98
+ mute = value
99
+ exoPlayer?.volume = if (mute) 0f else 1f
100
+ }
101
+
102
+ fun releasePlayer() {
103
+ exoPlayer?.release()
104
+ exoPlayer = null
105
+ }
106
+
107
+ // 👇 helper function to send events to React Native
108
+ private fun sendEvent(eventName: String, message: String? = null) {
109
+ val reactContext = context as? ReactContext ?: return
110
+ val event = Arguments.createMap()
111
+ message?.let { event.putString("message", it) }
112
+ reactContext
113
+ .getJSModule(RCTEventEmitter::class.java)
114
+ .receiveEvent(id, eventName, event)
115
+ }
116
+ }
@@ -0,0 +1,61 @@
1
+ package com.rnmedia3playerdemo
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.bridge.ReadableMap
5
+ import com.facebook.react.uimanager.SimpleViewManager
6
+ import com.facebook.react.uimanager.ThemedReactContext
7
+ import com.facebook.react.uimanager.annotations.ReactProp
8
+
9
+ /**
10
+ * Media3PlayerViewManager
11
+ *
12
+ * Exposes the native view to React Native.
13
+ * Props: source { uri: string }, autoplay, play, mute
14
+ * Events: onReady, onEnd, onError
15
+ */
16
+ class Media3PlayerViewManager(private val reactContext: ReactApplicationContext) :
17
+ SimpleViewManager<Media3PlayerView>() {
18
+
19
+ override fun getName(): String = "Media3PlayerView"
20
+
21
+ override fun createViewInstance(reactContext: ThemedReactContext): Media3PlayerView {
22
+ return Media3PlayerView(reactContext)
23
+ }
24
+
25
+ @ReactProp(name = "source")
26
+ fun setSource(view: Media3PlayerView, source: ReadableMap?) {
27
+ val uri: String? = source?.getString("uri")
28
+ if (!uri.isNullOrEmpty()) {
29
+ view.setSource(uri)
30
+ }
31
+ }
32
+
33
+ @ReactProp(name = "autoplay", defaultBoolean = false)
34
+ fun setAutoplay(view: Media3PlayerView, autoplay: Boolean) {
35
+ view.setAutoplay(autoplay)
36
+ }
37
+
38
+ @ReactProp(name = "play", defaultBoolean = false)
39
+ fun setPlay(view: Media3PlayerView, play: Boolean) {
40
+ view.setPlay(play)
41
+ }
42
+
43
+ @ReactProp(name = "mute", defaultBoolean = false)
44
+ fun setMute(view: Media3PlayerView, mute: Boolean) {
45
+ view.setMute(mute)
46
+ }
47
+
48
+ override fun onDropViewInstance(view: Media3PlayerView) {
49
+ super.onDropViewInstance(view)
50
+ view.releasePlayer()
51
+ }
52
+
53
+ // 👇 Expose custom events to JS
54
+ override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
55
+ return mutableMapOf(
56
+ "onReady" to mapOf("registrationName" to "onReady"),
57
+ "onEnd" to mapOf("registrationName" to "onEnd"),
58
+ "onError" to mapOf("registrationName" to "onError")
59
+ )
60
+ }
61
+ }
@@ -0,0 +1,37 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Copyright (C) 2014 The Android Open Source Project
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ -->
16
+ <inset xmlns:android="http://schemas.android.com/apk/res/android"
17
+ android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
18
+ android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
19
+ android:insetTop="@dimen/abc_edit_text_inset_top_material"
20
+ android:insetBottom="@dimen/abc_edit_text_inset_bottom_material"
21
+ >
22
+
23
+ <selector>
24
+ <!--
25
+ This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
26
+ The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
27
+ NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
28
+
29
+ <item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
30
+
31
+ For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
32
+ -->
33
+ <item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
34
+ <item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
35
+ </selector>
36
+
37
+ </inset>
@@ -0,0 +1,3 @@
1
+ <resources>
2
+ <string name="app_name">RNMedia3PlayerDemo</string>
3
+ </resources>
@@ -0,0 +1,9 @@
1
+ <resources>
2
+
3
+ <!-- Base application theme. -->
4
+ <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
5
+ <!-- Customize your theme here. -->
6
+ <item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
7
+ </style>
8
+
9
+ </resources>
package/index.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { ViewStyle } from 'react-native';
2
+ import * as React from 'react';
3
+
4
+ export interface Media3PlayerProps {
5
+ style?: ViewStyle | ViewStyle[];
6
+ source: { uri: string };
7
+ autoplay?: boolean;
8
+ play?: boolean;
9
+ mute?: boolean;
10
+ onReady?: () => void;
11
+ onEnd?: () => void;
12
+ onError?: (error: any) => void;
13
+ }
14
+
15
+ export default class Media3Player extends React.Component<Media3PlayerProps> {}
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import Media3Player from './src/Media3Player';
2
+
3
+ export default Media3Player;
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "react-native-media3-player",
3
+ "version": "0.0.1",
4
+ "description": "React Native Media3 Player component for Android (ExoPlayer 3 integration).",
5
+ "main": "index.js",
6
+ "types": "index.d.ts",
7
+ "keywords": [
8
+ "react-native",
9
+ "android",
10
+ "video",
11
+ "player",
12
+ "media3",
13
+ "exoplayer"
14
+ ],
15
+ "author": "Mohammad Rehan <mohdrehan29nov@gmail.com>",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/mdRehan991/react-native-media3-player.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/mdRehan991/react-native-media3-player/issues"
23
+ },
24
+ "homepage": "https://github.com/mdRehan991/react-native-media3-player#readme",
25
+ "peerDependencies": {
26
+ "react": ">=18.0.0",
27
+ "react-native": ">=0.72.0"
28
+ },
29
+ "files": [
30
+ "android",
31
+ "src",
32
+ "index.js",
33
+ "index.d.ts"
34
+ ]
35
+ }
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ import {requireNativeComponent, StyleSheet} from 'react-native';
3
+
4
+ // Link to native view
5
+ const NativeMedia3Player = requireNativeComponent('Media3PlayerView');
6
+
7
+ /**
8
+ * Media3Player
9
+ *
10
+ * Props:
11
+ * - source: { uri: string } ✅ required
12
+ * - autoplay: boolean
13
+ * - play: boolean
14
+ * - mute: boolean
15
+ * - onReady: function
16
+ * - onEnd: function
17
+ * - onError: function
18
+ */
19
+ export default function Media3Player({
20
+ style,
21
+ source,
22
+ autoplay = false,
23
+ play = false,
24
+ mute = false,
25
+ onReady,
26
+ onEnd,
27
+ onError,
28
+ }) {
29
+ if (!source || !source.uri) {
30
+ console.warn('Media3Player: "source" prop with a valid "uri" is required.');
31
+ return null;
32
+ }
33
+
34
+ return (
35
+ <NativeMedia3Player
36
+ style={[styles.default, style]} // ensure style is never undefined
37
+ source={source}
38
+ autoplay={autoplay}
39
+ play={play}
40
+ mute={mute}
41
+ onReady={onReady}
42
+ onEnd={onEnd}
43
+ onError={onError}
44
+ />
45
+ );
46
+ }
47
+
48
+ const styles = StyleSheet.create({
49
+ default: {
50
+ width: '100%',
51
+ height: 250,
52
+ backgroundColor: 'black',
53
+ },
54
+ });