react-native-media3-player 0.0.1 → 1.0.0
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/android/build.gradle +24 -6
- package/android/src/main/java/com/rnmedia3playerdemo/Media3Package.kt +17 -5
- package/android/src/main/java/com/rnmedia3playerdemo/Media3PlayerView.kt +81 -25
- package/android/src/main/java/com/rnmedia3playerdemo/Media3PlayerViewManager.kt +66 -21
- package/index.d.ts +5 -4
- package/package.json +11 -2
- package/src/Media3Player.js +21 -18
- package/src/Media3PlayerNativeComponent.ts +37 -0
package/android/build.gradle
CHANGED
|
@@ -1,37 +1,55 @@
|
|
|
1
|
+
// Apply the Android library plugin
|
|
1
2
|
apply plugin: "com.android.library"
|
|
3
|
+
// Apply the Kotlin Android plugin for Kotlin language support
|
|
2
4
|
apply plugin: "org.jetbrains.kotlin.android"
|
|
5
|
+
// Apply the React Native plugin to enable React Native integration
|
|
6
|
+
apply plugin: "com.facebook.react"
|
|
3
7
|
|
|
4
8
|
android {
|
|
9
|
+
// Set the namespace for the generated R class and manifest
|
|
5
10
|
namespace "com.rnmedia3playerdemo"
|
|
11
|
+
|
|
12
|
+
// Compile SDK version to build against
|
|
6
13
|
compileSdkVersion 35
|
|
7
14
|
|
|
8
15
|
defaultConfig {
|
|
16
|
+
// Minimum SDK version supported by the library
|
|
9
17
|
minSdkVersion 24
|
|
18
|
+
// Target SDK version for compatibility and behaviors
|
|
10
19
|
targetSdkVersion 34
|
|
11
20
|
}
|
|
12
21
|
|
|
13
22
|
compileOptions {
|
|
23
|
+
// Specify Java source and target compatibility
|
|
14
24
|
sourceCompatibility JavaVersion.VERSION_17
|
|
15
25
|
targetCompatibility JavaVersion.VERSION_17
|
|
16
26
|
}
|
|
17
27
|
|
|
18
28
|
kotlinOptions {
|
|
29
|
+
// Set the Kotlin JVM target version
|
|
19
30
|
jvmTarget = "17"
|
|
20
31
|
}
|
|
32
|
+
|
|
33
|
+
sourceSets {
|
|
34
|
+
main {
|
|
35
|
+
// Include codegen outputs (for TurboModules, Fabric, etc.) in the main sources
|
|
36
|
+
java.srcDirs += "${buildDir}/generated/source/codegen/java"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
21
39
|
}
|
|
22
40
|
|
|
23
41
|
dependencies {
|
|
24
|
-
//
|
|
25
|
-
|
|
42
|
+
// Dependency for React Native bridge (provided by the app, NOT bundled in aar)
|
|
43
|
+
compileOnly "com.facebook.react:react-android"
|
|
26
44
|
|
|
27
|
-
// Kotlin standard
|
|
28
|
-
implementation "org.jetbrains.kotlin:kotlin-stdlib
|
|
45
|
+
// Kotlin standard library dependency
|
|
46
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
|
29
47
|
|
|
30
|
-
//
|
|
48
|
+
// AndroidX Media3 ExoPlayer, UI components, and Common classes
|
|
31
49
|
implementation "androidx.media3:media3-exoplayer:1.4.1"
|
|
32
50
|
implementation "androidx.media3:media3-ui:1.4.1"
|
|
33
51
|
implementation "androidx.media3:media3-common:1.4.1"
|
|
34
52
|
|
|
35
|
-
//
|
|
53
|
+
// Android core utilities and extensions (KTX)
|
|
36
54
|
implementation "androidx.core:core-ktx:1.13.1"
|
|
37
55
|
}
|
|
@@ -2,13 +2,25 @@ package com.rnmedia3playerdemo
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.ReactPackage
|
|
4
4
|
import com.facebook.react.bridge.NativeModule
|
|
5
|
-
import com.facebook.react.uimanager.ViewManager
|
|
6
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Media3Package integrates the custom Media3PlayerViewManager with React Native.
|
|
10
|
+
*
|
|
11
|
+
* This package does not register any NativeModules. It only provides the
|
|
12
|
+
* Media3PlayerViewManager for use as a native UI component from JavaScript.
|
|
13
|
+
*/
|
|
8
14
|
class Media3Package : ReactPackage {
|
|
9
|
-
|
|
15
|
+
/**
|
|
16
|
+
* No native modules are exported by this package.
|
|
17
|
+
*/
|
|
18
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
|
|
19
|
+
emptyList()
|
|
10
20
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Registers Media3PlayerViewManager as the only custom ViewManager for this package.
|
|
23
|
+
*/
|
|
24
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
|
|
25
|
+
listOf(Media3PlayerViewManager())
|
|
14
26
|
}
|
|
@@ -9,26 +9,32 @@ import androidx.media3.common.Player
|
|
|
9
9
|
import androidx.media3.common.PlaybackException
|
|
10
10
|
import androidx.media3.exoplayer.ExoPlayer
|
|
11
11
|
import androidx.media3.ui.PlayerView
|
|
12
|
-
import com.facebook.react.bridge.ReactContext
|
|
13
|
-
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
14
12
|
import com.facebook.react.bridge.Arguments
|
|
13
|
+
import com.facebook.react.bridge.ReactContext
|
|
14
|
+
import com.facebook.react.bridge.WritableMap
|
|
15
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
16
|
+
import com.facebook.react.uimanager.events.Event
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* Handles ExoPlayer playback and exposes events to React Native:
|
|
20
|
-
* - onReady
|
|
21
|
-
* - onEnd
|
|
22
|
-
* - onError
|
|
19
|
+
* Custom view that wraps ExoPlayer and PlayerView, integrating with React Native.
|
|
23
20
|
*/
|
|
24
21
|
class Media3PlayerView(context: Context) : FrameLayout(context) {
|
|
22
|
+
// ExoPlayer instance to handle media playback
|
|
25
23
|
private var exoPlayer: ExoPlayer? = null
|
|
24
|
+
// PlayerView to display video content
|
|
26
25
|
private var playerView: PlayerView
|
|
26
|
+
// Currently loaded media source URI
|
|
27
27
|
private var sourceUri: String? = null
|
|
28
|
+
// Should video autoplay when ready
|
|
28
29
|
private var autoplay: Boolean = false
|
|
30
|
+
// Play state controlled by the JS prop
|
|
29
31
|
private var play: Boolean = false
|
|
32
|
+
// Mute state controlled by the JS prop
|
|
30
33
|
private var mute: Boolean = false
|
|
31
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Constructor: initialize the PlayerView and attach it to the layout.
|
|
37
|
+
*/
|
|
32
38
|
init {
|
|
33
39
|
playerView = PlayerView(context)
|
|
34
40
|
playerView.layoutParams = LayoutParams(
|
|
@@ -38,16 +44,23 @@ class Media3PlayerView(context: Context) : FrameLayout(context) {
|
|
|
38
44
|
addView(playerView)
|
|
39
45
|
}
|
|
40
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Initializes ExoPlayer and attaches a listener for player events.
|
|
49
|
+
* Ensures only one instance exists.
|
|
50
|
+
*/
|
|
41
51
|
private fun initializePlayer() {
|
|
42
52
|
if (exoPlayer == null) {
|
|
43
53
|
exoPlayer = ExoPlayer.Builder(context).build()
|
|
44
54
|
playerView.player = exoPlayer
|
|
45
55
|
|
|
56
|
+
// Listen for playback state changes and errors
|
|
46
57
|
exoPlayer?.addListener(object : Player.Listener {
|
|
47
58
|
override fun onPlaybackStateChanged(state: Int) {
|
|
48
59
|
when (state) {
|
|
49
60
|
Player.STATE_READY -> {
|
|
50
|
-
|
|
61
|
+
// Notify React Native that player is ready
|
|
62
|
+
sendEvent("topReady")
|
|
63
|
+
// If autoplay is enabled, start playback when ready
|
|
51
64
|
if (autoplay) {
|
|
52
65
|
exoPlayer?.playWhenReady = true
|
|
53
66
|
exoPlayer?.play()
|
|
@@ -55,62 +68,105 @@ class Media3PlayerView(context: Context) : FrameLayout(context) {
|
|
|
55
68
|
}
|
|
56
69
|
}
|
|
57
70
|
Player.STATE_ENDED -> {
|
|
58
|
-
|
|
71
|
+
// Notify React Native that playback has ended
|
|
72
|
+
sendEvent("topEnd")
|
|
59
73
|
}
|
|
60
74
|
}
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
override fun onPlayerError(error: PlaybackException) {
|
|
64
|
-
|
|
78
|
+
// Report playback errors to React Native
|
|
79
|
+
sendEvent("topError", error.message ?: "Unknown error")
|
|
65
80
|
}
|
|
66
81
|
})
|
|
67
82
|
}
|
|
68
83
|
}
|
|
69
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Sets the video source from a URI string and prepares the player.
|
|
87
|
+
* @param uriString Video source URI as a string
|
|
88
|
+
*/
|
|
70
89
|
fun setSource(uriString: String?) {
|
|
71
90
|
if (uriString.isNullOrEmpty()) return
|
|
72
91
|
sourceUri = uriString
|
|
73
92
|
|
|
93
|
+
// Ensure player is initialized
|
|
74
94
|
initializePlayer()
|
|
75
95
|
|
|
96
|
+
// Set and prepare the media item for playback
|
|
76
97
|
val item = MediaItem.fromUri(Uri.parse(uriString))
|
|
77
98
|
exoPlayer?.setMediaItem(item)
|
|
78
99
|
exoPlayer?.prepare()
|
|
79
100
|
}
|
|
80
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Sets the autoplay flag to control whether playback starts when player is ready.
|
|
104
|
+
* @param value Boolean value from JS prop
|
|
105
|
+
*/
|
|
81
106
|
fun setAutoplay(value: Boolean) {
|
|
82
107
|
autoplay = value
|
|
83
108
|
}
|
|
84
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Set the play state of the player.
|
|
112
|
+
* If true, the player will start/resume playback; otherwise, pause.
|
|
113
|
+
* @param value Boolean value from JS prop
|
|
114
|
+
*/
|
|
85
115
|
fun setPlay(value: Boolean) {
|
|
86
116
|
play = value
|
|
87
|
-
//
|
|
88
|
-
// if
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// }
|
|
117
|
+
// Optionally: Disabling autoplay if play is used directly
|
|
118
|
+
// Only play or pause if player is ready
|
|
119
|
+
if (play) {
|
|
120
|
+
exoPlayer?.play()
|
|
121
|
+
} else {
|
|
122
|
+
exoPlayer?.pause()
|
|
123
|
+
}
|
|
95
124
|
}
|
|
96
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Sets the mute state of the player.
|
|
128
|
+
* @param value Boolean indicating if the audio should be muted
|
|
129
|
+
*/
|
|
97
130
|
fun setMute(value: Boolean) {
|
|
98
131
|
mute = value
|
|
99
132
|
exoPlayer?.volume = if (mute) 0f else 1f
|
|
100
133
|
}
|
|
101
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Releases the player and cleans up resources.
|
|
137
|
+
* This should be called when the view is destroyed.
|
|
138
|
+
*/
|
|
102
139
|
fun releasePlayer() {
|
|
103
140
|
exoPlayer?.release()
|
|
104
141
|
exoPlayer = null
|
|
105
142
|
}
|
|
106
143
|
|
|
107
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Helper function to send events and optional data payloads to React Native JS side.
|
|
146
|
+
* @param eventName Name of the event (e.g., "topReady", "topError")
|
|
147
|
+
* @param message Optional message string to pass in the event payload
|
|
148
|
+
*/
|
|
108
149
|
private fun sendEvent(eventName: String, message: String? = null) {
|
|
109
150
|
val reactContext = context as? ReactContext ?: return
|
|
110
|
-
val
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
151
|
+
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
152
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
|
|
153
|
+
val payload = Arguments.createMap()
|
|
154
|
+
message?.let { payload.putString("message", it) }
|
|
155
|
+
eventDispatcher?.dispatchEvent(
|
|
156
|
+
Media3Event(surfaceId, id, eventName, payload)
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Custom event class to bridge native events to React Native UIManager system.
|
|
162
|
+
*/
|
|
163
|
+
private class Media3Event(
|
|
164
|
+
surfaceId: Int,
|
|
165
|
+
viewId: Int,
|
|
166
|
+
private val name: String,
|
|
167
|
+
private val payload: WritableMap
|
|
168
|
+
) : Event<Media3Event>(surfaceId, viewId) {
|
|
169
|
+
override fun getEventName(): String = name
|
|
170
|
+
override fun getEventData(): WritableMap = payload
|
|
115
171
|
}
|
|
116
172
|
}
|
|
@@ -1,61 +1,106 @@
|
|
|
1
1
|
package com.rnmedia3playerdemo
|
|
2
2
|
|
|
3
|
-
import com.facebook.react.bridge.ReactApplicationContext
|
|
4
3
|
import com.facebook.react.bridge.ReadableMap
|
|
4
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
5
5
|
import com.facebook.react.uimanager.SimpleViewManager
|
|
6
6
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
7
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
7
8
|
import com.facebook.react.uimanager.annotations.ReactProp
|
|
9
|
+
import com.facebook.react.viewmanagers.Media3PlayerViewManagerDelegate
|
|
10
|
+
import com.facebook.react.viewmanagers.Media3PlayerViewManagerInterface
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Exposes the native view to React Native.
|
|
13
|
-
* Props: source { uri: string }, autoplay, play, mute
|
|
14
|
-
* Events: onReady, onEnd, onError
|
|
13
|
+
* ViewManager for the custom Media3PlayerView.
|
|
14
|
+
* Responsible for creating the view, handling props from JS, and managing events.
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
@ReactModule(name = Media3PlayerViewManager.NAME)
|
|
17
|
+
class Media3PlayerViewManager :
|
|
18
|
+
SimpleViewManager<Media3PlayerView>(),
|
|
19
|
+
Media3PlayerViewManagerInterface<Media3PlayerView> {
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
companion object {
|
|
22
|
+
// The name used to reference this view manager from JS
|
|
23
|
+
const val NAME = "Media3PlayerView"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Delegate handles communication and prop mapping automatically when generated by Codegen
|
|
27
|
+
private val delegate = Media3PlayerViewManagerDelegate(this)
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns the delegate instance for prop/event mapping.
|
|
31
|
+
*/
|
|
32
|
+
override fun getDelegate(): ViewManagerDelegate<Media3PlayerView> = delegate
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns the unique name for this ViewManager, used by React Native.
|
|
36
|
+
*/
|
|
37
|
+
override fun getName(): String = NAME
|
|
20
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Creates and returns a new Media3PlayerView instance for this ViewManager.
|
|
41
|
+
* @param reactContext ThemedReactContext provided by React Native
|
|
42
|
+
*/
|
|
21
43
|
override fun createViewInstance(reactContext: ThemedReactContext): Media3PlayerView {
|
|
22
44
|
return Media3PlayerView(reactContext)
|
|
23
45
|
}
|
|
24
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Sets the "source" property on the Media3PlayerView.
|
|
49
|
+
* Reads the "uri" string from the passed ReadableMap and loads it into the native view.
|
|
50
|
+
*/
|
|
25
51
|
@ReactProp(name = "source")
|
|
26
|
-
fun setSource(view: Media3PlayerView, source: ReadableMap?) {
|
|
27
|
-
val uri
|
|
52
|
+
override fun setSource(view: Media3PlayerView, source: ReadableMap?) {
|
|
53
|
+
val uri = source?.getString("uri")
|
|
28
54
|
if (!uri.isNullOrEmpty()) {
|
|
29
55
|
view.setSource(uri)
|
|
30
56
|
}
|
|
31
57
|
}
|
|
32
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Sets the "autoplay" property on the Media3PlayerView.
|
|
61
|
+
* Controls whether playback should start automatically when ready.
|
|
62
|
+
*/
|
|
33
63
|
@ReactProp(name = "autoplay", defaultBoolean = false)
|
|
34
|
-
fun setAutoplay(view: Media3PlayerView,
|
|
35
|
-
view.setAutoplay(
|
|
64
|
+
override fun setAutoplay(view: Media3PlayerView, value: Boolean) {
|
|
65
|
+
view.setAutoplay(value)
|
|
36
66
|
}
|
|
37
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Sets the "play" property on the Media3PlayerView.
|
|
70
|
+
* Controls whether the player should be playing or paused.
|
|
71
|
+
*/
|
|
38
72
|
@ReactProp(name = "play", defaultBoolean = false)
|
|
39
|
-
fun setPlay(view: Media3PlayerView,
|
|
40
|
-
view.setPlay(
|
|
73
|
+
override fun setPlay(view: Media3PlayerView, value: Boolean) {
|
|
74
|
+
view.setPlay(value)
|
|
41
75
|
}
|
|
42
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Sets the "mute" property on the Media3PlayerView.
|
|
79
|
+
* Controls whether the audio should be muted.
|
|
80
|
+
*/
|
|
43
81
|
@ReactProp(name = "mute", defaultBoolean = false)
|
|
44
|
-
fun setMute(view: Media3PlayerView,
|
|
45
|
-
view.setMute(
|
|
82
|
+
override fun setMute(view: Media3PlayerView, value: Boolean) {
|
|
83
|
+
view.setMute(value)
|
|
46
84
|
}
|
|
47
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Called when the React Native view instance is about to be dropped/remounted.
|
|
88
|
+
* Ensures resources are released to avoid leaks.
|
|
89
|
+
*/
|
|
48
90
|
override fun onDropViewInstance(view: Media3PlayerView) {
|
|
49
91
|
super.onDropViewInstance(view)
|
|
50
92
|
view.releasePlayer()
|
|
51
93
|
}
|
|
52
94
|
|
|
53
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Exports native direct event types to React Native for event binding in JS.
|
|
97
|
+
* Maps native event names to the registration name expected by React.
|
|
98
|
+
*/
|
|
54
99
|
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
|
|
55
100
|
return mutableMapOf(
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
101
|
+
"topReady" to mapOf("registrationName" to "onReady"),
|
|
102
|
+
"topEnd" to mapOf("registrationName" to "onEnd"),
|
|
103
|
+
"topError" to mapOf("registrationName" to "onError")
|
|
59
104
|
)
|
|
60
105
|
}
|
|
61
106
|
}
|
package/index.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { ViewStyle } from 'react-native';
|
|
2
1
|
import * as React from 'react';
|
|
2
|
+
import {ViewStyle} from 'react-native';
|
|
3
3
|
|
|
4
4
|
export interface Media3PlayerProps {
|
|
5
5
|
style?: ViewStyle | ViewStyle[];
|
|
6
|
-
source: {
|
|
6
|
+
source: {uri: string};
|
|
7
7
|
autoplay?: boolean;
|
|
8
8
|
play?: boolean;
|
|
9
9
|
mute?: boolean;
|
|
10
10
|
onReady?: () => void;
|
|
11
11
|
onEnd?: () => void;
|
|
12
|
-
onError?: (
|
|
12
|
+
onError?: (event: {nativeEvent: {message: string}}) => void;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
declare const Media3Player: React.FC<Media3PlayerProps>;
|
|
16
|
+
export default Media3Player;
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-media3-player",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "React Native Media3 Player component for Android (ExoPlayer 3 integration).",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"react-native": "index.js",
|
|
6
7
|
"types": "index.d.ts",
|
|
7
8
|
"keywords": [
|
|
8
9
|
"react-native",
|
|
@@ -31,5 +32,13 @@
|
|
|
31
32
|
"src",
|
|
32
33
|
"index.js",
|
|
33
34
|
"index.d.ts"
|
|
34
|
-
]
|
|
35
|
+
],
|
|
36
|
+
"codegenConfig": {
|
|
37
|
+
"name": "RNMedia3PlayerSpec",
|
|
38
|
+
"type": "components",
|
|
39
|
+
"jsSrcsDir": "src",
|
|
40
|
+
"android": {
|
|
41
|
+
"javaPackageName": "com.rnmedia3playerdemo"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
35
44
|
}
|
package/src/Media3Player.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const NativeMedia3Player = requireNativeComponent('Media3PlayerView');
|
|
2
|
+
import {StyleSheet} from 'react-native';
|
|
3
|
+
// Import the native codegen-wrapped player view component
|
|
4
|
+
import NativeMedia3PlayerView from './Media3PlayerNativeComponent';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
* Media3Player
|
|
7
|
+
* Media3Player React component
|
|
9
8
|
*
|
|
10
9
|
* Props:
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
15
|
-
* -
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
10
|
+
* - style: (optional) additional style overrides
|
|
11
|
+
* - source: { uri: string } – required, the media URI to load
|
|
12
|
+
* - autoplay: (optional, default false) – whether playback should start automatically when ready
|
|
13
|
+
* - play: (optional, default false) – whether playback should currently be running (true = play, false = pause)
|
|
14
|
+
* - mute: (optional, default false) – whether audio should be muted
|
|
15
|
+
* - onReady: callback when player is ready
|
|
16
|
+
* - onEnd: callback when playback has ended
|
|
17
|
+
* - onError: callback when an error occurs during playback or loading
|
|
18
18
|
*/
|
|
19
19
|
export default function Media3Player({
|
|
20
20
|
style,
|
|
@@ -26,14 +26,16 @@ export default function Media3Player({
|
|
|
26
26
|
onEnd,
|
|
27
27
|
onError,
|
|
28
28
|
}) {
|
|
29
|
+
// Validate that source.uri is provided; warn and render nothing if missing
|
|
29
30
|
if (!source || !source.uri) {
|
|
30
|
-
console.warn('Media3Player: "source
|
|
31
|
+
console.warn('Media3Player: "source.uri" is required.');
|
|
31
32
|
return null;
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
// Render the native player view, passing all relevant props and composing the style
|
|
34
36
|
return (
|
|
35
|
-
<
|
|
36
|
-
style={[styles.default, style]}
|
|
37
|
+
<NativeMedia3PlayerView
|
|
38
|
+
style={[styles.default, style]}
|
|
37
39
|
source={source}
|
|
38
40
|
autoplay={autoplay}
|
|
39
41
|
play={play}
|
|
@@ -45,10 +47,11 @@ export default function Media3Player({
|
|
|
45
47
|
);
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
// Default styling applied to the player view unless overridden via 'style' prop
|
|
48
51
|
const styles = StyleSheet.create({
|
|
49
52
|
default: {
|
|
50
|
-
width: '100%',
|
|
51
|
-
height: 250,
|
|
52
|
-
backgroundColor: 'black',
|
|
53
|
+
width: '100%', // Occupy full width of parent
|
|
54
|
+
height: 250, // Fixed height for the player
|
|
55
|
+
backgroundColor: 'black', // Default background color
|
|
53
56
|
},
|
|
54
57
|
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Import the base ViewProps type from React Native to extend the native component's props
|
|
2
|
+
import type {ViewProps} from 'react-native';
|
|
3
|
+
// Import the DirectEventHandler type used for native-to-JS event callback typings
|
|
4
|
+
import type {DirectEventHandler} from 'react-native/Libraries/Types/CodegenTypes';
|
|
5
|
+
// Import codegenNativeComponent to register the native UI component for use in React Native
|
|
6
|
+
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
|
7
|
+
|
|
8
|
+
// Event type emitted when the player is ready
|
|
9
|
+
type OnReadyEvent = Readonly<{}>;
|
|
10
|
+
// Event type emitted when playback reaches the end
|
|
11
|
+
type OnEndEvent = Readonly<{}>;
|
|
12
|
+
// Event type emitted when an error occurs during playback
|
|
13
|
+
type OnErrorEvent = Readonly<{
|
|
14
|
+
message: string; // Error message describing what went wrong
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
// Props supported by the native Media3PlayerView component
|
|
18
|
+
export interface NativeProps extends ViewProps {
|
|
19
|
+
// Source URI for the media to play
|
|
20
|
+
source?: Readonly<{uri: string}>;
|
|
21
|
+
// Whether playback should start automatically when ready
|
|
22
|
+
autoplay?: boolean;
|
|
23
|
+
// Whether playback should currently be running (true = play, false = pause)
|
|
24
|
+
play?: boolean;
|
|
25
|
+
// Whether audio should be muted
|
|
26
|
+
mute?: boolean;
|
|
27
|
+
|
|
28
|
+
// Callback invoked when the player is ready to play
|
|
29
|
+
onReady?: DirectEventHandler<OnReadyEvent>;
|
|
30
|
+
// Callback invoked when playback reaches the end of the media
|
|
31
|
+
onEnd?: DirectEventHandler<OnEndEvent>;
|
|
32
|
+
// Callback invoked when an error occurs in playback or loading
|
|
33
|
+
onError?: DirectEventHandler<OnErrorEvent>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Create and export the code-generated native component using the props interface
|
|
37
|
+
export default codegenNativeComponent<NativeProps>('Media3PlayerView');
|