bitmovin-player-react-native 0.11.0 → 0.13.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 +27 -14
- package/RNBitmovinPlayer.podspec +1 -1
- package/android/.editorconfig +8 -0
- package/android/build.gradle +8 -2
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/BitmovinCastManagerModule.kt +76 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/DrmModule.kt +4 -4
- package/android/src/main/java/com/bitmovin/player/reactnative/EventRelay.kt +1 -1
- package/android/src/main/java/com/bitmovin/player/reactnative/OfflineModule.kt +22 -11
- package/android/src/main/java/com/bitmovin/player/reactnative/PlayerAnalyticsModule.kt +58 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/PlayerModule.kt +80 -1
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerView.kt +36 -5
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +71 -29
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt +6 -3
- package/android/src/main/java/com/bitmovin/player/reactnative/SourceModule.kt +55 -17
- package/android/src/main/java/com/bitmovin/player/reactnative/UuidModule.kt +1 -1
- package/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +387 -165
- package/android/src/main/java/com/bitmovin/player/reactnative/extensions/ReadableMapExtension.kt +19 -1
- package/android/src/main/java/com/bitmovin/player/reactnative/extensions/WritableMap.kt +8 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/offline/OfflineContentManagerBridge.kt +39 -22
- package/android/src/main/java/com/bitmovin/player/reactnative/offline/OfflineDownloadRequest.kt +1 -1
- package/android/src/main/java/com/bitmovin/player/reactnative/ui/CustomMessageHandlerBridge.kt +9 -7
- package/android/src/main/java/com/bitmovin/player/reactnative/ui/CustomMessageHandlerModule.kt +6 -6
- package/android/src/main/java/com/bitmovin/player/reactnative/ui/FullscreenHandlerBridge.kt +1 -1
- package/android/src/main/java/com/bitmovin/player/reactnative/ui/FullscreenHandlerModule.kt +4 -4
- package/android/src/main/java/com/bitmovin/player/reactnative/ui/RNPictureInPictureHandler.kt +14 -5
- package/ios/AudioSessionModule.swift +9 -9
- package/ios/BitmovinCastManagerModule.m +14 -0
- package/ios/BitmovinCastManagerModule.swift +82 -0
- package/ios/CustomMessageHandlerBridge.swift +11 -3
- package/ios/CustomMessageHandlerModule.swift +20 -12
- package/ios/DrmModule.swift +58 -37
- package/ios/Event+JSON.swift +28 -7
- package/ios/FullscreenHandlerBridge.swift +1 -1
- package/ios/FullscreenHandlerModule.swift +10 -10
- package/ios/OfflineContentManagerBridge.swift +53 -24
- package/ios/OfflineModule.swift +46 -35
- package/ios/PlayerAnalyticsModule.m +8 -0
- package/ios/PlayerAnalyticsModule.swift +66 -0
- package/ios/PlayerModule.m +11 -0
- package/ios/PlayerModule.swift +122 -18
- package/ios/RCTConvert+BitmovinPlayer.swift +355 -129
- package/ios/RNPlayerView+PlayerListener.swift +80 -43
- package/ios/RNPlayerView+UserInterfaceListener.swift +8 -8
- package/ios/RNPlayerView.swift +13 -2
- package/ios/RNPlayerViewManager.m +13 -0
- package/ios/RNPlayerViewManager.swift +114 -33
- package/ios/Registry.swift +2 -2
- package/ios/SourceModule.m +9 -2
- package/ios/SourceModule.swift +81 -20
- package/ios/UuidModule.swift +6 -5
- package/lib/index.d.mts +1192 -576
- package/lib/index.d.ts +1192 -576
- package/lib/index.js +233 -170
- package/lib/index.mjs +219 -155
- package/package.json +9 -6
- package/src/advertising.ts +18 -0
- package/src/analytics/config.ts +48 -64
- package/src/analytics/index.ts +1 -1
- package/src/analytics/player.ts +36 -0
- package/src/bitmovinCastManager.ts +87 -0
- package/src/bufferConfig.ts +42 -0
- package/src/components/PlayerView/events.ts +237 -0
- package/src/components/PlayerView/index.tsx +31 -45
- package/src/components/PlayerView/native.ts +1 -1
- package/src/components/PlayerView/pictureInPictureConfig.ts +22 -0
- package/src/components/PlayerView/playerViewConfig.ts +38 -0
- package/src/components/PlayerView/properties.ts +66 -0
- package/src/components/index.ts +3 -0
- package/src/drm/index.ts +7 -2
- package/src/drm/widevineConfig.ts +11 -3
- package/src/events.ts +112 -20
- package/src/hooks/usePlayer.ts +2 -1
- package/src/index.ts +8 -0
- package/src/offline/offlineContentManager.ts +33 -4
- package/src/offline/offlineContentManagerListener.ts +45 -29
- package/src/playbackConfig.ts +77 -0
- package/src/player.ts +56 -141
- package/src/playerConfig.ts +66 -0
- package/src/remoteControlConfig.ts +37 -0
- package/src/source.ts +42 -5
- package/src/subtitleTrack.ts +8 -11
- package/src/tweaksConfig.ts +8 -8
- package/src/ui/custommessagehandler.ts +33 -12
- package/src/ui/custommessagehandlerbridge.ts +2 -0
- package/src/ui/custommessagesender.ts +1 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/AnalyticsModule.kt +0 -196
- package/ios/AnalyticsModule.m +0 -15
- package/ios/AnalyticsModule.swift +0 -219
- package/src/analytics/collector.ts +0 -119
- package/src/utils.ts +0 -15
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bitmovin Player React Native
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This is an open-source project created to enable customers to integrate the Bitmovin mobile Player SDKs into React Native projects. It has been created to provide customers with a starting point, which can be built upon through active collaboration and contributions. We look forward to seeing this library expand and grow.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/bitmovin/bitmovin-player-react-native/actions/workflows/ci.yml)
|
|
6
6
|

