bitmovin-player-react-native 0.4.0 → 0.5.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 +249 -1
- package/RNBitmovinPlayer.podspec +3 -1
- package/android/build.gradle +3 -2
- package/android/src/main/java/com/bitmovin/player/reactnative/AnalyticsModule.kt +154 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerView.kt +45 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +25 -4
- package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt +3 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +172 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/extensions/Any.kt +27 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/extensions/ReactContextExtension.kt +8 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/extensions/String.kt +8 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/ui/FullscreenHandlerBridge.kt +37 -0
- package/android/src/main/java/com/bitmovin/player/reactnative/ui/FullscreenHandlerModule.kt +73 -0
- package/ios/AnalyticsModule.m +14 -0
- package/ios/AnalyticsModule.swift +180 -0
- package/ios/Event+JSON.swift +11 -0
- package/ios/FullscreenHandlerBridge.swift +33 -0
- package/ios/FullscreenHandlerModule.m +9 -0
- package/ios/FullscreenHandlerModule.swift +71 -0
- package/ios/RCTConvert+BitmovinPlayer.swift +174 -0
- package/ios/RNPlayerView+PlayerListener.swift +5 -1
- package/ios/RNPlayerView+UserInterfaceListener.swift +16 -0
- package/ios/RNPlayerView.swift +5 -0
- package/ios/RNPlayerViewManager.m +6 -0
- package/ios/RNPlayerViewManager.swift +21 -0
- package/lib/index.d.ts +498 -51
- package/lib/index.js +186 -42
- package/lib/index.mjs +167 -26
- package/package.json +1 -1
- package/src/analytics/collector.ts +97 -0
- package/src/analytics/config.ts +218 -0
- package/src/analytics/index.ts +2 -0
- package/src/components/PlayerView/events.ts +10 -0
- package/src/components/PlayerView/index.tsx +38 -1
- package/src/components/PlayerView/native.ts +4 -1
- package/src/events.ts +43 -0
- package/src/index.ts +2 -0
- package/src/media.ts +33 -0
- package/src/player.ts +21 -0
- package/src/source.ts +4 -0
- package/src/styleConfig.ts +87 -0
- package/src/ui/fullscreenhandler.ts +19 -0
- package/src/ui/fullscreenhandlerbridge.ts +59 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package com.bitmovin.player.reactnative.converter
|
|
2
2
|
|
|
3
|
+
import com.bitmovin.analytics.BitmovinAnalyticsConfig
|
|
4
|
+
import com.bitmovin.analytics.data.CustomData
|
|
3
5
|
import com.bitmovin.player.api.DeviceDescription.DeviceName
|
|
4
6
|
import com.bitmovin.player.api.DeviceDescription.ModelName
|
|
5
7
|
import com.bitmovin.player.api.PlaybackConfig
|
|
@@ -11,14 +13,20 @@ import com.bitmovin.player.api.event.PlayerEvent
|
|
|
11
13
|
import com.bitmovin.player.api.event.SourceEvent
|
|
12
14
|
import com.bitmovin.player.api.event.data.SeekPosition
|
|
13
15
|
import com.bitmovin.player.api.media.subtitle.SubtitleTrack
|
|
16
|
+
import com.bitmovin.player.api.media.thumbnail.ThumbnailTrack
|
|
17
|
+
import com.bitmovin.player.api.media.video.quality.VideoQuality
|
|
14
18
|
import com.bitmovin.player.api.source.Source
|
|
15
19
|
import com.bitmovin.player.api.source.SourceConfig
|
|
16
20
|
import com.bitmovin.player.api.source.SourceType
|
|
21
|
+
import com.bitmovin.player.api.ui.ScalingMode
|
|
22
|
+
import com.bitmovin.player.api.ui.StyleConfig
|
|
17
23
|
import com.bitmovin.player.reactnative.extensions.getName
|
|
18
24
|
import com.bitmovin.player.reactnative.extensions.putInt
|
|
19
25
|
import com.bitmovin.player.reactnative.extensions.putDouble
|
|
20
26
|
import com.bitmovin.player.reactnative.extensions.toList
|
|
21
27
|
import com.bitmovin.player.reactnative.extensions.toReadableArray
|
|
28
|
+
import com.bitmovin.player.reactnative.extensions.getProperty
|
|
29
|
+
import com.bitmovin.player.reactnative.extensions.setProperty
|
|
22
30
|
import com.facebook.react.bridge.*
|
|
23
31
|
import java.util.UUID
|
|
24
32
|
|
|
@@ -45,6 +53,11 @@ class JsonConverter {
|
|
|
45
53
|
playerConfig.playbackConfig = it
|
|
46
54
|
}
|
|
47
55
|
}
|
|
56
|
+
if (json.hasKey("styleConfig")) {
|
|
57
|
+
toStyleConfig(json.getMap("styleConfig"))?.let {
|
|
58
|
+
playerConfig.styleConfig = it
|
|
59
|
+
}
|
|
60
|
+
}
|
|
48
61
|
if (json.hasKey("tweaksConfig")) {
|
|
49
62
|
toTweaksConfig(json.getMap("tweaksConfig"))?.let {
|
|
50
63
|
playerConfig.tweaksConfig = it
|
|
@@ -81,6 +94,47 @@ class JsonConverter {
|
|
|
81
94
|
return playbackConfig
|
|
82
95
|
}
|
|
83
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Converts any JS object into a `StyleConfig` object.
|
|
99
|
+
* @param json JS object representing the `StyleConfig`.
|
|
100
|
+
* @return The generated `StyleConfig` if successful, `null` otherwise.
|
|
101
|
+
*/
|
|
102
|
+
@JvmStatic
|
|
103
|
+
fun toStyleConfig(json: ReadableMap?): StyleConfig? {
|
|
104
|
+
if (json == null) {
|
|
105
|
+
return null
|
|
106
|
+
}
|
|
107
|
+
val styleConfig = StyleConfig()
|
|
108
|
+
if (json.hasKey("isUiEnabled")) {
|
|
109
|
+
styleConfig.isUiEnabled = json.getBoolean("isUiEnabled")
|
|
110
|
+
}
|
|
111
|
+
if (json.hasKey("playerUiCss")) {
|
|
112
|
+
val playerUiCss = json.getString("playerUiCss")
|
|
113
|
+
if (!playerUiCss.isNullOrEmpty()) {
|
|
114
|
+
styleConfig.playerUiCss = playerUiCss
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (json.hasKey("supplementalPlayerUiCss")) {
|
|
118
|
+
val supplementalPlayerUiCss = json.getString("supplementalPlayerUiCss")
|
|
119
|
+
if (!supplementalPlayerUiCss.isNullOrEmpty()) {
|
|
120
|
+
styleConfig.supplementalPlayerUiCss = supplementalPlayerUiCss
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (json.hasKey("playerUiJs")) {
|
|
124
|
+
val playerUiJs = json.getString("playerUiJs")
|
|
125
|
+
if (!playerUiJs.isNullOrEmpty()) {
|
|
126
|
+
styleConfig.playerUiJs = playerUiJs
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (json.hasKey("scalingMode")) {
|
|
130
|
+
val scalingMode = json.getString("scalingMode")
|
|
131
|
+
if (!scalingMode.isNullOrEmpty()) {
|
|
132
|
+
styleConfig.scalingMode = ScalingMode.valueOf(scalingMode)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return styleConfig
|
|
136
|
+
}
|
|
137
|
+
|
|
84
138
|
/**
|
|
85
139
|
* Converts any JS object into a `TweaksConfig` object.
|
|
86
140
|
* @param json JS object representing the `TweaksConfig`.
|
|
@@ -207,6 +261,9 @@ class JsonConverter {
|
|
|
207
261
|
}
|
|
208
262
|
}
|
|
209
263
|
}
|
|
264
|
+
if (json.hasKey("thumbnailTrack")) {
|
|
265
|
+
config.thumbnailTrack = toThumbnailTrack(json.getString("thumbnailTrack"))
|
|
266
|
+
}
|
|
210
267
|
return config
|
|
211
268
|
}
|
|
212
269
|
|
|
@@ -376,6 +433,10 @@ class JsonConverter {
|
|
|
376
433
|
json.putDouble("skipOffset", event.skipOffset)
|
|
377
434
|
json.putDouble("timeOffset", event.timeOffset)
|
|
378
435
|
}
|
|
436
|
+
if (event is PlayerEvent.VideoPlaybackQualityChanged) {
|
|
437
|
+
json.putMap("newVideoQuality", fromVideoQuality(event.newVideoQuality))
|
|
438
|
+
json.putMap("oldVideoQuality", fromVideoQuality(event.oldVideoQuality))
|
|
439
|
+
}
|
|
379
440
|
return json
|
|
380
441
|
}
|
|
381
442
|
|
|
@@ -393,6 +454,19 @@ class JsonConverter {
|
|
|
393
454
|
widevineConfig
|
|
394
455
|
}
|
|
395
456
|
|
|
457
|
+
/**
|
|
458
|
+
* Converts an `url` string into a `ThumbnailsTrack`.
|
|
459
|
+
* @param url JS object representing the `ThumbnailsTrack`.
|
|
460
|
+
* @return The generated `ThumbnailsTrack` if successful, `null` otherwise.
|
|
461
|
+
*/
|
|
462
|
+
@JvmStatic
|
|
463
|
+
fun toThumbnailTrack(url: String?): ThumbnailTrack? {
|
|
464
|
+
if (url == null) {
|
|
465
|
+
return null
|
|
466
|
+
}
|
|
467
|
+
return ThumbnailTrack(url);
|
|
468
|
+
}
|
|
469
|
+
|
|
396
470
|
/**
|
|
397
471
|
* Converts an arbitrary `json` into a `SubtitleTrack`.
|
|
398
472
|
* @param json JS object representing the `SubtitleTrack`.
|
|
@@ -595,5 +669,103 @@ class JsonConverter {
|
|
|
595
669
|
AdQuartile.ThirdQuartile -> "third"
|
|
596
670
|
else -> null
|
|
597
671
|
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Converts an arbitrary json object into a `BitmovinAnalyticsConfig`.
|
|
675
|
+
* @param json JS object representing the `BitmovinAnalyticsConfig`.
|
|
676
|
+
* @return The produced `BitmovinAnalyticsConfig` or null.
|
|
677
|
+
*/
|
|
678
|
+
@JvmStatic
|
|
679
|
+
fun toAnalyticsConfig(json: ReadableMap?): BitmovinAnalyticsConfig? = json?.let {
|
|
680
|
+
var config: BitmovinAnalyticsConfig? = null
|
|
681
|
+
it.getString("key")?.let { key ->
|
|
682
|
+
config = it.getString("playerKey")
|
|
683
|
+
?.let { playerKey -> BitmovinAnalyticsConfig(key, playerKey) }
|
|
684
|
+
?: BitmovinAnalyticsConfig(key)
|
|
685
|
+
}
|
|
686
|
+
it.getString("cdnProvider")?.let { cdnProvider ->
|
|
687
|
+
config?.cdnProvider = cdnProvider
|
|
688
|
+
}
|
|
689
|
+
it.getString("customUserId")?.let { customUserId ->
|
|
690
|
+
config?.customUserId = customUserId
|
|
691
|
+
}
|
|
692
|
+
it.getString("experimentName")?.let { experimentName ->
|
|
693
|
+
config?.experimentName = experimentName
|
|
694
|
+
}
|
|
695
|
+
it.getString("videoId")?.let { videoId ->
|
|
696
|
+
config?.videoId = videoId
|
|
697
|
+
}
|
|
698
|
+
it.getString("title")?.let { title ->
|
|
699
|
+
config?.title = title
|
|
700
|
+
}
|
|
701
|
+
it.getString("path")?.let { path ->
|
|
702
|
+
config?.path = path
|
|
703
|
+
}
|
|
704
|
+
if (it.hasKey("isLive")) {
|
|
705
|
+
config?.isLive = it.getBoolean("isLive")
|
|
706
|
+
}
|
|
707
|
+
if (it.hasKey("ads")) {
|
|
708
|
+
config?.ads = it.getBoolean("ads")
|
|
709
|
+
}
|
|
710
|
+
if (it.hasKey("randomizeUserId")) {
|
|
711
|
+
config?.randomizeUserId = it.getBoolean("randomizeUserId")
|
|
712
|
+
}
|
|
713
|
+
for (n in 1..30) {
|
|
714
|
+
it.getString("customData${n}")?.let { customDataN ->
|
|
715
|
+
config?.setProperty("customData${n}", customDataN)
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
config
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Converts an arbitrary json object into an analytics `CustomData`.
|
|
723
|
+
* @param json JS object representing the `CustomData`.
|
|
724
|
+
* @return The produced `CustomData` or null.
|
|
725
|
+
*/
|
|
726
|
+
@JvmStatic
|
|
727
|
+
fun toAnalyticsCustomData(json: ReadableMap?): CustomData? = json?.let {
|
|
728
|
+
val customData = CustomData()
|
|
729
|
+
for (n in 1..30) {
|
|
730
|
+
it.getString("customData${n}")?.let { customDataN ->
|
|
731
|
+
customData.setProperty("customData${n}", customDataN)
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
customData
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Converts an arbitrary analytics `CustomData` object into a JS value.
|
|
739
|
+
* @param customData `CustomData` to be converted.
|
|
740
|
+
* @return The produced JS value or null.
|
|
741
|
+
*/
|
|
742
|
+
@JvmStatic
|
|
743
|
+
fun fromAnalyticsCustomData(customData: CustomData?): ReadableMap? = customData?.let {
|
|
744
|
+
val json = Arguments.createMap()
|
|
745
|
+
for (n in 1..30) {
|
|
746
|
+
it.getProperty<String>("customData${n}")?.let { customDataN ->
|
|
747
|
+
json.putString("customData${n}", customDataN)
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
json
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Converts any `VideoQuality` value into its json representation.
|
|
755
|
+
* @param videoQuality `VideoQuality` value.
|
|
756
|
+
* @return The produced JS string.
|
|
757
|
+
*/
|
|
758
|
+
@JvmStatic
|
|
759
|
+
fun fromVideoQuality(videoQuality: VideoQuality?): WritableMap? = videoQuality?.let {
|
|
760
|
+
Arguments.createMap().apply {
|
|
761
|
+
putString("id", videoQuality.id)
|
|
762
|
+
putString("label", videoQuality.label)
|
|
763
|
+
putInt("bitrate", videoQuality.bitrate)
|
|
764
|
+
putString("codec", videoQuality.codec)
|
|
765
|
+
putDouble("frameRate", videoQuality.frameRate.toDouble())
|
|
766
|
+
putInt("height", videoQuality.height)
|
|
767
|
+
putInt("width", videoQuality.width)
|
|
768
|
+
}
|
|
769
|
+
}
|
|
598
770
|
}
|
|
599
771
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
package com.bitmovin.player.reactnative.extensions
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reflection helper for dynamically getting a property by name from a java object.
|
|
5
|
+
* @param propertyName Property name.
|
|
6
|
+
* @return A mutable property reference that can be used to get/set the prop's value.
|
|
7
|
+
*/
|
|
8
|
+
@Suppress("UNCHECKED_CAST")
|
|
9
|
+
inline fun <reified T> Any?.getProperty(propertyName: String): T? = this?.let {
|
|
10
|
+
val getter = it::class.java.methods.firstOrNull { method ->
|
|
11
|
+
method.name == "get${propertyName.capitalized()}"
|
|
12
|
+
}
|
|
13
|
+
getter?.invoke(it) as? T
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Reflection helper for dynamically setting a property value by name to a java object.
|
|
18
|
+
* @param propertyName Property name.
|
|
19
|
+
* @param value Value that will be set for the specified `propertyName`.
|
|
20
|
+
*/
|
|
21
|
+
@Suppress("UNCHECKED_CAST")
|
|
22
|
+
inline fun <reified T> Any?.setProperty(propertyName: String, value: T) = this?.let {
|
|
23
|
+
val setter = it::class.java.methods.firstOrNull { method ->
|
|
24
|
+
method.name == "set${propertyName.capitalized()}"
|
|
25
|
+
}
|
|
26
|
+
setter?.invoke(it, value)
|
|
27
|
+
}
|
package/android/src/main/java/com/bitmovin/player/reactnative/extensions/ReactContextExtension.kt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
package com.bitmovin.player.reactnative.extensions
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactContext
|
|
4
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
5
|
+
|
|
6
|
+
inline fun <reified T : ReactContextBaseJavaModule> ReactContext.getModule(): T? {
|
|
7
|
+
return getNativeModule(T::class.java)
|
|
8
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
package com.bitmovin.player.reactnative.ui
|
|
2
|
+
|
|
3
|
+
import com.bitmovin.player.api.ui.FullscreenHandler
|
|
4
|
+
import com.bitmovin.player.reactnative.NativeId
|
|
5
|
+
import com.bitmovin.player.reactnative.extensions.getModule
|
|
6
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
7
|
+
|
|
8
|
+
class FullscreenHandlerBridge(
|
|
9
|
+
val context: ReactApplicationContext,
|
|
10
|
+
private val nativeId: NativeId
|
|
11
|
+
) : FullscreenHandler {
|
|
12
|
+
override var isFullscreen = false
|
|
13
|
+
|
|
14
|
+
override fun onDestroy() {
|
|
15
|
+
// Do nothing
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override fun onFullscreenExitRequested() {
|
|
19
|
+
context
|
|
20
|
+
.getModule<FullscreenHandlerModule>()
|
|
21
|
+
?.requestExitFullscreen(nativeId)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override fun onFullscreenRequested() {
|
|
25
|
+
context
|
|
26
|
+
.getModule<FullscreenHandlerModule>()
|
|
27
|
+
?.requestEnterFullscreen(nativeId)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override fun onPause() {
|
|
31
|
+
// Do nothing
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
override fun onResume() {
|
|
35
|
+
// Do nothing
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
package com.bitmovin.player.reactnative.ui
|
|
2
|
+
|
|
3
|
+
import com.bitmovin.player.reactnative.NativeId
|
|
4
|
+
import com.bitmovin.player.reactnative.Registry
|
|
5
|
+
import com.facebook.react.bridge.*
|
|
6
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
7
|
+
import java.util.concurrent.locks.ReentrantLock
|
|
8
|
+
import kotlin.concurrent.withLock
|
|
9
|
+
|
|
10
|
+
private const val MODULE_NAME = "FullscreenHandlerModule"
|
|
11
|
+
|
|
12
|
+
@ReactModule(name = MODULE_NAME)
|
|
13
|
+
class FullscreenHandlerModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
|
|
14
|
+
override fun getName() = MODULE_NAME
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* In-memory mapping from `nativeId`s to `FullscreenHandler` instances.
|
|
18
|
+
*/
|
|
19
|
+
private val fullscreenHandler: Registry<FullscreenHandlerBridge> = mutableMapOf()
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Module's local lock object used to sync calls between Kotlin and JS.
|
|
23
|
+
*/
|
|
24
|
+
private val lock = ReentrantLock()
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Lock condition used to sync operations on the fullscreen handler.
|
|
28
|
+
*/
|
|
29
|
+
private val fullscreenChangedCondition = lock.newCondition()
|
|
30
|
+
|
|
31
|
+
fun getInstance(nativeId: NativeId?): FullscreenHandlerBridge? = fullscreenHandler[nativeId]
|
|
32
|
+
|
|
33
|
+
fun requestEnterFullscreen(nativeId: NativeId) {
|
|
34
|
+
context.catalystInstance.callFunction(
|
|
35
|
+
"FullscreenBridge-${nativeId}",
|
|
36
|
+
"enterFullscreen",
|
|
37
|
+
Arguments.createArray() as NativeArray
|
|
38
|
+
)
|
|
39
|
+
lock.withLock {
|
|
40
|
+
fullscreenChangedCondition.await()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fun requestExitFullscreen(nativeId: NativeId) {
|
|
45
|
+
context.catalystInstance.callFunction(
|
|
46
|
+
"FullscreenBridge-${nativeId}",
|
|
47
|
+
"exitFullscreen",
|
|
48
|
+
Arguments.createArray() as NativeArray
|
|
49
|
+
)
|
|
50
|
+
lock.withLock {
|
|
51
|
+
fullscreenChangedCondition.await()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
56
|
+
fun onFullscreenChanged(nativeId: NativeId, isFullscreenEnabled: Boolean) {
|
|
57
|
+
fullscreenHandler[nativeId]?.isFullscreen = isFullscreenEnabled
|
|
58
|
+
lock.withLock {
|
|
59
|
+
fullscreenChangedCondition.signal()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@ReactMethod
|
|
64
|
+
fun registerHandler(nativeId: NativeId) {
|
|
65
|
+
val fullscreenHandler = fullscreenHandler[nativeId] ?: FullscreenHandlerBridge(context, nativeId)
|
|
66
|
+
this.fullscreenHandler[nativeId] = fullscreenHandler
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@ReactMethod
|
|
70
|
+
fun destroy(nativeId: NativeId) {
|
|
71
|
+
fullscreenHandler.remove(nativeId)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
|
|
3
|
+
@interface RCT_EXTERN_REMAP_MODULE(AnalyticsModule, AnalyticsModule, NSObject)
|
|
4
|
+
|
|
5
|
+
RCT_EXTERN_METHOD(initWithConfig:(NSString *)nativeId config:(nullable id)config)
|
|
6
|
+
RCT_EXTERN_METHOD(destroy:(NSString *)nativeId)
|
|
7
|
+
RCT_EXTERN_METHOD(attach:(NSString *)nativeId playerId:(NSString *)playerId)
|
|
8
|
+
RCT_EXTERN_METHOD(detach:(NSString *)nativeId)
|
|
9
|
+
RCT_EXTERN_METHOD(setCustomDataOnce:(NSString *)nativeId json:(nullable id)json)
|
|
10
|
+
RCT_EXTERN_METHOD(setCustomData:(NSString *)nativeId json:(nullable id)json)
|
|
11
|
+
RCT_EXTERN_METHOD(getCustomData:(NSString *)nativeId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
12
|
+
RCT_EXTERN_METHOD(getUserId:(NSString *)nativeId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
13
|
+
|
|
14
|
+
@end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import BitmovinPlayer
|
|
2
|
+
import BitmovinAnalyticsCollector
|
|
3
|
+
|
|
4
|
+
@objc(AnalyticsModule)
|
|
5
|
+
class AnalyticsModule: NSObject, RCTBridgeModule {
|
|
6
|
+
/// React bridge reference.
|
|
7
|
+
@objc var bridge: RCTBridge!
|
|
8
|
+
|
|
9
|
+
/// PlayerModule instance fetched from the bridge's registry
|
|
10
|
+
@objc var playerModule: PlayerModule? {
|
|
11
|
+
bridge.module(for: PlayerModule.self) as? PlayerModule
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/// In-memory mapping from `nativeId`s to `BitmovinPlayerCollector` instances.
|
|
15
|
+
private var collectors: Registry<BitmovinPlayerCollector> = [:]
|
|
16
|
+
|
|
17
|
+
/// JS module name.
|
|
18
|
+
static func moduleName() -> String! {
|
|
19
|
+
"AnalyticsModule"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/// Module requires main thread initialization.
|
|
23
|
+
static func requiresMainQueueSetup() -> Bool {
|
|
24
|
+
true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// Use `UIManager.addBlock` to enqueue module methods on UI thread.
|
|
28
|
+
var methodQueue: DispatchQueue! {
|
|
29
|
+
bridge.uiManager.methodQueue
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
Retrieves a `BitmovinPlayerCollector` instance from the internal registry for the given `nativeId`.
|
|
34
|
+
- Parameter nativeId: Native Id of the collector instance.
|
|
35
|
+
- Returns: Collector instance associated with the `nativeId` or `nil`.
|
|
36
|
+
*/
|
|
37
|
+
@objc func retrieve(_ nativeId: NativeId) -> BitmovinPlayerCollector? {
|
|
38
|
+
collectors[nativeId]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
Creates a new `BitmovinPlayerCollector` instance inside the internal registry using the provided `config` object.
|
|
43
|
+
- Parameter nativeId: ID to associate with the `BitmovinPlayerCollector` instance.
|
|
44
|
+
- Parameter config: `BitmovinAnalyticsConfig` object received from JS.
|
|
45
|
+
*/
|
|
46
|
+
@objc(initWithConfig:config:)
|
|
47
|
+
func initWithConfig(_ nativeId: NativeId, config: Any?) {
|
|
48
|
+
bridge.uiManager.addUIBlock { [weak self] _, _ in
|
|
49
|
+
guard let analyticsConfig = RCTConvert.analyticsConfig(config) else {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
self?.collectors[nativeId] = BitmovinPlayerCollector(config: analyticsConfig)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
Detaches and removes the given `BitmovinPlayerCollector` from the internal registry.
|
|
58
|
+
- Parameter nativeId: Native Id of the collector instance.
|
|
59
|
+
*/
|
|
60
|
+
@objc(destroy:)
|
|
61
|
+
func destroy(_ nativeId: NativeId) {
|
|
62
|
+
bridge.uiManager.addUIBlock { [weak self] _, _ in
|
|
63
|
+
self?.collectors[nativeId]?.detachPlayer()
|
|
64
|
+
self?.collectors[nativeId] = nil
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
Attaches a `BitmovinPlayerCollector` to the `Player` instance with native Id equal to `playerId`.
|
|
70
|
+
- Parameter nativeId: Native Id of the collector instance.
|
|
71
|
+
- Parameter playerId: Native Id of the player instance.
|
|
72
|
+
*/
|
|
73
|
+
@objc(attach:playerId:)
|
|
74
|
+
func attach(_ nativeId: NativeId, playerId: NativeId) {
|
|
75
|
+
bridge.uiManager.addUIBlock { [weak self] _, _ in
|
|
76
|
+
guard
|
|
77
|
+
let collector = self?.collectors[nativeId],
|
|
78
|
+
let player = self?.playerModule?.retrieve(playerId)
|
|
79
|
+
else {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
collector.attachPlayer(player: player)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
Detaches the player object from a `BitmovinPlayerCollector` instance.
|
|
88
|
+
- Parameter nativeId: Native Id of the collector instance.
|
|
89
|
+
*/
|
|
90
|
+
@objc(detach:)
|
|
91
|
+
func detach(_ nativeId: NativeId) {
|
|
92
|
+
bridge.uiManager.addUIBlock { [weak self] _, _ in
|
|
93
|
+
guard let collector = self?.collectors[nativeId] else {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
collector.detachPlayer()
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
Updates the custom data config for a `BitmovinPlayerCollector` instance.
|
|
102
|
+
- Parameter nativeId: Native Id of the collector instance.
|
|
103
|
+
- Parameter json: Custom data config json.
|
|
104
|
+
*/
|
|
105
|
+
@objc(setCustomDataOnce:json:)
|
|
106
|
+
func setCustomDataOnce(_ nativeId: NativeId, json: Any?) {
|
|
107
|
+
bridge.uiManager.addUIBlock { [weak self] _, _ in
|
|
108
|
+
guard
|
|
109
|
+
let collector = self?.collectors[nativeId],
|
|
110
|
+
let customData = RCTConvert.analyticsCustomData(json)
|
|
111
|
+
else {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
collector.setCustomDataOnce(customData: customData)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
Sets the custom data config for a `BitmovinPlayerCollector` instance.
|
|
120
|
+
- Parameter nativeId: Native Id of the collector instance.
|
|
121
|
+
- Parameter json: Custom data config json.
|
|
122
|
+
*/
|
|
123
|
+
@objc(setCustomData:json:)
|
|
124
|
+
func setCustomData(_ nativeId: NativeId, json: Any?) {
|
|
125
|
+
bridge.uiManager.addUIBlock { [weak self] _, _ in
|
|
126
|
+
guard
|
|
127
|
+
let collector = self?.collectors[nativeId],
|
|
128
|
+
let customData = RCTConvert.analyticsCustomData(json)
|
|
129
|
+
else {
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
collector.setCustomData(customData: customData)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
Gets the current custom data config for a `BitmovinPlayerCollector` instance.
|
|
138
|
+
- Parameter nativeId: Native Id of the the collector instance.
|
|
139
|
+
- Parameter resolver: JS promise resolver.
|
|
140
|
+
- Parameter rejecter: JS promise rejecter.
|
|
141
|
+
*/
|
|
142
|
+
@objc(getCustomData:resolver:rejecter:)
|
|
143
|
+
func getCustomData(
|
|
144
|
+
_ nativeId: NativeId,
|
|
145
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
146
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
147
|
+
) {
|
|
148
|
+
bridge.uiManager.addUIBlock { [weak self] _, _ in
|
|
149
|
+
guard
|
|
150
|
+
let collector = self?.collectors[nativeId],
|
|
151
|
+
let customData = RCTConvert.toJson(analyticsCustomData: collector.getCustomData())
|
|
152
|
+
else {
|
|
153
|
+
reject("[AnalyticsModule]", "Could not find analytics collector with ID (\(nativeId))", nil)
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
resolve(customData)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
Gets the current user Id for a `BitmovinPlayerCollector` instance.
|
|
162
|
+
- Parameter nativeId: Native Id of the the collector instance.
|
|
163
|
+
- Parameter resolver: JS promise resolver.
|
|
164
|
+
- Parameter rejecter: JS promise rejecter.
|
|
165
|
+
*/
|
|
166
|
+
@objc(getUserId:resolver:rejecter:)
|
|
167
|
+
func getUserId(
|
|
168
|
+
_ nativeId: NativeId,
|
|
169
|
+
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
170
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
171
|
+
) {
|
|
172
|
+
bridge.uiManager.addUIBlock { [weak self] _, _ in
|
|
173
|
+
guard let collector = self?.collectors[nativeId] else {
|
|
174
|
+
reject("[AnalyticsModule]", "Could not find analytics collector with ID (\(nativeId))", nil)
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
resolve(collector.getUserId())
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
package/ios/Event+JSON.swift
CHANGED
|
@@ -284,3 +284,14 @@ extension AdStartedEvent {
|
|
|
284
284
|
]
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
|
+
|
|
288
|
+
extension VideoDownloadQualityChangedEvent {
|
|
289
|
+
func toJSON() -> [AnyHashable: Any] {
|
|
290
|
+
[
|
|
291
|
+
"newVideoQuality": RCTConvert.toJson(videoQuality: videoQualityNew),
|
|
292
|
+
"oldVideoQuality": RCTConvert.toJson(videoQuality: videoQualityOld),
|
|
293
|
+
"name": name,
|
|
294
|
+
"timestamp": timestamp
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import BitmovinPlayer
|
|
2
|
+
|
|
3
|
+
class FullscreenHandlerBridge: NSObject, FullscreenHandler {
|
|
4
|
+
var isFullscreen = false
|
|
5
|
+
|
|
6
|
+
private let nativeId: NativeId
|
|
7
|
+
private let bridge: RCTBridge
|
|
8
|
+
|
|
9
|
+
init(_ nativeId: NativeId, bridge: RCTBridge) {
|
|
10
|
+
self.nativeId = nativeId
|
|
11
|
+
self.bridge = bridge
|
|
12
|
+
super.init()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
func onFullscreenRequested() {
|
|
16
|
+
guard let fullscreenHandlerModule = getFullscreenHandlerModule() else {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
fullscreenHandlerModule.onFullscreenRequested(nativeId: nativeId)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
func onFullscreenExitRequested() {
|
|
23
|
+
guard let fullscreenHandlerModule = getFullscreenHandlerModule() else {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
fullscreenHandlerModule.onFullscreenExitRequested(nativeId: nativeId)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/// Fetches the initialized `FullscreenHandlerModule` instance on RN's bridge object.
|
|
30
|
+
private func getFullscreenHandlerModule() -> FullscreenHandlerModule? {
|
|
31
|
+
bridge.module(for: FullscreenHandlerModule.self) as? FullscreenHandlerModule
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
|
|
3
|
+
@interface RCT_EXTERN_REMAP_MODULE(FullscreenHandlerModule, FullscreenHandlerModule, NSObject)
|
|
4
|
+
|
|
5
|
+
RCT_EXTERN_METHOD(destroy:(NSString *)nativeId)
|
|
6
|
+
|
|
7
|
+
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(onFullscreenChanged:(NSString *)nativeId isFullscreenEnabled:(BOOL)isFullscreenEnabled)
|
|
8
|
+
RCT_EXTERN_METHOD(registerHandler:(NSString *)nativeId)
|
|
9
|
+
@end
|