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.
Files changed (43) hide show
  1. package/README.md +249 -1
  2. package/RNBitmovinPlayer.podspec +3 -1
  3. package/android/build.gradle +3 -2
  4. package/android/src/main/java/com/bitmovin/player/reactnative/AnalyticsModule.kt +154 -0
  5. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerView.kt +45 -0
  6. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +25 -4
  7. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewPackage.kt +3 -0
  8. package/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +172 -0
  9. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/Any.kt +27 -0
  10. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/ReactContextExtension.kt +8 -0
  11. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/String.kt +8 -0
  12. package/android/src/main/java/com/bitmovin/player/reactnative/ui/FullscreenHandlerBridge.kt +37 -0
  13. package/android/src/main/java/com/bitmovin/player/reactnative/ui/FullscreenHandlerModule.kt +73 -0
  14. package/ios/AnalyticsModule.m +14 -0
  15. package/ios/AnalyticsModule.swift +180 -0
  16. package/ios/Event+JSON.swift +11 -0
  17. package/ios/FullscreenHandlerBridge.swift +33 -0
  18. package/ios/FullscreenHandlerModule.m +9 -0
  19. package/ios/FullscreenHandlerModule.swift +71 -0
  20. package/ios/RCTConvert+BitmovinPlayer.swift +174 -0
  21. package/ios/RNPlayerView+PlayerListener.swift +5 -1
  22. package/ios/RNPlayerView+UserInterfaceListener.swift +16 -0
  23. package/ios/RNPlayerView.swift +5 -0
  24. package/ios/RNPlayerViewManager.m +6 -0
  25. package/ios/RNPlayerViewManager.swift +21 -0
  26. package/lib/index.d.ts +498 -51
  27. package/lib/index.js +186 -42
  28. package/lib/index.mjs +167 -26
  29. package/package.json +1 -1
  30. package/src/analytics/collector.ts +97 -0
  31. package/src/analytics/config.ts +218 -0
  32. package/src/analytics/index.ts +2 -0
  33. package/src/components/PlayerView/events.ts +10 -0
  34. package/src/components/PlayerView/index.tsx +38 -1
  35. package/src/components/PlayerView/native.ts +4 -1
  36. package/src/events.ts +43 -0
  37. package/src/index.ts +2 -0
  38. package/src/media.ts +33 -0
  39. package/src/player.ts +21 -0
  40. package/src/source.ts +4 -0
  41. package/src/styleConfig.ts +87 -0
  42. package/src/ui/fullscreenhandler.ts +19 -0
  43. package/src/ui/fullscreenhandlerbridge.ts +59 -0
