bitmovin-player-react-native 0.7.2 → 0.8.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/README.md +2 -17
- package/RNBitmovinPlayer.podspec +3 -3
- package/android/build.gradle +2 -2
- package/android/gradlew +8 -4
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +39 -20
- package/android/src/main/java/com/bitmovin/player/reactnative/ui/FullscreenHandlerModule.kt +5 -0
- package/ios/FullscreenHandlerModule.m +1 -0
- package/ios/FullscreenHandlerModule.swift +5 -0
- package/ios/RNPlayerViewManager.m +1 -0
- package/ios/RNPlayerViewManager.swift +22 -0
- package/lib/index.d.ts +16 -1
- package/lib/index.js +30 -2
- package/lib/index.mjs +31 -3
- package/package.json +4 -2
- package/src/components/PlayerView/index.tsx +44 -4
- package/src/ui/fullscreenhandlerbridge.ts +14 -0
package/README.md
CHANGED
|
@@ -11,11 +11,6 @@ Official React Native bindings for Bitmovin's mobile Player SDKs.
|
|
|
11
11
|
[](https://www.npmjs.com/package/bitmovin-player-react-native)
|
|
12
12
|
|
|
13
13
|
> As the library is under active development, this means certain features from our native SDKs are not yet exposed through these React Native bindings.
|
|
14
|
-
> See [Feature Support](#feature-support) for an overview of the supported features.
|
|
15
|
-
>
|
|
16
|
-
> Not seeing the features you’re looking for?
|
|
17
|
-
> We are accepting community pull requests to this open-source project so please feel free to contribute.
|
|
18
|
-
> or let us know in [our community](https://community.bitmovin.com/c/requests/14) what features we should work on next.
|
|
19
14
|
|
|
20
15
|
- [Bitmovin Player React Native](#bitmovin-player-react-native)
|
|
21
16
|
- [Platform Support](#platform-support)
|
|
@@ -33,24 +28,14 @@ This library requires at least React Native 0.64+ and React 17+ to work properly
|
|
|
33
28
|
- iOS 14.0+
|
|
34
29
|
- tvOS 14.0+
|
|
35
30
|
- Android API Level 21+
|
|
36
|
-
- Android TV API Level
|
|
31
|
+
- Android TV API Level 24+
|
|
37
32
|
- Fire TV FireOS 5.0+
|
|
38
33
|
|
|
39
34
|
Please note that browsers and other browser-like environments such as webOS and Tizen are not supported. For more details regarding Bitmovin Player SDK platform and device support, please refer to the [Supported Platforms & Devices](https://developer.bitmovin.com/playback/docs/supported-platforms-devices-player) page of our documentation.
|
|
40
35
|
|
|
41
36
|
## Feature Support
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
| Feature | State |
|
|
46
|
-
| -------------------------------- | ----------------------------------------- |
|
|
47
|
-
| Playback of DRM-protected assets | :white_check_mark: Available since v0.2.0 |
|
|
48
|
-
| Subtitles & Captions | :white_check_mark: Available since v0.2.0 |
|
|
49
|
-
| Advertising | :white_check_mark: Available since v0.4.0 |
|
|
50
|
-
| Analytics | :white_check_mark: Available since v0.5.0 |
|
|
51
|
-
| Playlist API | :x: Not available |
|
|
52
|
-
| Casting | :x: Not available |
|
|
53
|
-
| Offline Playback | :x: Not available |
|
|
38
|
+
Please refer to the [Features](https://developer.bitmovin.com/playback/docs/react-native-introduction#features) section of our documentation for an up-to-date list of supported Player features.
|
|
54
39
|
|
|
55
40
|
## Documentation
|
|
56
41
|
|
package/RNBitmovinPlayer.podspec
CHANGED
|
@@ -19,9 +19,9 @@ Pod::Spec.new do |s|
|
|
|
19
19
|
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
20
20
|
|
|
21
21
|
s.dependency "React-Core"
|
|
22
|
-
s.dependency "BitmovinPlayer", "3.41.
|
|
22
|
+
s.dependency "BitmovinPlayer", "3.41.2"
|
|
23
23
|
s.dependency "BitmovinAnalyticsCollector/Core", "2.9.4"
|
|
24
24
|
s.dependency "BitmovinAnalyticsCollector/BitmovinPlayer", "2.9.4"
|
|
25
|
-
s.ios.dependency "GoogleAds-IMA-iOS-SDK", "3.
|
|
26
|
-
s.tvos.dependency "GoogleAds-IMA-tvOS-SDK", "4.
|
|
25
|
+
s.ios.dependency "GoogleAds-IMA-iOS-SDK", "3.18.4"
|
|
26
|
+
s.tvos.dependency "GoogleAds-IMA-tvOS-SDK", "4.8.2"
|
|
27
27
|
end
|
package/android/build.gradle
CHANGED
|
@@ -51,10 +51,10 @@ android {
|
|
|
51
51
|
|
|
52
52
|
dependencies {
|
|
53
53
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
|
54
|
-
implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.
|
|
54
|
+
implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.29.0'
|
|
55
55
|
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
|
|
56
56
|
implementation 'com.bitmovin.analytics:collector-bitmovin-player:2.12.1'
|
|
57
|
-
implementation 'com.bitmovin.player:player:3.
|
|
57
|
+
implementation 'com.bitmovin.player:player:3.40.0'
|
|
58
58
|
//noinspection GradleDynamicVersion
|
|
59
59
|
implementation 'com.facebook.react:react-native:+' // From node_modules
|
|
60
60
|
}
|
package/android/gradlew
CHANGED
|
@@ -85,9 +85,6 @@ done
|
|
|
85
85
|
APP_BASE_NAME=${0##*/}
|
|
86
86
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
|
87
87
|
|
|
88
|
-
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
89
|
-
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
90
|
-
|
|
91
88
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
92
89
|
MAX_FD=maximum
|
|
93
90
|
|
|
@@ -133,10 +130,13 @@ location of your Java installation."
|
|
|
133
130
|
fi
|
|
134
131
|
else
|
|
135
132
|
JAVACMD=java
|
|
136
|
-
|
|
133
|
+
if ! command -v java >/dev/null 2>&1
|
|
134
|
+
then
|
|
135
|
+
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
137
136
|
|
|
138
137
|
Please set the JAVA_HOME variable in your environment to match the
|
|
139
138
|
location of your Java installation."
|
|
139
|
+
fi
|
|
140
140
|
fi
|
|
141
141
|
|
|
142
142
|
# Increase the maximum file descriptors if we can.
|
|
@@ -197,6 +197,10 @@ if "$cygwin" || "$msys" ; then
|
|
|
197
197
|
done
|
|
198
198
|
fi
|
|
199
199
|
|
|
200
|
+
|
|
201
|
+
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
202
|
+
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
203
|
+
|
|
200
204
|
# Collect all arguments for the java command;
|
|
201
205
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
|
202
206
|
# shell script including quotes and variable substitutions, so put them in
|
|
@@ -24,10 +24,11 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
|
|
|
24
24
|
/**
|
|
25
25
|
* Native component functions.
|
|
26
26
|
*/
|
|
27
|
-
enum class Commands {
|
|
28
|
-
ATTACH_PLAYER,
|
|
29
|
-
ATTACH_FULLSCREEN_BRIDGE,
|
|
30
|
-
SET_CUSTOM_MESSAGE_HANDLER_BRIDGE_ID,
|
|
27
|
+
enum class Commands(val command: String) {
|
|
28
|
+
ATTACH_PLAYER("attachPlayer"),
|
|
29
|
+
ATTACH_FULLSCREEN_BRIDGE("attachFullscreenBridge"),
|
|
30
|
+
SET_CUSTOM_MESSAGE_HANDLER_BRIDGE_ID("setCustomMessageHandlerBridgeId"),
|
|
31
|
+
SET_FULLSCREEN("setFullscreen");
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
|
@@ -132,11 +133,9 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
|
|
|
132
133
|
* to call 'functions' on them.
|
|
133
134
|
* @return map between names (used in js) and command ids (used in native code).
|
|
134
135
|
*/
|
|
135
|
-
override fun getCommandsMap():
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"setCustomMessageHandlerBridgeId" to Commands.SET_CUSTOM_MESSAGE_HANDLER_BRIDGE_ID.ordinal,
|
|
139
|
-
)
|
|
136
|
+
override fun getCommandsMap(): Map<String, Int> = Commands.values().associate {
|
|
137
|
+
it.command to it.ordinal
|
|
138
|
+
}
|
|
140
139
|
|
|
141
140
|
/**
|
|
142
141
|
* Callback triggered in response to command dispatches from the js side.
|
|
@@ -145,19 +144,23 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
|
|
|
145
144
|
* @param args Arguments list sent from the js side.
|
|
146
145
|
*/
|
|
147
146
|
override fun receiveCommand(view: RNPlayerView, commandId: String?, args: ReadableArray?) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
val command = commandId?.toInt()?.toCommand() ?: throw IllegalArgumentException(
|
|
148
|
+
"The received command is not supported by the Bitmovin Player View"
|
|
149
|
+
)
|
|
150
|
+
when (command) {
|
|
151
|
+
Commands.ATTACH_PLAYER -> attachPlayer(view, args?.getString(1), args?.getMap(2))
|
|
152
|
+
Commands.ATTACH_FULLSCREEN_BRIDGE -> args?.getString(1)?.let { fullscreenBridgeId ->
|
|
153
|
+
attachFullscreenBridge(view, fullscreenBridgeId)
|
|
154
|
+
}
|
|
155
|
+
Commands.SET_CUSTOM_MESSAGE_HANDLER_BRIDGE_ID -> {
|
|
156
|
+
args?.getString(1)?.let { customMessageHandlerBridgeId ->
|
|
157
|
+
setCustomMessageHandlerBridgeId(view, customMessageHandlerBridgeId)
|
|
154
158
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
+
}
|
|
160
|
+
Commands.SET_FULLSCREEN -> {
|
|
161
|
+
args?.getBoolean(1)?.let { isFullscreen ->
|
|
162
|
+
setFullscreen(view, isFullscreen)
|
|
159
163
|
}
|
|
160
|
-
else -> {}
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
}
|
|
@@ -170,6 +173,20 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
|
|
|
170
173
|
}
|
|
171
174
|
}
|
|
172
175
|
|
|
176
|
+
private fun setFullscreen(view: RNPlayerView, isFullscreen: Boolean) {
|
|
177
|
+
if (view.playerView?.isFullscreen == isFullscreen) return
|
|
178
|
+
|
|
179
|
+
Handler(Looper.getMainLooper()).post {
|
|
180
|
+
with(view.playerView ?: return@post) {
|
|
181
|
+
if (isFullscreen) {
|
|
182
|
+
enterFullscreen()
|
|
183
|
+
} else {
|
|
184
|
+
exitFullscreen()
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
173
190
|
private fun setCustomMessageHandlerBridgeId(view: RNPlayerView, customMessageHandlerBridgeId: NativeId) {
|
|
174
191
|
this.customMessageHandlerBridgeId = customMessageHandlerBridgeId
|
|
175
192
|
attachCustomMessageHandlerBridge(view)
|
|
@@ -223,3 +240,5 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
|
|
|
223
240
|
*/
|
|
224
241
|
private fun getPlayerModule(): PlayerModule? = context.getModule()
|
|
225
242
|
}
|
|
243
|
+
|
|
244
|
+
private fun Int.toCommand(): RNPlayerViewManager.Commands? = RNPlayerViewManager.Commands.values().getOrNull(this)
|
|
@@ -66,6 +66,11 @@ class FullscreenHandlerModule(private val context: ReactApplicationContext) : Re
|
|
|
66
66
|
this.fullscreenHandler[nativeId] = fullscreenHandler
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
@ReactMethod
|
|
70
|
+
fun setIsFullscreenActive(nativeId: NativeId, isFullscreenActive: Boolean) {
|
|
71
|
+
fullscreenHandler[nativeId]?.isFullscreen = isFullscreenActive
|
|
72
|
+
}
|
|
73
|
+
|
|
69
74
|
@ReactMethod
|
|
70
75
|
fun destroy(nativeId: NativeId) {
|
|
71
76
|
fullscreenHandler.remove(nativeId)
|
|
@@ -6,4 +6,5 @@ RCT_EXTERN_METHOD(destroy:(NSString *)nativeId)
|
|
|
6
6
|
|
|
7
7
|
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(onFullscreenChanged:(NSString *)nativeId isFullscreenEnabled:(BOOL)isFullscreenEnabled)
|
|
8
8
|
RCT_EXTERN_METHOD(registerHandler:(NSString *)nativeId)
|
|
9
|
+
RCT_EXTERN_METHOD(setIsFullscreenActive:(NSString *)nativeId isFullscreen:(BOOL)isFullscreen)
|
|
9
10
|
@end
|
|
@@ -57,6 +57,11 @@ class FullscreenHandlerModule: NSObject, RCTBridgeModule {
|
|
|
57
57
|
fullscreenHandlers[nativeId] = FullscreenHandlerBridge(nativeId, bridge: bridge)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
@objc(setIsFullscreenActive:isFullscreen:)
|
|
61
|
+
func setIsFullscreenActive(_ nativeId: NativeId, isFullscreen: Bool) {
|
|
62
|
+
fullscreenHandlers[nativeId]?.isFullscreen = isFullscreen
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
func onFullscreenRequested(nativeId: NativeId) {
|
|
61
66
|
fullscreenChangeDispatchGroup.enter()
|
|
62
67
|
bridge.enqueueJSCall("FullscreenBridge-\(nativeId)", method: "enterFullscreen", args: []) {}
|
|
@@ -56,5 +56,6 @@ RCT_EXPORT_VIEW_PROPERTY(onFullscreenExit, RCTBubblingEventBlock)
|
|
|
56
56
|
RCT_EXTERN_METHOD(attachPlayer:(nonnull NSNumber *)viewId playerId:(NSString *)playerId playerConfig:(nullable NSDictionary *)playerConfig)
|
|
57
57
|
RCT_EXTERN_METHOD(attachFullscreenBridge:(nonnull NSNumber *)viewId fullscreenBridgeId:(NSString *)fullscreenBridgeId)
|
|
58
58
|
RCT_EXTERN_METHOD(setCustomMessageHandlerBridgeId:(nonnull NSNumber *)viewId customMessageHandlerBridgeId:(NSString *)fullscreenBridgeId)
|
|
59
|
+
RCT_EXTERN_METHOD(setFullscreen:(nonnull NSNumber *)viewId isFullscreen:(BOOL)isFullscreen)
|
|
59
60
|
|
|
60
61
|
@end
|
|
@@ -71,6 +71,28 @@ class RNPlayerViewManager: RCTViewManager {
|
|
|
71
71
|
self.customMessageHandlerBridgeId = customMessageHandlerBridgeId
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
@objc func setFullscreen(_ viewId: NSNumber, isFullscreen: Bool) {
|
|
75
|
+
bridge.uiManager.addUIBlock { [weak self] _, views in
|
|
76
|
+
guard
|
|
77
|
+
let self,
|
|
78
|
+
let view = views?[viewId] as? RNPlayerView
|
|
79
|
+
else {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
guard let playerView = view.playerView else {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
guard playerView.isFullscreen != isFullscreen else {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
if isFullscreen {
|
|
89
|
+
playerView.enterFullscreen()
|
|
90
|
+
} else {
|
|
91
|
+
playerView.exitFullscreen()
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
74
96
|
/// Fetches the initialized `PlayerModule` instance on RN's bridge object.
|
|
75
97
|
private func getPlayerModule() -> PlayerModule? {
|
|
76
98
|
bridge.module(for: PlayerModule.self) as? PlayerModule
|
package/lib/index.d.ts
CHANGED
|
@@ -2174,14 +2174,29 @@ interface PlayerViewProps extends BasePlayerViewProps, PlayerViewEvents {
|
|
|
2174
2174
|
* and render audio/video inside the `PlayerView`.
|
|
2175
2175
|
*/
|
|
2176
2176
|
player: Player;
|
|
2177
|
+
/**
|
|
2178
|
+
* The `FullscreenHandler` that is used by the `PlayerView` to control the fullscreen mode.
|
|
2179
|
+
*/
|
|
2177
2180
|
fullscreenHandler?: FullscreenHandler;
|
|
2181
|
+
/**
|
|
2182
|
+
* The `CustomMessageHandler` that can be used to directly communicate with the embedded WebUi.
|
|
2183
|
+
*/
|
|
2178
2184
|
customMessageHandler?: CustomMessageHandler;
|
|
2185
|
+
/**
|
|
2186
|
+
* Can be set to `true` to request fullscreen mode, or `false` to request exit of fullscreen mode.
|
|
2187
|
+
* Should not be used to get the current fullscreen state. Use `onFullscreenEnter` and `onFullscreenExit`
|
|
2188
|
+
* or the `FullscreenHandler.isFullscreenActive` property to get the current state.
|
|
2189
|
+
* Using this property to change the fullscreen state, it is ensured that the embedded Player UI is also aware
|
|
2190
|
+
* of potential fullscreen state changes.
|
|
2191
|
+
* To use this property, a `FullscreenHandler` must be set.
|
|
2192
|
+
*/
|
|
2193
|
+
isFullscreenRequested?: Boolean;
|
|
2179
2194
|
}
|
|
2180
2195
|
/**
|
|
2181
2196
|
* Component that provides the Bitmovin Player UI and default UI handling to an attached `Player` instance.
|
|
2182
2197
|
* This component needs a `Player` instance to work properly so make sure one is passed to it as a prop.
|
|
2183
2198
|
*/
|
|
2184
|
-
declare function PlayerView({ style, player, fullscreenHandler, customMessageHandler, ...props }: PlayerViewProps): JSX.Element;
|
|
2199
|
+
declare function PlayerView({ style, player, fullscreenHandler, customMessageHandler, isFullscreenRequested, ...props }: PlayerViewProps): JSX.Element;
|
|
2185
2200
|
|
|
2186
2201
|
/**
|
|
2187
2202
|
* React hook that creates and returns a reference to a `Player` instance
|
package/lib/index.js
CHANGED
|
@@ -186,6 +186,16 @@ var FullscreenHandlerBridge = class {
|
|
|
186
186
|
);
|
|
187
187
|
FullscreenHandlerModule.registerHandler(this.nativeId);
|
|
188
188
|
}
|
|
189
|
+
setFullscreenHandler(fullscreenHandler) {
|
|
190
|
+
if (this.fullscreenHandler === fullscreenHandler) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
this.fullscreenHandler = fullscreenHandler;
|
|
194
|
+
FullscreenHandlerModule.setIsFullscreenActive(
|
|
195
|
+
this.nativeId,
|
|
196
|
+
fullscreenHandler?.isFullscreenActive ?? false
|
|
197
|
+
);
|
|
198
|
+
}
|
|
189
199
|
destroy() {
|
|
190
200
|
if (!this.isDestroyed) {
|
|
191
201
|
FullscreenHandlerModule.destroy(this.nativeId);
|
|
@@ -273,8 +283,19 @@ function PlayerView({
|
|
|
273
283
|
player,
|
|
274
284
|
fullscreenHandler,
|
|
275
285
|
customMessageHandler,
|
|
286
|
+
isFullscreenRequested = false,
|
|
276
287
|
...props
|
|
277
288
|
}) {
|
|
289
|
+
const fakeStateUpdater = (0, import_react2.useState)(1)[1];
|
|
290
|
+
const workaroundViewManagerCommandNotSent = (0, import_react2.useCallback)(() => {
|
|
291
|
+
setTimeout(
|
|
292
|
+
() => fakeStateUpdater((i) => {
|
|
293
|
+
console.log("Workaround #163");
|
|
294
|
+
return i + 1;
|
|
295
|
+
}),
|
|
296
|
+
100
|
|
297
|
+
);
|
|
298
|
+
}, [fakeStateUpdater]);
|
|
278
299
|
const nativeView = (0, import_react2.useRef)(null);
|
|
279
300
|
const proxy = useProxy(nativeView);
|
|
280
301
|
const nativeViewStyle = import_react_native8.StyleSheet.flatten([styles.baseStyle, style]);
|
|
@@ -283,7 +304,7 @@ function PlayerView({
|
|
|
283
304
|
fullscreenBridge.current = new FullscreenHandlerBridge();
|
|
284
305
|
}
|
|
285
306
|
if (fullscreenBridge.current) {
|
|
286
|
-
fullscreenBridge.current.fullscreenHandler
|
|
307
|
+
fullscreenBridge.current.setFullscreenHandler(fullscreenHandler);
|
|
287
308
|
}
|
|
288
309
|
const customMessageHandlerBridge = (0, import_react2.useRef)(void 0);
|
|
289
310
|
if (customMessageHandler && !customMessageHandlerBridge.current) {
|
|
@@ -313,6 +334,7 @@ function PlayerView({
|
|
|
313
334
|
fullscreenBridge.current.nativeId
|
|
314
335
|
);
|
|
315
336
|
}
|
|
337
|
+
workaroundViewManagerCommandNotSent();
|
|
316
338
|
}
|
|
317
339
|
return () => {
|
|
318
340
|
fullscreenBridge.current?.destroy();
|
|
@@ -320,7 +342,13 @@ function PlayerView({
|
|
|
320
342
|
customMessageHandlerBridge.current?.destroy();
|
|
321
343
|
customMessageHandlerBridge.current = void 0;
|
|
322
344
|
};
|
|
323
|
-
}, [player]);
|
|
345
|
+
}, [player, workaroundViewManagerCommandNotSent]);
|
|
346
|
+
(0, import_react2.useEffect)(() => {
|
|
347
|
+
const node = (0, import_react_native8.findNodeHandle)(nativeView.current);
|
|
348
|
+
if (node) {
|
|
349
|
+
dispatch("setFullscreen", node, isFullscreenRequested);
|
|
350
|
+
}
|
|
351
|
+
}, [isFullscreenRequested, nativeView]);
|
|
324
352
|
return /* @__PURE__ */ import_react2.default.createElement(NativePlayerView, {
|
|
325
353
|
ref: nativeView,
|
|
326
354
|
style: nativeViewStyle,
|
package/lib/index.mjs
CHANGED
|
@@ -98,7 +98,7 @@ var AudioSession = {
|
|
|
98
98
|
};
|
|
99
99
|
|
|
100
100
|
// src/components/PlayerView/index.tsx
|
|
101
|
-
import React, { useRef, useEffect } from "react";
|
|
101
|
+
import React, { useRef, useEffect, useState, useCallback as useCallback2 } from "react";
|
|
102
102
|
import {
|
|
103
103
|
Platform,
|
|
104
104
|
UIManager,
|
|
@@ -147,6 +147,16 @@ var FullscreenHandlerBridge = class {
|
|
|
147
147
|
);
|
|
148
148
|
FullscreenHandlerModule.registerHandler(this.nativeId);
|
|
149
149
|
}
|
|
150
|
+
setFullscreenHandler(fullscreenHandler) {
|
|
151
|
+
if (this.fullscreenHandler === fullscreenHandler) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
this.fullscreenHandler = fullscreenHandler;
|
|
155
|
+
FullscreenHandlerModule.setIsFullscreenActive(
|
|
156
|
+
this.nativeId,
|
|
157
|
+
fullscreenHandler?.isFullscreenActive ?? false
|
|
158
|
+
);
|
|
159
|
+
}
|
|
150
160
|
destroy() {
|
|
151
161
|
if (!this.isDestroyed) {
|
|
152
162
|
FullscreenHandlerModule.destroy(this.nativeId);
|
|
@@ -234,8 +244,19 @@ function PlayerView({
|
|
|
234
244
|
player,
|
|
235
245
|
fullscreenHandler,
|
|
236
246
|
customMessageHandler,
|
|
247
|
+
isFullscreenRequested = false,
|
|
237
248
|
...props
|
|
238
249
|
}) {
|
|
250
|
+
const fakeStateUpdater = useState(1)[1];
|
|
251
|
+
const workaroundViewManagerCommandNotSent = useCallback2(() => {
|
|
252
|
+
setTimeout(
|
|
253
|
+
() => fakeStateUpdater((i) => {
|
|
254
|
+
console.log("Workaround #163");
|
|
255
|
+
return i + 1;
|
|
256
|
+
}),
|
|
257
|
+
100
|
|
258
|
+
);
|
|
259
|
+
}, [fakeStateUpdater]);
|
|
239
260
|
const nativeView = useRef(null);
|
|
240
261
|
const proxy = useProxy(nativeView);
|
|
241
262
|
const nativeViewStyle = StyleSheet.flatten([styles.baseStyle, style]);
|
|
@@ -244,7 +265,7 @@ function PlayerView({
|
|
|
244
265
|
fullscreenBridge.current = new FullscreenHandlerBridge();
|
|
245
266
|
}
|
|
246
267
|
if (fullscreenBridge.current) {
|
|
247
|
-
fullscreenBridge.current.fullscreenHandler
|
|
268
|
+
fullscreenBridge.current.setFullscreenHandler(fullscreenHandler);
|
|
248
269
|
}
|
|
249
270
|
const customMessageHandlerBridge = useRef(void 0);
|
|
250
271
|
if (customMessageHandler && !customMessageHandlerBridge.current) {
|
|
@@ -274,6 +295,7 @@ function PlayerView({
|
|
|
274
295
|
fullscreenBridge.current.nativeId
|
|
275
296
|
);
|
|
276
297
|
}
|
|
298
|
+
workaroundViewManagerCommandNotSent();
|
|
277
299
|
}
|
|
278
300
|
return () => {
|
|
279
301
|
fullscreenBridge.current?.destroy();
|
|
@@ -281,7 +303,13 @@ function PlayerView({
|
|
|
281
303
|
customMessageHandlerBridge.current?.destroy();
|
|
282
304
|
customMessageHandlerBridge.current = void 0;
|
|
283
305
|
};
|
|
284
|
-
}, [player]);
|
|
306
|
+
}, [player, workaroundViewManagerCommandNotSent]);
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
const node = findNodeHandle2(nativeView.current);
|
|
309
|
+
if (node) {
|
|
310
|
+
dispatch("setFullscreen", node, isFullscreenRequested);
|
|
311
|
+
}
|
|
312
|
+
}, [isFullscreenRequested, nativeView]);
|
|
285
313
|
return /* @__PURE__ */ React.createElement(NativePlayerView, {
|
|
286
314
|
ref: nativeView,
|
|
287
315
|
style: nativeViewStyle,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bitmovin-player-react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Official React Native bindings for Bitmovin's mobile Player SDKs.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib/index.mjs",
|
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
"format": "prettier --write .",
|
|
29
29
|
"build": "tsup ./src/index.ts --dts --target es2020 --format cjs,esm -d lib",
|
|
30
30
|
"example": "yarn --cwd example",
|
|
31
|
-
"pods": "
|
|
31
|
+
"pods": "yarn pods-install || yarn pods-install --repo-update || yarn pods-update",
|
|
32
|
+
"pods-install": "cd example/ios && bundle install && bundle exec pod install --silent",
|
|
33
|
+
"pods-update": "cd example/ios && bundle install && bundle exec pod update --silent",
|
|
32
34
|
"bootstrap": "yarn && yarn example && yarn pods",
|
|
33
35
|
"prepare": "husky install"
|
|
34
36
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useRef, useEffect } from 'react';
|
|
1
|
+
import React, { useRef, useEffect, useState, useCallback } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Platform,
|
|
4
4
|
UIManager,
|
|
@@ -35,9 +35,25 @@ export interface PlayerViewProps extends BasePlayerViewProps, PlayerViewEvents {
|
|
|
35
35
|
*/
|
|
36
36
|
player: Player;
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* The `FullscreenHandler` that is used by the `PlayerView` to control the fullscreen mode.
|
|
40
|
+
*/
|
|
38
41
|
fullscreenHandler?: FullscreenHandler;
|
|
39
42
|
|
|
43
|
+
/**
|
|
44
|
+
* The `CustomMessageHandler` that can be used to directly communicate with the embedded WebUi.
|
|
45
|
+
*/
|
|
40
46
|
customMessageHandler?: CustomMessageHandler;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Can be set to `true` to request fullscreen mode, or `false` to request exit of fullscreen mode.
|
|
50
|
+
* Should not be used to get the current fullscreen state. Use `onFullscreenEnter` and `onFullscreenExit`
|
|
51
|
+
* or the `FullscreenHandler.isFullscreenActive` property to get the current state.
|
|
52
|
+
* Using this property to change the fullscreen state, it is ensured that the embedded Player UI is also aware
|
|
53
|
+
* of potential fullscreen state changes.
|
|
54
|
+
* To use this property, a `FullscreenHandler` must be set.
|
|
55
|
+
*/
|
|
56
|
+
isFullscreenRequested?: Boolean;
|
|
41
57
|
}
|
|
42
58
|
|
|
43
59
|
/**
|
|
@@ -73,9 +89,20 @@ export function PlayerView({
|
|
|
73
89
|
player,
|
|
74
90
|
fullscreenHandler,
|
|
75
91
|
customMessageHandler,
|
|
92
|
+
isFullscreenRequested = false,
|
|
76
93
|
...props
|
|
77
94
|
}: PlayerViewProps) {
|
|
78
|
-
|
|
95
|
+
const fakeStateUpdater = useState(1)[1];
|
|
96
|
+
const workaroundViewManagerCommandNotSent = useCallback(() => {
|
|
97
|
+
setTimeout(
|
|
98
|
+
() =>
|
|
99
|
+
fakeStateUpdater((i) => {
|
|
100
|
+
console.log('Workaround #163'); // Player will not load 1/10th if this log is removed :((((
|
|
101
|
+
return i + 1;
|
|
102
|
+
}),
|
|
103
|
+
100
|
|
104
|
+
);
|
|
105
|
+
}, [fakeStateUpdater]);
|
|
79
106
|
const nativeView = useRef(null);
|
|
80
107
|
// Native events proxy helper.
|
|
81
108
|
const proxy = useProxy(nativeView);
|
|
@@ -89,7 +116,7 @@ export function PlayerView({
|
|
|
89
116
|
fullscreenBridge.current = new FullscreenHandlerBridge();
|
|
90
117
|
}
|
|
91
118
|
if (fullscreenBridge.current) {
|
|
92
|
-
fullscreenBridge.current.fullscreenHandler
|
|
119
|
+
fullscreenBridge.current.setFullscreenHandler(fullscreenHandler);
|
|
93
120
|
}
|
|
94
121
|
|
|
95
122
|
const customMessageHandlerBridge: React.MutableRefObject<
|
|
@@ -127,14 +154,27 @@ export function PlayerView({
|
|
|
127
154
|
fullscreenBridge.current.nativeId
|
|
128
155
|
);
|
|
129
156
|
}
|
|
157
|
+
// Workaround React Native Command not sent until UI refresh
|
|
158
|
+
// See: https://github.com/bitmovin/bitmovin-player-react-native/issues/163
|
|
159
|
+
// Seems to be a dup of https://github.com/microsoft/react-native-windows/issues/7543
|
|
160
|
+
// Remove the workaround when React Native is updated
|
|
161
|
+
workaroundViewManagerCommandNotSent();
|
|
130
162
|
}
|
|
163
|
+
|
|
131
164
|
return () => {
|
|
132
165
|
fullscreenBridge.current?.destroy();
|
|
133
166
|
fullscreenBridge.current = undefined;
|
|
134
167
|
customMessageHandlerBridge.current?.destroy();
|
|
135
168
|
customMessageHandlerBridge.current = undefined;
|
|
136
169
|
};
|
|
137
|
-
}, [player]);
|
|
170
|
+
}, [player, workaroundViewManagerCommandNotSent]);
|
|
171
|
+
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
const node = findNodeHandle(nativeView.current);
|
|
174
|
+
if (node) {
|
|
175
|
+
dispatch('setFullscreen', node, isFullscreenRequested);
|
|
176
|
+
}
|
|
177
|
+
}, [isFullscreenRequested, nativeView]);
|
|
138
178
|
return (
|
|
139
179
|
<NativePlayerView
|
|
140
180
|
ref={nativeView}
|
|
@@ -23,6 +23,20 @@ export class FullscreenHandlerBridge {
|
|
|
23
23
|
FullscreenHandlerModule.registerHandler(this.nativeId);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
setFullscreenHandler(fullscreenHandler: FullscreenHandler | undefined) {
|
|
27
|
+
if (this.fullscreenHandler === fullscreenHandler) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.fullscreenHandler = fullscreenHandler;
|
|
32
|
+
|
|
33
|
+
// synchronize current state from fullscreenHandler to native
|
|
34
|
+
FullscreenHandlerModule.setIsFullscreenActive(
|
|
35
|
+
this.nativeId,
|
|
36
|
+
fullscreenHandler?.isFullscreenActive ?? false
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
/**
|
|
27
41
|
* Destroys the native FullscreenHandler
|
|
28
42
|
*/
|