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 +21 -0
- package/README.md +153 -0
- package/android/build.gradle +37 -0
- package/android/gradle.properties +39 -0
- package/android/settings.gradle +2 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/com/rnmedia3playerdemo/Media3Package.kt +14 -0
- package/android/src/main/java/com/rnmedia3playerdemo/Media3PlayerView.kt +116 -0
- package/android/src/main/java/com/rnmedia3playerdemo/Media3PlayerViewManager.kt +61 -0
- package/android/src/main/res/drawable/rn_edit_text_material.xml +37 -0
- package/android/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/android/src/main/res/values/strings.xml +3 -0
- package/android/src/main/res/values/styles.xml +9 -0
- package/index.d.ts +15 -0
- package/index.js +3 -0
- package/package.json +35 -0
- package/src/Media3Player.js +54 -0
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,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>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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
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
|
+
});
|