package/README.md CHANGED
@@ -32,8 +32,20 @@ Official React Native bindings for Bitmovin's mobile Player SDKs.
32
32
  - [Enabling DRM protection](#enabling-drm-protection)
33
33
  - [Prepare hooks](#prepare-hooks)
34
34
  - [Adding external subtitle tracks](#adding-external-subtitle-tracks)
35
+ - [Adding external thumbnail track](#adding-external-thumbnail-track)
35
36
  - [Enabling Picture in Picture mode](#enabling-picture-in-picture-mode)
37
+ - [Android](#android)
38
+ - [iOS](#ios)
39
+ - [Showing the Picture in Picture UI option](#showing-the-picture-in-picture-ui-option)
40
+ - [Supported Picture in Picture events](#supported-picture-in-picture-events)
41
+ - [Customize HTML UI](#customize-html-ui-android-and-ios-only)
42
+ - [Setting up fullscreen handling](#setting-up-fullscreen-handling)
43
+ - [Supported fullscreen related events](#supported-fullscreen-related-events)
36
44
  - [Setting up ads](#setting-up-ads)
45
+ - [Static ads configuration](#static-ads-configuration)
46
+ - [Dynamic ads scheduling](#dynamic-ads-scheduling)
47
+ - [Supported ads events](#supported-ads-events)
48
+ - [Setting up analytics](#setting-up-analytics)
37
49
  - [Contributing](#contributing)
38
50
 
39
51
  ## Platform Support
@@ -56,7 +68,7 @@ Features of the native mobile Player SDKs are progressively being implemented in
56
68
  | -------------------------------- | ----------------------------------------- |
57
69
  | Playback of DRM-protected assets | :white_check_mark: Available since v0.2.0 |
58
70
  | Subtitles & Captions | :white_check_mark: Available since v0.2.0 |
59
- | Advertising | :gear: In progress, Q4 2022 |
71
+ | Advertising | :white_check_mark: Available since v0.4.0 |
60
72
  | Playlist API | :x: Not available |
61
73
  | Offline Playback | :x: Not available |
62
74
  | Analytics | :x: Coming Q1 2023 |
@@ -516,6 +528,38 @@ The supported `PlayerView` events for subtitles are:
516
528
 
517
529
  You might check out a complete subtitle example in the [`example/`](https://github.com/bitmovin/bitmovin-player-react-native/tree/development/example) app.
518
530
 
531
+ ### Adding external thumbnail track
532
+
533
+ Thumbnail seeking is a must have for any video longer than a few minutes. It increases usability and the general QoE [(Quality of Experience)](https://bitmovin.com/ultra-high-definition-quality-experience-mpeg-dash-part-1/) dramatically.
534
+
535
+ Setting up is simple with the Bitmovin Player. Thumbnails are loaded into the timeline as a track. All you need to do is to tell the player the location of the thumbnail file:
536
+
537
+ ```typescript
538
+ import { Platform } from 'react-native';
539
+ import {
540
+ SourceConfig,
541
+ SourceType,
542
+ SubtitleFormat,
543
+ } from 'bitmovin-player-react-native';
544
+
545
+ // Source config with an external subtitle track.
546
+ const config: SourceConfig = {
547
+ url:
548
+ Platform.OS === 'ios'
549
+ ? 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8'
550
+ : 'https://bitmovin-a.akamaihd.net/content/sintel/sintel.mpd',
551
+ type: Platform.OS === 'ios' ? SourceType.HLS : SourceType.DASH,
552
+ poster: 'https://bitmovin-a.akamaihd.net/content/sintel/poster.png',
553
+ // External thumbnail track url to be added to this source.
554
+ thumbnailTrack:
555
+ 'https://cdn.bitmovin.com/content/assets/art-of-motion-dash-hls-progressive/thumbnails/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.vtt',
556
+ };
557
+ ```
558
+
559
+ What’s required for a video player with thumbnails
560
+
561
+ Adaptive Streaming relies on encoding your video into several groups of files (streams) at various resolutions, while thumbnails also need to be generated in the encoding process. The encoder creates a set of thumbnail images and combines them into a single image file (“Sprite”). For more information on encoding your videos, have a look at our [Cloud Encoding Service](https://bitmovin.com/encoding/).
562
+
519
563
  ### Enabling Picture in Picture mode
520
564
 
521
565
  In order to make use of the Picture in Picture functionalities provided by the player, it's first necessary to configure your native application to properly support PiP.
@@ -612,6 +656,143 @@ The supported Picture in Picture events on `PlayerView` are:
612
656
 
613
657
  Check [`events.ts`](https://github.com/bitmovin/bitmovin-player-react-native/blob/development/src/components/PlayerView/events.ts) for more information about them.
614
658
 
659
+ ### Customize HTML UI (Android and iOS only)
660
+
661
+ The Bitmovin Player SDKs use the open source [Bitmovin Player Web UI](https://github.com/bitmovin/bitmovin-player-ui) on all platforms, except tvOS.
662
+ The UI is customizable in multiple ways.
663
+
664
+ #### Custom implementation
665
+
666
+ Since the Bitmovin Player Web UI is open source, it can be forked and modified to tailor to any application's needs.
667
+ See [Cusomizing the UI](https://github.com/bitmovin/bitmovin-player-ui#customizing-the-ui) section for details.
668
+
669
+ In case a custom implementation of the Player UI is desired, configure the hosted JS and CSS files via the `StyleConfig` as shown in the following example:
670
+
671
+ ```ts
672
+ const player = usePlayer({
673
+ styleConfig: {
674
+ playerUiCss: 'CUSTOM_UI_CSS_URL',
675
+ playerUiJs: 'CUSTOM_UI_JS_URL',
676
+ },
677
+ });
678
+ ```
679
+
680
+ #### Custom CSS
681
+
682
+ Customization of the default built-in Bitmovin Player UI is possible via providing custom styling CSS by only configuring `playerUiCss` as shown in the following example:
683
+
684
+ ```ts
685
+ const player = usePlayer({
686
+ styleConfig: {
687
+ playerUiCss: 'CUSTOM_UI_CSS_URL',
688
+ },
689
+ });
690
+ ```
691
+
692
+ #### Supplemental CSS
693
+
694
+ In case the usage of the default Bitmovin Player UI is sufficient with minor additional styling, it can be achieved via providing the URL to the additional CSS stylesheet via `supplementalPlayerUiCss`.
695
+
696
+ ```ts
697
+ const player = usePlayer({
698
+ styleConfig: {
699
+ supplementalPlayerUiCss: 'SUPPLEMENTAL_UI_CSS_URL',
700
+ },
701
+ });
702
+ ```
703
+
704
+ ### Setting up fullscreen handling
705
+
706
+ In order to enable the player to support fullscreen and show the fullscreen button when using the Bitmovin Player Web UI, a `FullscreenHandler` needs to be implemented.
707
+ Its responsibility is to update the UI when transitioning between fullscreen and non-fullscreen states.
708
+ The player view itself does not update it's presentation as the meaning of fullscreen is determined by the application integrating our library.
709
+
710
+ Here are the basics of enabling fullscreen support:
711
+
712
+ ```typescript
713
+ // Define a handler to take care of fullscreen transitions
714
+ class SampleFullscreenHandler implements FullscreenHandler {
715
+ isFullscreenActive: boolean = true;
716
+ onFullscreen: (fullscreenMode: boolean) => void;
717
+
718
+ constructor(
719
+ isFullscreenActive: boolean,
720
+ onFullscreen: (fullscreenMode: boolean) => void
721
+ ) {
722
+ this.isFullscreenActive = isFullscreenActive;
723
+ this.onFullscreen = onFullscreen;
724
+ }
725
+
726
+ enterFullscreen(): void {
727
+ // Update UI state for fullscreen mode
728
+ this.onFullscreen(true);
729
+ this.isFullscreenActive = true;
730
+ console.log('enter fullscreen');
731
+ }
732
+
733
+ exitFullscreen(): void {
734
+ // Update UI state for non-fullscreen mode
735
+ this.onFullscreen(false);
736
+ this.isFullscreenActive = false;
737
+ console.log('exit fullscreen');
738
+ }
739
+ }
740
+
741
+ export default function BasicFullscreenHandling() {
742
+ // Set up player and other components
743
+
744
+ // Create SampleFullscreenHandler instance and enable it to update state
745
+ const [fullscreenMode, setFullscreenMode] = useState(false);
746
+ const fullscreenHandler = new SampleFullscreenHandler(
747
+ fullscreenMode,
748
+ setFullscreenMode
749
+ );
750
+
751
+ return (
752
+ <View>
753
+ <PlayerView
754
+ player={player}
755
+ style={fullscreenMode ? styles.playerFullscreen : styles.player}
756
+ fullscreenHandler={fullscreenHandler}
757
+ onFullscreenEnter={onFullscreenEnter}
758
+ onFullscreenExit={onFullscreenExit}
759
+ onFullscreenEnabled={onFullscreenEnabled}
760
+ onFullscreenDisabled={onFullscreenDisabled}
761
+ />
762
+ </View>
763
+ );
764
+ }
765
+
766
+ // Define your styles
767
+ const styles = StyleSheet.create({
768
+ player: {
769
+ flex: 1,
770
+ backgroundColor: 'black',
771
+ },
772
+ playerFullscreen: {
773
+ position: 'absolute',
774
+ top: 0,
775
+ right: 0,
776
+ bottom: 0,
777
+ left: 0,
778
+ backgroundColor: 'black',
779
+ },
780
+ });
781
+ ```
782
+
783
+ Check [`BasicFullscreenHandling.tsx`](https://github.com/bitmovin/bitmovin-player-react-native/blob/development/example/src/screens/BasicFullscreenHandling.tsx) for a full example implementation.
784
+
785
+ #### Supported fullscreen related events
786
+
787
+ The supported fullscreen events on `PlayerView` are:
788
+
789
+ - `onFullscreenEnter`
790
+ - `onFullscreenExit`
791
+ - `onFullscreenEnabled`
792
+ - `onFullscreenDisabled`
793
+
794
+ Check [`events.ts`](https://github.com/bitmovin/bitmovin-player-react-native/blob/development/src/components/PlayerView/events.ts) for more information about them.
795
+
615
796
  ### Setting up ads
616
797
 
617
798
  The Bitmovin Player SDKs are capable of displaying Ads out of the box and there are two ways they can be
@@ -700,6 +881,73 @@ The supported `PlayerView` events for ads are:
700
881
 
701
882
  You can check out a complete ads example in the [`example/`](https://github.com/bitmovin/bitmovin-player-react-native/tree/development/example) app.
702
883
 
884
+ ### Setting up analytics
885
+
886
+ Each `Player` instance has an associated analytics collector that can be configured to send analytics information about it. By default,
887
+ the associated collector is disabled unless an `analyticsConfig` option is specified. So in order to get analytics up and running, add the following configuration options to your `PlayerConfig`:
888
+
889
+ ```typescript
890
+ const player = usePlayer({
891
+ analyticsConfig: {
892
+ // Bitmovin analytics key from the Analytics Dashboard
893
+ key: '<ANALYTICS-KEY>', // `key` is the only required parameter.
894
+ // Bitmovin player license key
895
+ playerKey: '<BITMOVIN-PLAYER-KEY>',
896
+ // Asset CDN provider. Check out `CdnProvider` on `src/analytics/config.ts` for more options.
897
+ cdnProvider: CdnProvider.AKAMAI,
898
+ // User-defined user ID.
899
+ customUserId: 'Custom user ID',
900
+ // Whether the user ID should be randomly generated or not. Default value is false.
901
+ randomizeUserId: false,
902
+ // Experiment name that'll appear at the Analytics Dashboard.
903
+ experimentName: 'Experiment name',
904
+ // Video ID on your server
905
+ videoId: 'MyVideoId',
906
+ // Video title
907
+ title: 'Art of Motion',
908
+ // Whether this is a live stream video. Default is false.
909
+ isLive: false,
910
+ // Whether collector should also collect statistics about ads
911
+ // Can be changed to `true` in case `advertisingConfig` is also present.
912
+ // Default is false.
913
+ ads: false,
914
+ // Navigation breadcrumb.
915
+ // The path taken by the user inside your application.
916
+ path: '/examples/basic_analytics',
917
+ // List of custom data fields to be registered at the Analytics Dashboard.
918
+ // Useful to customize collection with your own data along with the SDK.
919
+ customData1: 'Custom data field 1',
920
+ customData2: 'Custom data field 2',
921
+ customData3: 'Custom data field 3',
922
+ customData4: 'Custom data field 4',
923
+ customData5: 'Custom data field 5',
924
+ // Usage of customData properties are supported up to 30 fields
925
+ customData30: 'Custom data field 30',
926
+ },
927
+ });
928
+ ```
929
+
930
+ And that's it. Now you should start receiving analytics information about your `player` instance on the [Analytics Dashboard](https://bitmovin.com/dashboard/analytics).
931
+
932
+ Optionally, you can also access the configured `analyticsCollector` object in order to get some information (like `userId`) or
933
+ update your custom data during runtime:
934
+
935
+ ```typescript
936
+ // Get the current user id.
937
+ const userId = await player.analyticsCollector?.getUserId();
938
+
939
+ // Get the current custom data config.
940
+ const customData = await player.analyticsCollector?.getCustomData();
941
+
942
+ // Update the current custom data config.
943
+ player.analyticsCollector?.setCustomDataOnce({
944
+ customData2: 'Updated custom data field 2',
945
+ customData4: 'Updated custom data field 4',
946
+ });
947
+ ```
948
+
949
+ You can check out a complete analytics example in the [`example/`](https://github.com/bitmovin/bitmovin-player-react-native/tree/development/example) app.
950
+
703
951
  ## Contributing
704
952
 
705
953
  See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
@@ -19,7 +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.30.0"
22
+ s.dependency "BitmovinPlayer", "3.32.0"
23
+ s.dependency "BitmovinAnalyticsCollector/Core", "2.9.4"
24
+ s.dependency "BitmovinAnalyticsCollector/BitmovinPlayer", "2.9.4"
23
25
  s.ios.dependency "GoogleAds-IMA-iOS-SDK", "3.17.0"
24
26
  s.tvos.dependency "GoogleAds-IMA-tvOS-SDK", "4.6.1"
25
27
  end
@@ -1,6 +1,6 @@
1
1
  buildscript {
2
2
  ext {
3
- kotlinVersion = '1.7.20'
3
+ kotlinVersion = '1.7.21'
4
4
  androidToolsVersion = '7.0.4'
5
5
  }
6
6
  repositories {
@@ -52,6 +52,7 @@ dependencies {
52
52
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
53
53
  implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.26.0'
54
54
  implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
55
- implementation 'com.bitmovin.player:player:3.25.2'
55
+ implementation 'com.bitmovin.analytics:collector-bitmovin-player:2.12.1'
56
+ implementation 'com.bitmovin.player:player:3.26.1'
56
57
  implementation 'com.facebook.react:react-native:+'
57
58
  }
@@ -0,0 +1,154 @@
1
+ package com.bitmovin.player.reactnative
2
+
3
+ import com.bitmovin.analytics.bitmovin.player.BitmovinPlayerCollector
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 = "AnalyticsModule"
10
+
11
+ @ReactModule(name = MODULE_NAME)
12
+ class AnalyticsModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
13
+ /**
14
+ * In-memory mapping from `nativeId`s to `BitmovinPlayerCollector` instances.
15
+ */
16
+ private val collectors: Registry<BitmovinPlayerCollector> = mutableMapOf()
17
+
18
+ /**
19
+ * JS exported module name.
20
+ */
21
+ override fun getName() = MODULE_NAME
22
+
23
+ /**
24
+ * Fetches the `BitmovinPlayerCollector` instance associated with `nativeId` from the internal registry.
25
+ * @param nativeId `BitmovinPlayerCollector` instance ID.
26
+ * @return The associated `BitmovinPlayerCollector` instance or `null`.
27
+ */
28
+ fun getCollector(nativeId: NativeId?): BitmovinPlayerCollector? {
29
+ if (nativeId == null) {
30
+ return null
31
+ }
32
+ return collectors[nativeId]
33
+ }
34
+
35
+ /**
36
+ * Creates a new `BitmovinPlayerCollector` instance inside the internal registry using the provided `config` object.
37
+ * @param config `BitmovinAnalyticsConfig` object received from JS.
38
+ */
39
+ @ReactMethod
40
+ fun initWithConfig(nativeId: NativeId, config: ReadableMap?) {
41
+ uiManager()?.addUIBlock { _ ->
42
+ JsonConverter.toAnalyticsConfig(config)?.let {
43
+ collectors[nativeId] = BitmovinPlayerCollector(it, context)
44
+ }
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Detaches and removes the given `BitmovinPlayerCollector` from the internal registry.
50
+ * @param nativeId Native Id of the collector instance.
51
+ */
52
+ @ReactMethod
53
+ fun destroy(nativeId: NativeId) {
54
+ uiManager()?.addUIBlock {
55
+ if (collectors.containsKey(nativeId)) {
56
+ collectors[nativeId]?.detachPlayer()
57
+ collectors.remove(nativeId)
58
+ }
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Attaches a `BitmovinPlayerCollector` to the `Player` instance with native Id equal to `playerId`.
64
+ * @param nativeId Native Id of the collector instance.
65
+ * @param playerId Native Id of the player instance.
66
+ */
67
+ @ReactMethod
68
+ fun attach(nativeId: NativeId, playerId: NativeId) {
69
+ uiManager()?.addUIBlock { _ ->
70
+ playerModule()?.getPlayer(playerId)?.let {
71
+ collectors[nativeId]?.attachPlayer(it)
72
+ }
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Detaches the player object from a `BitmovinPlayerCollector` instance.
78
+ * @param nativeId Native Id of the collector instance.
79
+ */
80
+ @ReactMethod
81
+ fun detach(nativeId: NativeId) {
82
+ uiManager()?.addUIBlock { _ ->
83
+ collectors[nativeId]?.detachPlayer()
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Updates the custom data config for a `BitmovinPlayerCollector` instance.
89
+ * @param nativeId Native Id of the collector instance.
90
+ * @param json Custom data config json.
91
+ */
92
+ @ReactMethod
93
+ fun setCustomDataOnce(nativeId: NativeId, json: ReadableMap?) {
94
+ uiManager()?.addUIBlock { _ ->
95
+ JsonConverter.toAnalyticsCustomData(json)?.let {
96
+ collectors[nativeId]?.setCustomDataOnce(it)
97
+ }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Sets the custom data config for a `BitmovinPlayerCollector` instance.
103
+ * @param nativeId Native Id of the collector instance.
104
+ * @param json Custom data config json.
105
+ */
106
+ @ReactMethod
107
+ fun setCustomData(nativeId: NativeId, json: ReadableMap?) {
108
+ uiManager()?.addUIBlock { _ ->
109
+ JsonConverter.toAnalyticsCustomData(json)?.let {
110
+ collectors[nativeId]?.customData = it
111
+ }
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Gets the current custom data config for a `BitmovinPlayerCollector` instance.
117
+ * @param nativeId Native Id of the the collector instance.
118
+ * @param promise JS promise object.
119
+ */
120
+ @ReactMethod
121
+ fun getCustomData(nativeId: NativeId, promise: Promise) {
122
+ uiManager()?.addUIBlock { _ ->
123
+ collectors[nativeId]?.let {
124
+ promise.resolve(JsonConverter.fromAnalyticsCustomData(it.customData))
125
+ }
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Gets the current user Id for a `BitmovinPlayerCollector` instance.
131
+ * @param nativeId Native Id of the the collector instance.
132
+ * @param promise JS promise object.
133
+ */
134
+ @ReactMethod
135
+ fun getUserId(nativeId: NativeId, promise: Promise) {
136
+ uiManager()?.addUIBlock { _ ->
137
+ collectors[nativeId]?.let {
138
+ promise.resolve(it.userId)
139
+ }
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Helper function that gets the instantiated `UIManagerModule` from modules registry.
145
+ */
146
+ private fun uiManager(): UIManagerModule? =
147
+ context.getNativeModule(UIManagerModule::class.java)
148
+
149
+ /**
150
+ * Helper function that gets the instantiated `PlayerModule` from modules registry.
151
+ */
152
+ private fun playerModule(): PlayerModule? =
153
+ context.getNativeModule(PlayerModule::class.java)
154
+ }
@@ -451,6 +451,41 @@ class RNPlayerView(val context: ReactApplicationContext) : LinearLayout(context)
451
451
  emitEvent("adStarted", it)
452
452
  }
453
453
 
454
+ /**
455
+ * `onVideoPlaybackQualityChanged` event callback.
456
+ */
457
+ private val onVideoPlaybackQualityChanged: (PlayerEvent.VideoPlaybackQualityChanged) -> Unit = {
458
+ emitEvent("videoPlaybackQualityChanged", it)
459
+ }
460
+
461
+ /**
462
+ * `onFullscreenEnabled` event callback.
463
+ */
464
+ private val onFullscreenEnabled: (PlayerEvent.FullscreenEnabled) -> Unit = {
465
+ emitEvent("fullscreenEnabled", it)
466
+ }
467
+
468
+ /**
469
+ * `onFullscreenEnabled` event callback.
470
+ */
471
+ private val onFullscreenDisabled: (PlayerEvent.FullscreenDisabled) -> Unit = {
472
+ emitEvent("fullscreenDisabled", it)
473
+ }
474
+
475
+ /**
476
+ * `onFullscreenEnter` event callback.
477
+ */
478
+ private val onFullscreenEnter: (PlayerEvent.FullscreenEnter) -> Unit = {
479
+ emitEvent("fullscreenEnter", it)
480
+ }
481
+
482
+ /**
483
+ * `onFullscreenEnter` event callback.
484
+ */
485
+ private val onFullscreenExit: (PlayerEvent.FullscreenExit) -> Unit = {
486
+ emitEvent("fullscreenExit", it)
487
+ }
488
+
454
489
  /**
455
490
  * Start listening and emitting player events as bubbling events to the js side.
456
491
  */
@@ -491,11 +526,16 @@ class RNPlayerView(val context: ReactApplicationContext) : LinearLayout(context)
491
526
  on(onAdScheduled)
492
527
  on(onAdSkipped)
493
528
  on(onAdStarted)
529
+ on(onVideoPlaybackQualityChanged)
494
530
  }
495
531
  playerView?.apply {
496
532
  on(onPictureInPictureAvailabilityChanged)
497
533
  on(onPictureInPictureEnter)
498
534
  on(onPictureInPictureExit)
535
+ on(onFullscreenEnabled)
536
+ on(onFullscreenDisabled)
537
+ on(onFullscreenEnter)
538
+ on(onFullscreenExit)
499
539
  }
500
540
  }
501
541
 
@@ -539,11 +579,16 @@ class RNPlayerView(val context: ReactApplicationContext) : LinearLayout(context)
539
579
  off(onAdScheduled)
540
580
  off(onAdSkipped)
541
581
  off(onAdStarted)
582
+ off(onVideoPlaybackQualityChanged)
542
583
  }
543
584
  playerView?.apply {
544
585
  off(onPictureInPictureAvailabilityChanged)
545
586
  off(onPictureInPictureEnter)
546
587
  off(onPictureInPictureExit)
588
+ off(onFullscreenEnabled)
589
+ off(onFullscreenDisabled)
590
+ off(onFullscreenEnter)
591
+ off(onFullscreenExit)
547
592
  }
548
593
  }
549
594
 
@@ -4,6 +4,9 @@ import android.os.Handler
4
4
  import android.os.Looper
5
5
  import android.view.ViewGroup.LayoutParams
6
6
  import com.bitmovin.player.PlayerView
7
+ import com.bitmovin.player.reactnative.extensions.getModule
8
+ import com.bitmovin.player.reactnative.ui.FullscreenHandlerBridge
9
+ import com.bitmovin.player.reactnative.ui.FullscreenHandlerModule
7
10
  import com.bitmovin.player.reactnative.ui.RNPictureInPictureHandler
8
11
  import com.facebook.react.bridge.*
9
12
  import com.facebook.react.module.annotations.ReactModule
@@ -19,6 +22,7 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
19
22
  */
20
23
  enum class Commands {
21
24
  ATTACH_PLAYER,
25
+ ATTACH_FULLSCREEN_BRIDGE
22
26
  }
23
27
 
24
28
  /**
@@ -91,6 +95,11 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
91
95
  "adScheduled" to "onAdScheduled",
92
96
  "adSkipped" to "onAdSkipped",
93
97
  "adStarted" to "onAdStarted",
98
+ "videoPlaybackQualityChanged" to "onVideoPlaybackQualityChanged",
99
+ "fullscreenEnabled" to "onFullscreenEnabled",
100
+ "fullscreenDisabled" to "onFullscreenDisabled",
101
+ "fullscreenEnter" to "onFullscreenEnter",
102
+ "fullscreenExit" to "onFullscreenExit",
94
103
  )
95
104
 
96
105
  /**
@@ -112,7 +121,8 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
112
121
  * @return map between names (used in js) and command ids (used in native code).
113
122
  */
114
123
  override fun getCommandsMap(): MutableMap<String, Int> = mutableMapOf(
115
- "attachPlayer" to Commands.ATTACH_PLAYER.ordinal
124
+ "attachPlayer" to Commands.ATTACH_PLAYER.ordinal,
125
+ "attachFullscreenBridge" to Commands.ATTACH_FULLSCREEN_BRIDGE.ordinal,
116
126
  )
117
127
 
118
128
  /**
@@ -126,11 +136,22 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
126
136
  commandId?.toInt()?.let {
127
137
  when (it) {
128
138
  Commands.ATTACH_PLAYER.ordinal -> attachPlayer(view, args?.getString(1), args?.getMap(2))
139
+ Commands.ATTACH_FULLSCREEN_BRIDGE.ordinal -> args?.getString(1)?.let { fullscreenBridgeId ->
140
+ attachFullscreenBridge(view, fullscreenBridgeId)
141
+ }
129
142
  else -> {}
130
143
  }
131
144
  }
132
145
  }
133
146
 
147
+ private fun attachFullscreenBridge(view: RNPlayerView, fullscreenBridgeId: NativeId) {
148
+ Handler(Looper.getMainLooper()).post {
149
+ view.playerView?.setFullscreenHandler(
150
+ context.getModule<FullscreenHandlerModule>()?.getInstance(fullscreenBridgeId)
151
+ )
152
+ }
153
+ }
154
+
134
155
  /**
135
156
  * Set the `Player` instance for the target view using `playerId`.
136
157
  * @param view Target `RNPlayerView`.
@@ -149,7 +170,8 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
149
170
  val playerView = PlayerView(context, player)
150
171
  playerView.layoutParams = LayoutParams(
151
172
  LayoutParams.MATCH_PARENT,
152
- LayoutParams.MATCH_PARENT)
173
+ LayoutParams.MATCH_PARENT
174
+ )
153
175
  view.addPlayerView(playerView)
154
176
  }
155
177
  }
@@ -158,6 +180,5 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
158
180
  /**
159
181
  * Helper function that gets the instantiated `PlayerModule` from modules registry.
160
182
  */
161
- private fun getPlayerModule(): PlayerModule? =
162
- context.getNativeModule(PlayerModule::class.java)
183
+ private fun getPlayerModule(): PlayerModule? = context.getModule()
163
184
  }
@@ -1,6 +1,7 @@
1
1
  package com.bitmovin.player.reactnative
2
2
 
3
3
  import android.view.View
4
+ import com.bitmovin.player.reactnative.ui.FullscreenHandlerModule
4
5
  import com.facebook.react.ReactPackage
5
6
  import com.facebook.react.bridge.NativeModule
6
7
  import com.facebook.react.bridge.ReactApplicationContext
@@ -21,7 +22,9 @@ class RNPlayerViewPackage : ReactPackage {
21
22
  PlayerModule(reactContext),
22
23
  SourceModule(reactContext),
23
24
  DrmModule(reactContext),
25
+ AnalyticsModule(reactContext),
24
26
  RNPlayerViewManager(reactContext),
27
+ FullscreenHandlerModule(reactContext)
25
28
  )
26
29
  }
27
30