|
|
@@ -10,17 +10,6 @@ Official React Native bindings for Bitmovin's mobile Player SDKs.
|
|
|
10
10
|
[](https://www.npmjs.com/package/bitmovin-player-react-native)
|
|
11
11
|
[](https://www.npmjs.com/package/bitmovin-player-react-native)
|
|
12
12
|
|
|
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
|
-
|
|
15
|
-
- [Bitmovin Player React Native](#bitmovin-player-react-native)
|
|
16
|
-
- [Platform Support](#platform-support)
|
|
17
|
-
- [Feature Support](#feature-support)
|
|
18
|
-
- [Documentation](#documentation)
|
|
19
|
-
- [Getting Started](#getting-started-guide)
|
|
20
|
-
- [Feature Guides](#feature-guides)
|
|
21
|
-
- [Sample Application](#sample-application)
|
|
22
|
-
- [Contributing](#contributing)
|
|
23
|
-
|
|
24
13
|
## Platform Support
|
|
25
14
|
|
|
26
15
|
This library requires at least React Native 0.64+ and React 17+ to work properly. The currently supported platforms are:
|
|
@@ -39,6 +28,10 @@ Please refer to the [Features](https://developer.bitmovin.com/playback/docs/reac
|
|
|
39
28
|
|
|
40
29
|
## Documentation
|
|
41
30
|
|
|
31
|
+
### API Reference
|
|
32
|
+
|
|
33
|
+
Our API reference can be found [here](https://cdn.bitmovin.com/player/reactnative/0/docs/index.html).
|
|
34
|
+
|
|
42
35
|
### Getting Started Guide
|
|
43
36
|
|
|
44
37
|
Our [Getting Started Guide](https://developer.bitmovin.com/playback/docs/getting-started-react-native) walks you through setting up and configuring the Bitmovin Player in React Native projects.
|
|
@@ -51,6 +44,26 @@ Check out our [React Native Guides](https://developer.bitmovin.com/playback/docs
|
|
|
51
44
|
|
|
52
45
|
In the [/example/](https://github.com/bitmovin/bitmovin-player-react-native/tree/development/example) folder you can find a sample application showcasing many of the features of the Player React Native SDK.
|
|
53
46
|
|
|
54
|
-
##
|
|
47
|
+
## Maintenance and Updates
|
|
48
|
+
|
|
49
|
+
As an open source project, this library is not part of a regular maintenance or update schedule and is updated on an adhoc basis when contributions are made.
|
|
50
|
+
|
|
51
|
+
## Contributing to this project
|
|
52
|
+
|
|
53
|
+
We are pleased to accept changes, updates and fixes from the community wishing to use and expand this project. Bitmovin will review any Pull Requests made. We do our best to provide timely feedback, but please note that no SLAs apply. New releases are tagged and published on our discretion. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for more details on how to contribute.
|
|
54
|
+
|
|
55
|
+
## Raising a Feature Suggestion
|
|
56
|
+
|
|
57
|
+
If you see something missing that might be useful but are unable to contribute the feature yourself, please feel free to [submit a feature request](https://community.bitmovin.com/t/how-to-submit-a-feature-request-to-us/1463) through the Bitmovin Community. Feature suggestions will be considered by Bitmovin’s Product team for future roadmap plans.
|
|
58
|
+
|
|
59
|
+
## Reporting a bug
|
|
60
|
+
|
|
61
|
+
If you come across a bug related to the Player React Native SDK, please raise this through the support ticketing system accessible in your [Bitmovin Dashboard](https://dashboard.bitmovin.com/support/tickets).
|
|
62
|
+
|
|
63
|
+
## Support and SLA Disclaimer
|
|
64
|
+
|
|
65
|
+
As an open-source project and not a core product offering, any request, issue or query related to this project is excluded from any SLA and Support terms that a customer might have with either Bitmovin or another third-party service provider or Company contributing to this project. Any and all updates are purely at the contributor's discretion.
|
|
66
|
+
|
|
67
|
+
## Need more help?
|
|
55
68
|
|
|
56
|
-
|
|
69
|
+
Should you need further help, please raise your request to your Bitmovin account team. We can assist in a number of ways, from providing you professional services help to putting you in touch with preferred system integrators who can work with you to achieve your goals.
|
package/RNBitmovinPlayer.podspec
CHANGED
|
@@ -19,7 +19,7 @@ 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.
|
|
22
|
+
s.dependency "BitmovinPlayer", "3.46.0"
|
|
23
23
|
s.ios.dependency "GoogleAds-IMA-iOS-SDK", "3.18.4"
|
|
24
24
|
s.tvos.dependency "GoogleAds-IMA-tvOS-SDK", "4.8.2"
|
|
25
25
|
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
[*.{kt,kts}]
|
|
2
|
+
ktlint_code_style=android_studio
|
|
3
|
+
max_line_length=120
|
|
4
|
+
# Allow wildcard imports for react native bridge, since IntelliJ does this automatically when performing
|
|
5
|
+
# imports optimization.
|
|
6
|
+
ij_kotlin_packages_to_use_import_on_demand = com.facebook.react.bridge.*
|
|
7
|
+
ij_kotlin_allow_trailing_comma=true
|
|
8
|
+
ij_kotlin_allow_trailing_comma_on_call_site=true
|
package/android/build.gradle
CHANGED
|
@@ -2,19 +2,25 @@ buildscript {
|
|
|
2
2
|
ext {
|
|
3
3
|
kotlinVersion = '1.7.21'
|
|
4
4
|
androidToolsVersion = '7.4.2'
|
|
5
|
+
ktlintVersion = '11.6.0'
|
|
5
6
|
}
|
|
6
7
|
repositories {
|
|
7
8
|
google()
|
|
8
9
|
mavenCentral()
|
|
10
|
+
maven {
|
|
11
|
+
url "https://plugins.gradle.org/m2/"
|
|
12
|
+
}
|
|
9
13
|
}
|
|
10
14
|
dependencies {
|
|
11
15
|
classpath "com.android.tools.build:gradle:$androidToolsVersion"
|
|
12
16
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
|
17
|
+
classpath "org.jlleitschuh.gradle:ktlint-gradle:$ktlintVersion"
|
|
13
18
|
}
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
apply plugin: 'com.android.library'
|
|
17
22
|
apply plugin: 'kotlin-android'
|
|
23
|
+
apply plugin: 'org.jlleitschuh.gradle.ktlint'
|
|
18
24
|
|
|
19
25
|
repositories {
|
|
20
26
|
mavenLocal()
|
|
@@ -51,9 +57,9 @@ android {
|
|
|
51
57
|
|
|
52
58
|
dependencies {
|
|
53
59
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
|
54
|
-
implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.
|
|
60
|
+
implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.31.0'
|
|
55
61
|
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
|
|
56
|
-
implementation 'com.bitmovin.player:player:3.
|
|
62
|
+
implementation 'com.bitmovin.player:player:3.48.0+jason'
|
|
57
63
|
//noinspection GradleDynamicVersion
|
|
58
64
|
implementation 'com.facebook.react:react-native:+' // From node_modules
|
|
59
65
|
}
|
|
Binary file
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
package com.bitmovin.player.reactnative
|
|
2
|
+
|
|
3
|
+
import com.bitmovin.player.casting.BitmovinCastManager
|
|
4
|
+
import com.bitmovin.player.reactnative.converter.JsonConverter
|
|
5
|
+
import com.facebook.react.bridge.Promise
|
|
6
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
7
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
8
|
+
import com.facebook.react.bridge.ReactMethod
|
|
9
|
+
import com.facebook.react.bridge.ReadableMap
|
|
10
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
11
|
+
import com.facebook.react.uimanager.UIManagerModule
|
|
12
|
+
|
|
13
|
+
private const val MODULE_NAME = "BitmovinCastManagerModule"
|
|
14
|
+
|
|
15
|
+
@ReactModule(name = MODULE_NAME)
|
|
16
|
+
class BitmovinCastManagerModule(
|
|
17
|
+
private val context: ReactApplicationContext,
|
|
18
|
+
) : ReactContextBaseJavaModule(context) {
|
|
19
|
+
override fun getName() = MODULE_NAME
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns whether the [BitmovinCastManager] is initialized.
|
|
23
|
+
*/
|
|
24
|
+
@ReactMethod
|
|
25
|
+
fun isInitialized(promise: Promise) = uiManager?.addUIBlock {
|
|
26
|
+
promise.resolve(BitmovinCastManager.isInitialized())
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Initializes the [BitmovinCastManager] with the given options.
|
|
31
|
+
*/
|
|
32
|
+
@ReactMethod
|
|
33
|
+
fun initializeCastManager(options: ReadableMap?, promise: Promise) {
|
|
34
|
+
val castOptions = JsonConverter.toCastOptions(options)
|
|
35
|
+
uiManager?.addUIBlock {
|
|
36
|
+
BitmovinCastManager.initialize(
|
|
37
|
+
castOptions?.applicationId,
|
|
38
|
+
castOptions?.messageNamespace,
|
|
39
|
+
)
|
|
40
|
+
promise.resolve(null)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Sends a message to the receiver.
|
|
46
|
+
*/
|
|
47
|
+
@ReactMethod
|
|
48
|
+
fun sendMessage(message: String, messageNamespace: String?, promise: Promise) {
|
|
49
|
+
uiManager?.addUIBlock {
|
|
50
|
+
BitmovinCastManager.getInstance().sendMessage(message, messageNamespace)
|
|
51
|
+
promise.resolve(null)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Updates the context of the [BitmovinCastManager] to the current activity.
|
|
57
|
+
*/
|
|
58
|
+
@ReactMethod
|
|
59
|
+
fun updateContext(promise: Promise) {
|
|
60
|
+
uiManager?.addUIBlock {
|
|
61
|
+
BitmovinCastManager.getInstance().updateContext(currentActivity)
|
|
62
|
+
promise.resolve(null)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private val uiManager: UIManagerModule?
|
|
67
|
+
get() = context.getNativeModule(UIManagerModule::class.java)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Represents configuration options for the [BitmovinCastManager].
|
|
72
|
+
*/
|
|
73
|
+
data class BitmovinCastManagerOptions(
|
|
74
|
+
val applicationId: String? = null,
|
|
75
|
+
val messageNamespace: String? = null,
|
|
76
|
+
)
|
|
@@ -130,7 +130,7 @@ class DrmModule(private val context: ReactApplicationContext) : ReactContextBase
|
|
|
130
130
|
nativeId,
|
|
131
131
|
"onPrepareMessage",
|
|
132
132
|
preparedMessages,
|
|
133
|
-
preparedMessagesCondition
|
|
133
|
+
preparedMessagesCondition,
|
|
134
134
|
)
|
|
135
135
|
widevineConfig.prepareMessageCallback = PrepareMessageCallback {
|
|
136
136
|
prepareMessage(it)
|
|
@@ -151,7 +151,7 @@ class DrmModule(private val context: ReactApplicationContext) : ReactContextBase
|
|
|
151
151
|
nativeId,
|
|
152
152
|
"onPrepareLicense",
|
|
153
153
|
preparedLicenses,
|
|
154
|
-
preparedLicensesCondition
|
|
154
|
+
preparedLicensesCondition,
|
|
155
155
|
)
|
|
156
156
|
widevineConfig.prepareLicenseCallback = PrepareLicenseCallback {
|
|
157
157
|
prepareLicense(it)
|
|
@@ -170,11 +170,11 @@ class DrmModule(private val context: ReactApplicationContext) : ReactContextBase
|
|
|
170
170
|
nativeId: NativeId,
|
|
171
171
|
method: String,
|
|
172
172
|
registry: Registry<String>,
|
|
173
|
-
registryCondition: Condition
|
|
173
|
+
registryCondition: Condition,
|
|
174
174
|
): PrepareCallback = {
|
|
175
175
|
val args = Arguments.createArray()
|
|
176
176
|
args.pushString(Base64.encodeToString(it, Base64.NO_WRAP))
|
|
177
|
-
context.catalystInstance.callFunction("DRM-$
|
|
177
|
+
context.catalystInstance.callFunction("DRM-$nativeId", method, args as NativeArray)
|
|
178
178
|
lock.withLock {
|
|
179
179
|
registryCondition.await()
|
|
180
180
|
val result = registry[nativeId]
|
|
@@ -21,7 +21,7 @@ class EventRelay<E : EventEmitter<T>, T : Event>(
|
|
|
21
21
|
/**
|
|
22
22
|
* Is called for every relayed event together with its associated name.
|
|
23
23
|
*/
|
|
24
|
-
private val eventOutput: (String, Event) -> Unit
|
|
24
|
+
private val eventOutput: (String, Event) -> Unit,
|
|
25
25
|
) {
|
|
26
26
|
private val eventListeners = forwardingEventClassesAndNameMapping.map {
|
|
27
27
|
Subscription(it.key) { event -> eventOutput(it.value, event) }
|
|
@@ -3,8 +3,8 @@ package com.bitmovin.player.reactnative
|
|
|
3
3
|
import com.bitmovin.player.api.offline.options.OfflineOptionEntryState
|
|
4
4
|
import com.bitmovin.player.reactnative.converter.JsonConverter
|
|
5
5
|
import com.bitmovin.player.reactnative.extensions.toList
|
|
6
|
-
import com.bitmovin.player.reactnative.offline.OfflineDownloadRequest
|
|
7
6
|
import com.bitmovin.player.reactnative.offline.OfflineContentManagerBridge
|
|
7
|
+
import com.bitmovin.player.reactnative.offline.OfflineDownloadRequest
|
|
8
8
|
import com.facebook.react.bridge.*
|
|
9
9
|
import com.facebook.react.module.annotations.ReactModule
|
|
10
10
|
import com.facebook.react.uimanager.UIManagerModule
|
|
@@ -69,7 +69,13 @@ class OfflineModule(private val context: ReactApplicationContext) : ReactContext
|
|
|
69
69
|
return@addUIBlock
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
offlineContentManagerBridges[nativeId] = OfflineContentManagerBridge(
|
|
72
|
+
offlineContentManagerBridges[nativeId] = OfflineContentManagerBridge(
|
|
73
|
+
nativeId,
|
|
74
|
+
context,
|
|
75
|
+
identifier,
|
|
76
|
+
sourceConfig,
|
|
77
|
+
context.cacheDir.path,
|
|
78
|
+
)
|
|
73
79
|
}
|
|
74
80
|
promise.resolve(null)
|
|
75
81
|
}
|
|
@@ -117,7 +123,8 @@ class OfflineModule(private val context: ReactApplicationContext) : ReactContext
|
|
|
117
123
|
return@safeOfflineContentManager
|
|
118
124
|
}
|
|
119
125
|
OfflineOptionEntryState.Downloading,
|
|
120
|
-
OfflineOptionEntryState.Failed
|
|
126
|
+
OfflineOptionEntryState.Failed,
|
|
127
|
+
-> {
|
|
121
128
|
promise.reject(IllegalStateException("Download already in progress"))
|
|
122
129
|
return@safeOfflineContentManager
|
|
123
130
|
}
|
|
@@ -127,7 +134,7 @@ class OfflineModule(private val context: ReactApplicationContext) : ReactContext
|
|
|
127
134
|
}
|
|
128
135
|
else -> {}
|
|
129
136
|
}
|
|
130
|
-
val minimumBitRate = if(request.hasKey("minimumBitrate")) request.getInt("minimumBitrate") else null
|
|
137
|
+
val minimumBitRate = if (request.hasKey("minimumBitrate")) request.getInt("minimumBitrate") else null
|
|
131
138
|
if (minimumBitRate != null && minimumBitRate < 0) {
|
|
132
139
|
promise.reject(IllegalArgumentException("Invalid download request"))
|
|
133
140
|
return@safeOfflineContentManager
|
|
@@ -136,7 +143,9 @@ class OfflineModule(private val context: ReactApplicationContext) : ReactContext
|
|
|
136
143
|
val audioOptionIds = request.getArray("audioOptionIds")?.toList<String>()?.filterNotNull()
|
|
137
144
|
val textOptionIds = request.getArray("textOptionIds")?.toList<String>()?.filterNotNull()
|
|
138
145
|
|
|
139
|
-
getOfflineContentManagerBridge(nativeId)?.process(
|
|
146
|
+
getOfflineContentManagerBridge(nativeId)?.process(
|
|
147
|
+
OfflineDownloadRequest(minimumBitRate, audioOptionIds, textOptionIds),
|
|
148
|
+
)
|
|
140
149
|
promise.resolve(null)
|
|
141
150
|
} catch (e: Exception) {
|
|
142
151
|
promise.reject(e)
|
|
@@ -260,20 +269,22 @@ class OfflineModule(private val context: ReactApplicationContext) : ReactContext
|
|
|
260
269
|
}
|
|
261
270
|
}
|
|
262
271
|
|
|
263
|
-
private fun safeOfflineContentManager(
|
|
272
|
+
private fun safeOfflineContentManager(
|
|
273
|
+
nativeId: NativeId,
|
|
274
|
+
promise: Promise,
|
|
275
|
+
runBlock: OfflineContentManagerBridge.() -> Unit,
|
|
276
|
+
) {
|
|
264
277
|
getOfflineContentManagerBridge(nativeId)?.let(runBlock)
|
|
265
|
-
|
|
278
|
+
?: promise.reject(IllegalArgumentException("Could not find the offline module instance"))
|
|
266
279
|
}
|
|
267
280
|
|
|
268
281
|
/**
|
|
269
282
|
* Helper function that returns the initialized `DrmModule` instance.
|
|
270
283
|
*/
|
|
271
|
-
private fun drmModule(): DrmModule? =
|
|
272
|
-
context.getNativeModule(DrmModule::class.java)
|
|
284
|
+
private fun drmModule(): DrmModule? = context.getNativeModule(DrmModule::class.java)
|
|
273
285
|
|
|
274
286
|
/**
|
|
275
287
|
* Helper function that returns the initialized `UIManager` instance.
|
|
276
288
|
*/
|
|
277
|
-
private fun uiManager(): UIManagerModule? =
|
|
278
|
-
context.getNativeModule(UIManagerModule::class.java)
|
|
289
|
+
private fun uiManager(): UIManagerModule? = context.getNativeModule(UIManagerModule::class.java)
|
|
279
290
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
package com.bitmovin.player.reactnative
|
|
2
|
+
|
|
3
|
+
import com.bitmovin.player.api.analytics.AnalyticsApi.Companion.analytics
|
|
4
|
+
import com.bitmovin.player.reactnative.converter.JsonConverter
|
|
5
|
+
import com.facebook.react.bridge.*
|
|
6
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
7
|
+
import com.facebook.react.uimanager.UIManagerModule
|
|
8
|
+
|
|
9
|
+
private const val MODULE_NAME = "PlayerAnalyticsModule"
|
|
10
|
+
|
|
11
|
+
@ReactModule(name = MODULE_NAME)
|
|
12
|
+
class PlayerAnalyticsModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
|
|
13
|
+
/**
|
|
14
|
+
* JS exported module name.
|
|
15
|
+
*/
|
|
16
|
+
override fun getName() = MODULE_NAME
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Sends a sample with the provided custom data.
|
|
20
|
+
* Does not change the configured custom data of the collector or source.
|
|
21
|
+
* @param nativeId Native Id of the collector instance.
|
|
22
|
+
* @param json Custom data config json.
|
|
23
|
+
*/
|
|
24
|
+
@ReactMethod
|
|
25
|
+
fun sendCustomDataEvent(nativeId: NativeId, json: ReadableMap?) {
|
|
26
|
+
uiManager()?.addUIBlock { _ ->
|
|
27
|
+
JsonConverter.toAnalyticsCustomData(json)?.let {
|
|
28
|
+
playerModule()?.getPlayer(nativeId)?.analytics?.sendCustomDataEvent(it)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gets the current user Id for a player instance with analytics.
|
|
35
|
+
* @param nativeId Native Id of the the player instance.
|
|
36
|
+
* @param promise JS promise object.
|
|
37
|
+
*/
|
|
38
|
+
@ReactMethod
|
|
39
|
+
fun getUserId(playerId: NativeId, promise: Promise) {
|
|
40
|
+
uiManager()?.addUIBlock { _ ->
|
|
41
|
+
playerModule()?.getPlayer(playerId)?.analytics?.let {
|
|
42
|
+
promise.resolve(it.userId)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Helper function that gets the instantiated `UIManagerModule` from modules registry.
|
|
49
|
+
*/
|
|
50
|
+
private fun uiManager(): UIManagerModule? =
|
|
51
|
+
context.getNativeModule(UIManagerModule::class.java)
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Helper function that gets the instantiated `PlayerModule` from modules registry.
|
|
55
|
+
*/
|
|
56
|
+
private fun playerModule(): PlayerModule? =
|
|
57
|
+
context.getNativeModule(PlayerModule::class.java)
|
|
58
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
package com.bitmovin.player.reactnative
|
|
2
2
|
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.bitmovin.analytics.api.DefaultMetadata
|
|
3
5
|
import com.bitmovin.player.api.Player
|
|
6
|
+
import com.bitmovin.player.api.analytics.create
|
|
7
|
+
import com.bitmovin.player.api.event.PlayerEvent
|
|
4
8
|
import com.bitmovin.player.reactnative.converter.JsonConverter
|
|
5
9
|
import com.facebook.react.bridge.*
|
|
6
10
|
import com.facebook.react.module.annotations.ReactModule
|
|
@@ -47,6 +51,37 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Creates a new `Player` instance inside the internal players using the provided `playerConfig` and `analyticsConfig`.
|
|
56
|
+
* @param playerConfigJson `PlayerConfig` object received from JS.
|
|
57
|
+
* @param analyticsConfigJson `AnalyticsConfig` object received from JS.
|
|
58
|
+
*/
|
|
59
|
+
@ReactMethod
|
|
60
|
+
fun initWithAnalyticsConfig(nativeId: NativeId, playerConfigJson: ReadableMap?, analyticsConfigJson: ReadableMap?) {
|
|
61
|
+
uiManager()?.addUIBlock {
|
|
62
|
+
if (players.containsKey(nativeId)) {
|
|
63
|
+
Log.d("[PlayerModule]", "Duplicate player creation for id $nativeId")
|
|
64
|
+
return@addUIBlock
|
|
65
|
+
}
|
|
66
|
+
val playerConfig = JsonConverter.toPlayerConfig(playerConfigJson)
|
|
67
|
+
val analyticsConfig = JsonConverter.toAnalyticsConfig(analyticsConfigJson)
|
|
68
|
+
val defaultMetadata = JsonConverter.toAnalyticsDefaultMetadata(
|
|
69
|
+
analyticsConfigJson?.getMap("defaultMetadata"),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
players[nativeId] = if (analyticsConfig == null) {
|
|
73
|
+
Player.create(context, playerConfig)
|
|
74
|
+
} else {
|
|
75
|
+
Player.create(
|
|
76
|
+
context = context,
|
|
77
|
+
playerConfig = playerConfig,
|
|
78
|
+
analyticsConfig = analyticsConfig,
|
|
79
|
+
defaultMetadata = defaultMetadata ?: DefaultMetadata(),
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
50
85
|
/**
|
|
51
86
|
* Load the source of the given `nativeId` with `config` options from JS.
|
|
52
87
|
* @param nativeId Target player.
|
|
@@ -448,7 +483,9 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
448
483
|
@ReactMethod
|
|
449
484
|
fun setMaxSelectableBitrate(nativeId: NativeId, maxSelectableBitrate: Int) {
|
|
450
485
|
uiManager()?.addUIBlock {
|
|
451
|
-
players[nativeId]?.setMaxSelectableVideoBitrate(
|
|
486
|
+
players[nativeId]?.setMaxSelectableVideoBitrate(
|
|
487
|
+
maxSelectableBitrate.takeUnless { it == -1 } ?: Integer.MAX_VALUE,
|
|
488
|
+
)
|
|
452
489
|
}
|
|
453
490
|
}
|
|
454
491
|
|
|
@@ -464,6 +501,48 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
|
|
|
464
501
|
}
|
|
465
502
|
}
|
|
466
503
|
|
|
504
|
+
/**
|
|
505
|
+
* Initiates casting the current video to a cast-compatible remote device. The user has to choose to which device it
|
|
506
|
+
* should be sent.
|
|
507
|
+
*/
|
|
508
|
+
@ReactMethod
|
|
509
|
+
fun castVideo(nativeId: NativeId) {
|
|
510
|
+
uiManager()?.addUIBlock {
|
|
511
|
+
players[nativeId]?.castVideo()
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Stops casting the current video. Has no effect if [isCasting] is false.
|
|
517
|
+
*/
|
|
518
|
+
@ReactMethod
|
|
519
|
+
fun castStop(nativeId: NativeId) {
|
|
520
|
+
uiManager()?.addUIBlock {
|
|
521
|
+
players[nativeId]?.castStop()
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Whether casting to a cast-compatible remote device is available. [PlayerEvent.CastAvailable] signals when
|
|
527
|
+
* casting becomes available.
|
|
528
|
+
*/
|
|
529
|
+
@ReactMethod
|
|
530
|
+
fun isCastAvailable(nativeId: NativeId, promise: Promise) {
|
|
531
|
+
uiManager()?.addUIBlock {
|
|
532
|
+
promise.resolve(players[nativeId]?.isCastAvailable)
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Whether video is currently being casted to a remote device and not played locally.
|
|
538
|
+
*/
|
|
539
|
+
@ReactMethod
|
|
540
|
+
fun isCasting(nativeId: NativeId, promise: Promise) {
|
|
541
|
+
uiManager()?.addUIBlock {
|
|
542
|
+
promise.resolve(players[nativeId]?.isCasting)
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
467
546
|
/**
|
|
468
547
|
* Helper function that returns the initialized `UIManager` instance.
|
|
469
548
|
*/
|
|
@@ -11,6 +11,7 @@ import com.bitmovin.player.api.Player
|
|
|
11
11
|
import com.bitmovin.player.api.event.Event
|
|
12
12
|
import com.bitmovin.player.api.event.PlayerEvent
|
|
13
13
|
import com.bitmovin.player.api.event.SourceEvent
|
|
14
|
+
import com.bitmovin.player.api.ui.PlayerViewConfig
|
|
14
15
|
import com.bitmovin.player.reactnative.converter.JsonConverter
|
|
15
16
|
import com.bitmovin.player.reactnative.ui.RNPictureInPictureDelegate
|
|
16
17
|
import com.bitmovin.player.reactnative.ui.RNPictureInPictureHandler
|
|
@@ -62,6 +63,18 @@ private val EVENT_CLASS_TO_REACT_NATIVE_NAME_MAPPING = mapOf(
|
|
|
62
63
|
PlayerEvent.AdSkipped::class to "adSkipped",
|
|
63
64
|
PlayerEvent.AdStarted::class to "adStarted",
|
|
64
65
|
PlayerEvent.VideoPlaybackQualityChanged::class to "videoPlaybackQualityChanged",
|
|
66
|
+
PlayerEvent.CastStart::class to "castStart",
|
|
67
|
+
@Suppress("DEPRECATION")
|
|
68
|
+
PlayerEvent.CastPlaybackFinished::class to "castPlaybackFinished",
|
|
69
|
+
@Suppress("DEPRECATION")
|
|
70
|
+
PlayerEvent.CastPaused::class to "castPaused",
|
|
71
|
+
@Suppress("DEPRECATION")
|
|
72
|
+
PlayerEvent.CastPlaying::class to "castPlaying",
|
|
73
|
+
PlayerEvent.CastStarted::class to "castStarted",
|
|
74
|
+
PlayerEvent.CastAvailable::class to "castAvailable",
|
|
75
|
+
PlayerEvent.CastStopped::class to "castStopped",
|
|
76
|
+
PlayerEvent.CastWaitingForDevice::class to "castWaitingForDevice",
|
|
77
|
+
PlayerEvent.CastTimeUpdated::class to "castTimeUpdated",
|
|
65
78
|
)
|
|
66
79
|
|
|
67
80
|
private val EVENT_CLASS_TO_REACT_NATIVE_NAME_MAPPING_UI = mapOf<KClass<out Event>, String>(
|
|
@@ -80,8 +93,11 @@ private val EVENT_CLASS_TO_REACT_NATIVE_NAME_MAPPING_UI = mapOf<KClass<out Event
|
|
|
80
93
|
* exposes player events as bubbling events.
|
|
81
94
|
*/
|
|
82
95
|
@SuppressLint("ViewConstructor")
|
|
83
|
-
class RNPlayerView(val context: ReactApplicationContext) :
|
|
84
|
-
|
|
96
|
+
class RNPlayerView(val context: ReactApplicationContext) :
|
|
97
|
+
LinearLayout(context),
|
|
98
|
+
LifecycleEventListener,
|
|
99
|
+
View.OnLayoutChangeListener,
|
|
100
|
+
RNPictureInPictureDelegate {
|
|
85
101
|
|
|
86
102
|
init {
|
|
87
103
|
// React Native has a bug that dynamically added views sometimes aren't laid out again properly.
|
|
@@ -97,6 +113,7 @@ class RNPlayerView(val context: ReactApplicationContext) : LinearLayout(context)
|
|
|
97
113
|
* to the `eventOutput` callback.
|
|
98
114
|
*/
|
|
99
115
|
private val playerEventRelay = EventRelay<Player, Event>(EVENT_CLASS_TO_REACT_NATIVE_NAME_MAPPING, ::emitEvent)
|
|
116
|
+
|
|
100
117
|
/**
|
|
101
118
|
* Relays the provided set of events, emitted by the player view, together with the associated name
|
|
102
119
|
* to the `eventOutput` callback.
|
|
@@ -128,6 +145,11 @@ class RNPlayerView(val context: ReactApplicationContext) : LinearLayout(context)
|
|
|
128
145
|
*/
|
|
129
146
|
var pictureInPictureHandler: RNPictureInPictureHandler? = null
|
|
130
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Configures the visual presentation and behaviour of the [playerView].
|
|
150
|
+
*/
|
|
151
|
+
var config: RNPlayerViewConfigWrapper? = null
|
|
152
|
+
|
|
131
153
|
/**
|
|
132
154
|
* Whether this view should pause video playback when activity's onPause is called.
|
|
133
155
|
* By default, `shouldPausePlaybackOnActivityPause` is set to false when entering PiP mode.
|
|
@@ -261,7 +283,7 @@ class RNPlayerView(val context: ReactApplicationContext) : LinearLayout(context)
|
|
|
261
283
|
post {
|
|
262
284
|
measure(
|
|
263
285
|
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
264
|
-
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
286
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY),
|
|
265
287
|
)
|
|
266
288
|
layout(left, top, right, bottom)
|
|
267
289
|
}
|
|
@@ -269,8 +291,8 @@ class RNPlayerView(val context: ReactApplicationContext) : LinearLayout(context)
|
|
|
269
291
|
|
|
270
292
|
/**
|
|
271
293
|
* Emits a bubbling event with payload to js.
|
|
272
|
-
* @param
|
|
273
|
-
* @param
|
|
294
|
+
* @param name Native event name.
|
|
295
|
+
* @param event Optional js object to be sent as payload.
|
|
274
296
|
*/
|
|
275
297
|
private inline fun <reified E : Event> emitEvent(name: String, event: E) {
|
|
276
298
|
val payload = if (event is PlayerEvent) {
|
|
@@ -284,3 +306,12 @@ class RNPlayerView(val context: ReactApplicationContext) : LinearLayout(context)
|
|
|
284
306
|
.receiveEvent(id, name, payload)
|
|
285
307
|
}
|
|
286
308
|
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Representation of the React Native API `PlayerViewConfig` object.
|
|
312
|
+
* This is necessary as not all of its values can be directly mapped to the native `PlayerViewConfig`.
|
|
313
|
+
*/
|
|
314
|
+
data class RNPlayerViewConfigWrapper(
|
|
315
|
+
val playerViewConfig: PlayerViewConfig?,
|
|
316
|
+
val pictureInPictureConfig: RNPictureInPictureHandler.PictureInPictureConfig?,
|
|
317
|
+
)
|