bitmovin-player-react-native 0.3.0 → 0.4.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 (36) hide show
  1. package/README.md +238 -24
  2. package/RNBitmovinPlayer.podspec +3 -1
  3. package/android/build.gradle +7 -5
  4. package/android/src/main/java/com/bitmovin/player/reactnative/DrmModule.kt +4 -5
  5. package/android/src/main/java/com/bitmovin/player/reactnative/PlayerModule.kt +41 -5
  6. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerView.kt +273 -2
  7. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +45 -5
  8. package/android/src/main/java/com/bitmovin/player/reactnative/SourceModule.kt +4 -5
  9. package/android/src/main/java/com/bitmovin/player/reactnative/UuidModule.kt +3 -1
  10. package/android/src/main/java/com/bitmovin/player/reactnative/converter/JsonConverter.kt +301 -7
  11. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/ReadableArray.kt +35 -0
  12. package/android/src/main/java/com/bitmovin/player/reactnative/extensions/WritableMap.kt +19 -0
  13. package/android/src/main/java/com/bitmovin/player/reactnative/ui/RNPictureInPictureHandler.kt +191 -0
  14. package/ios/AudioSessionModule.m +10 -0
  15. package/ios/AudioSessionModule.swift +65 -0
  16. package/ios/Event+JSON.swift +123 -0
  17. package/ios/PlayerModule.m +6 -0
  18. package/ios/PlayerModule.swift +44 -0
  19. package/ios/RCTConvert+BitmovinPlayer.swift +285 -15
  20. package/ios/RNPlayerView+PlayerListener.swift +52 -0
  21. package/ios/RNPlayerView+UserInterfaceListener.swift +19 -0
  22. package/ios/RNPlayerView.swift +17 -0
  23. package/ios/RNPlayerViewManager.m +18 -1
  24. package/ios/RNPlayerViewManager.swift +2 -1
  25. package/lib/index.d.ts +577 -3
  26. package/lib/index.js +92 -33
  27. package/lib/index.mjs +75 -19
  28. package/package.json +1 -1
  29. package/src/advertising.ts +155 -0
  30. package/src/audioSession.ts +47 -0
  31. package/src/components/PlayerView/events.ts +39 -3
  32. package/src/components/PlayerView/index.tsx +31 -11
  33. package/src/events.ts +212 -0
  34. package/src/index.ts +2 -0
  35. package/src/player.ts +41 -1
  36. package/src/tweaksConfig.ts +153 -0
package/README.md CHANGED
@@ -7,25 +7,33 @@ Official React Native bindings for Bitmovin's mobile Player SDKs.
7
7
  [![MIT License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)
8
8
  [![Bitmovin Community](https://img.shields.io/discourse/users?label=community&server=https%3A%2F%2Fcommunity.bitmovin.com)](https://community.bitmovin.com/?utm_source=github&utm_medium=bitmovin-player-react-native&utm_campaign=dev-community)
9
9
 
10
- > The library is under active development.
10
+ > As the library is under active development, this means certain features from our native SDKs are not yet exposed through these React Native bindings.
11
+ > See [Feature Support](#feature-support) for an overview of the supported features.
12
+ >
13
+ > Not seeing the features you’re looking for?
14
+ > We are accepting community pull requests to this open-source project so please feel free to contribute.
15
+ > or let us know in [our community](https://community.bitmovin.com/c/requests/14) what features we should work on next.
11
16
 
12
17
  - [Bitmovin Player React Native](#bitmovin-player-react-native)
13
18
  - [Platform Support](#platform-support)
19
+ - [Feature Support](#feature-support)
14
20
  - [Installation](#installation)
15
21
  - [Add package dependency](#add-package-dependency)
16
22
  - [Setup iOS Player SDK](#setup-ios-player-sdk)
17
23
  - [Setup Android Player SDK](#setup-android-player-sdk)
18
24
  - [Getting Started](#getting-started)
19
25
  - [Setting up a license key](#setting-up-a-license-key)
20
- - [Configuring through code](#configuring-through-code)
21
- - [Setting up a playback configurations](#setting-up-a-playback-configurations)
22
- - [Configuring `Info.plist`](#configuring-infoplist)
23
- - [Configuring `AndroidManifest.xml`](#configuring-androidmanifestxml)
26
+ - [Through code](#through-code)
27
+ - [Through `Info.plist`](#through-infoplist)
28
+ - [Through `AndroidManifest.xml`](#through-androidmanifestxml)
29
+ - [Setting up the playback configuration](#setting-up-the-playback-configuration)
24
30
  - [Accessing native `Player` instances](#accessing-native-player-instances)
25
31
  - [Listening to events](#listening-to-events)
26
32
  - [Enabling DRM protection](#enabling-drm-protection)
27
33
  - [Prepare hooks](#prepare-hooks)
28
34
  - [Adding external subtitle tracks](#adding-external-subtitle-tracks)
35
+ - [Enabling Picture in Picture mode](#enabling-picture-in-picture-mode)
36
+ - [Setting up ads](#setting-up-ads)
29
37
  - [Contributing](#contributing)
30
38
 
31
39
  ## Platform Support
@@ -40,6 +48,19 @@ This library requires at least React Native 0.64+ and React 17+ to work properly
40
48
 
41
49
  Please note that browsers and other browser-like environments such as webOS and Tizen are not supported.
42
50
 
51
+ ## Feature Support
52
+
53
+ Features of the native mobile Player SDKs are progressively being implemented in this React Native library. The table below summarizes the current state of the main Player SDK features.
54
+
55
+ | Feature | State |
56
+ | -------------------------------- | ----------------------------------------- |
57
+ | Playback of DRM-protected assets | :white_check_mark: Available since v0.2.0 |
58
+ | Subtitles & Captions | :white_check_mark: Available since v0.2.0 |
59
+ | Advertising | :gear: In progress, Q4 2022 |
60
+ | Playlist API | :x: Not available |
61
+ | Offline Playback | :x: Not available |
62
+ | Analytics | :x: Coming Q1 2023 |
63
+
43
64
  ## Installation
44
65
 
45
66
  Since Bitmovin's native SDKs are distributed through custom [Cocoapods](https://github.com/bitmovin/cocoapod-specs) and [Maven](https://artifacts.bitmovin.com/ui/native/public-releases) repositories, the installation cannot be managed by React Native's Autolink and requires some extra steps. Please refer to the installation instructions for each platform below. For more information on integrating the native SDKs, refer to the [Getting Started guides](https://bitmovin.com/docs/getting-started).
@@ -200,7 +221,7 @@ First of all, create a license key on the [Dashboard](https://bitmovin.com/dashb
200
221
 
201
222
  Then your license key can be either set from code or by configuring `Info.plist` and `AndroidManifest.xml`.
202
223
 
203
- #### Configuring through code
224
+ #### Through code
204
225
 
205
226
  ```typescript
206
227
  // Simply pass the `licenseKey` property to `PlayerConfig` when instantiating a player.
@@ -219,7 +240,24 @@ const player = new Player({
219
240
  });
220
241
  ```
221
242
 
222
- ### Setting up a playback configurations
243
+ #### Through `Info.plist`
244
+
245
+ Add the following lines to the `<dict>` section of your `ios/Info.plist`:
246
+
247
+ ```xml
248
+ <key>BitmovinPlayerLicenseKey</key>
249
+ <string>ENTER-YOUR-LICENSE-KEY</string>
250
+ ```
251
+
252
+ #### Through `AndroidManifest.xml`
253
+
254
+ Add the following line to the `<application>` section of your `android/app/src/main/AndroidManifest.xml`:
255
+
256
+ ```xml
257
+ <meta-data android:name="BITMOVIN_PLAYER_LICENSE_KEY" android:value="ENTER-YOUR-LICENSE-KEY" />
258
+ ```
259
+
260
+ ### Setting up the playback configuration
223
261
 
224
262
  If needed, the default player behavior can be configured through the `playbackConfig` key when initialized.
225
263
 
@@ -239,6 +277,14 @@ const player = usePlayer({
239
277
  // Whether background playback is enabled or not. Default is false.
240
278
  // Only available for iOS.
241
279
  isBackgroundPlaybackEnabled: true,
280
+ // Enable the Picture in Picture mode option on the player controls.
281
+ //
282
+ // Note iOS requires the audio session category of your app to be set to `playback` otherwise
283
+ // PiP mode won't work.
284
+ //
285
+ // Check out `Enabling Picture in Picture mode` section of README for more information
286
+ // on how to properly configure your app to support PiP.
287
+ isPictureInPictureEnabled: true,
242
288
  },
243
289
  });
244
290
 
@@ -251,27 +297,11 @@ const player = new Player({
251
297
  isMuted: true,
252
298
  isTimeShiftEnabled: true,
253
299
  isBackgroundPlaybackEnabled: true,
300
+ isPictureInPictureEnabled: true,
254
301
  },
255
302
  });
256
303
  ```
257
304
 
258
- #### Configuring `Info.plist`
259
-
260
- Add the following lines to the `<dict>` section of your `ios/Info.plist`:
261
-
262
- ```xml
263
- <key>BitmovinPlayerLicenseKey</key>
264
- <string>ENTER-YOUR-LICENSE-KEY</string>
265
- ```
266
-
267
- #### Configuring `AndroidManifest.xml`
268
-
269
- Add the following line to the `<application>` section of your `android/app/src/main/AndroidManifest.xml`:
270
-
271
- ```xml
272
- <meta-data android:name="BITMOVIN_PLAYER_LICENSE_KEY" android:value="ENTER-YOUR-LICENSE-KEY" />
273
- ```
274
-
275
305
  ### Accessing native `Player` instances
276
306
 
277
307
  When you instantiate a player with `usePlayer` or `new Player()` from javascript, you're actually either creating a new `Player` instance in the native side (see [SDKs docs](https://bitmovin.com/docs/player/sdks) for more info) or referencing an existing one.
@@ -486,6 +516,190 @@ The supported `PlayerView` events for subtitles are:
486
516
 
487
517
  You might check out a complete subtitle example in the [`example/`](https://github.com/bitmovin/bitmovin-player-react-native/tree/development/example) app.
488
518
 
519
+ ### Enabling Picture in Picture mode
520
+
521
+ 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.
522
+
523
+ The steps required for each platform are described below:
524
+
525
+ #### Android
526
+
527
+ **Declare Picture in Picture support on AndroidManifest.xml**
528
+
529
+ Open `android/app/src/main/AndroidManifest.xml` and set `android:supportsPictureInPicture` to `true`
530
+ on your main activity's manifest. Also, specify that your activity handles layout configuration changes
531
+ so that your activity doesn't relaunch when layout changes occur during PiP mode transitions:
532
+
533
+ ```xml
534
+ <activity android:name=".MainActivity"
535
+ android:supportsPictureInPicture="true"
536
+ android:configChanges=
537
+ "screenSize|smallestScreenSize|screenLayout|orientation"
538
+ ...
539
+ ```
540
+
541
+ #### iOS
542
+
543
+ **Set background modes capability**
544
+
545
+ Make sure to add the `UIBackgroundModes` key to the `dict` section of your `Info.plist`:
546
+
547
+ ```xml
548
+ <key>UIBackgroundModes</key>
549
+ <array>
550
+ <string>audio</string>
551
+ </array>
552
+ ```
553
+
554
+ This step can also be performed from [Xcode](https://developer.apple.com/documentation/xcode/configuring-background-execution-modes).
555
+
556
+ **Configure audio session on app startup**
557
+
558
+ Configure your app's `AudioSession` category to `playback` during the main component's initialization:
559
+
560
+ ```typescript
561
+ import { AudioSession } from 'bitmovin-player-react-native';
562
+
563
+ // App's root component
564
+ const App = () => {
565
+ useEffect(() => {
566
+ // Set your app's `AudioSession` category to `playback` on initialization.
567
+ // Please, note even though this step is required for iOS it won't take any effect on Android.
568
+ AudioSession.setCategory('playback').catch((error) => {
569
+ // Handle any native error that might occur during this process.
570
+ handleError(error);
571
+ });
572
+ });
573
+ // ...
574
+ return /* ... */;
575
+ };
576
+ ```
577
+
578
+ This step is required in order to properly enable background playback on iOS. Without it, the Picture in Picture option appears on the player UI but has no effect when used.
579
+
580
+ You can read more about it on [Apple's docs](https://developer.apple.com/documentation/avfaudio/avaudiosession/category/1616509-playback).
581
+
582
+ #### Showing the Picture in Picture UI option
583
+
584
+ Now that your native application is properly configured to support PiP changes, the player instance
585
+ in your JS code can be configured to show the Picture in Picture option in the player UI.
586
+
587
+ Simply add `isPictureInPictureEnabled: true` on your player's `playbackConfig` option:
588
+
589
+ ```typescript
590
+ const player = usePlayer({
591
+ playbackConfig: {
592
+ isPictureInPictureEnabled: true,
593
+ },
594
+ });
595
+ ```
596
+
597
+ #### Supported Picture in Picture events
598
+
599
+ The supported Picture in Picture events on `PlayerView` are:
600
+
601
+ - `onPictureInPictureEnter`
602
+ - `onPictureInPictureExit`
603
+
604
+ **iOS only**
605
+
606
+ - `onPictureInPictureEntered`
607
+ - `onPictureInPictureExited`
608
+
609
+ **Android only**
610
+
611
+ - `onPictureInPictureAvailabilityChanged`
612
+
613
+ Check [`events.ts`](https://github.com/bitmovin/bitmovin-player-react-native/blob/development/src/components/PlayerView/events.ts) for more information about them.
614
+
615
+ ### Setting up ads
616
+
617
+ The Bitmovin Player SDKs are capable of displaying Ads out of the box and there are two ways they can be
618
+ configured with the player. One option is to use static configuration in the player config object,
619
+ and the other is to schedule them dynamically using `Player.scheduleAd`.
620
+
621
+ #### Static ads configuration
622
+
623
+ The easiest way to configure Ads is by adding the `advertisingConfig` property to the player configuration object.
624
+ All that needs to be provided is a URL pointing to a target Ad tag along with the type of the tag.
625
+
626
+ ```typescript
627
+ const player = usePlayer({
628
+ licenseKey: '<PLAYER_LICENSE_KEY>',
629
+ advertisingConfig: {
630
+ // Each object in `schedule` represents an `AdItem`.
631
+ schedule: [
632
+ // An `AdItem` represents a time slot within the streamed content dedicated to ads playback.
633
+ {
634
+ // Each item specifies a list of sources with a type and URL to the ad manifest in the ads
635
+ // server. All but the first source act as fallback if the first one fails to load.
636
+ // The start and end of an ad break are signaled via `AdBreakStartedEvent` and `AdBreakFinishedEvent`.
637
+ sources: [
638
+ {
639
+ type: AdSourceType.IMA,
640
+ tag: 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dskippablelinear&correlator=',
641
+ },
642
+ // Fallback sources...
643
+ ],
644
+ // Each item also specifies the position where it should appear during playback.
645
+ // The possible position values are documented below.
646
+ // The default value is `pre`.
647
+ position: '20%',
648
+ },
649
+ ],
650
+ },
651
+ });
652
+ ```
653
+
654
+ The possible `AdItem` position values are:
655
+
656
+ - `"pre"`: pre-roll ad (for VoD and Live streaming; appears before playback starts)
657
+ - `"post"`: post-roll ad (for VoD streaming only; appears after playback finishes)
658
+ - Fractional seconds: `"10"`, `"12.5"` (mid-roll ad, for VoD and Live streaming)
659
+ - Percentage of the entire video duration: `"25%"`, `"50%"` (mid-roll ad, for VoD streaming only)
660
+ - Timecode `hh:mm:ss.mmm`: `"00:10:30.000"`, `"01:00:00.000"` (mid-roll ad, for VoD streaming only)
661
+
662
+ #### Dynamic ads scheduling
663
+
664
+ To gain more flexibility, it is also possible to schedule an `AdItem` dynamically in code using the
665
+ `Player` instance. To do this, you need to call the `scheduleAd` method.
666
+
667
+ ```typescript
668
+ // The object passed to `scheduleAd` must be an `AdItem`.
669
+ player.scheduleAd({
670
+ // Ad source with fallbacks.
671
+ sources: [
672
+ {
673
+ tag: '<AD-URL>',
674
+ type: AdSourceType.IMA,
675
+ },
676
+ ],
677
+ });
678
+ ```
679
+
680
+ An `AdScheduledEvent` event is dispatched when the ad is successfully scheduled via `scheduleAd`.
681
+
682
+ Also, during playback, it's also possible to check whether an ad is being played with `player.isAd()`
683
+ and skip the ad being currently played with `player.skipAd()` (see `AdSkippedEvent`).
684
+
685
+ #### Supported ads events
686
+
687
+ The supported `PlayerView` events for ads are:
688
+
689
+ - `onAdBreakFinished`
690
+ - `onAdBreakStarted`
691
+ - `onAdClicked`
692
+ - `onAdError`
693
+ - `onAdFinished`
694
+ - `onAdManifestLoad`
695
+ - `onAdManifestLoaded`
696
+ - `onAdQuartile`
697
+ - `onAdScheduled`
698
+ - `onAdSkipped`
699
+ - `onAdStarted`
700
+
701
+ You can check out a complete ads example in the [`example/`](https://github.com/bitmovin/bitmovin-player-react-native/tree/development/example) app.
702
+
489
703
  ## Contributing
490
704
 
491
705
  See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
@@ -19,5 +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.28.0"
22
+ s.dependency "BitmovinPlayer", "3.30.0"
23
+ s.ios.dependency "GoogleAds-IMA-iOS-SDK", "3.17.0"
24
+ s.tvos.dependency "GoogleAds-IMA-tvOS-SDK", "4.6.1"
23
25
  end
@@ -1,6 +1,6 @@
1
1
  buildscript {
2
2
  ext {
3
- kotlinVersion = '1.7.0'
3
+ kotlinVersion = '1.7.20'
4
4
  androidToolsVersion = '7.0.4'
5
5
  }
6
6
  repositories {
@@ -27,10 +27,10 @@ repositories {
27
27
  }
28
28
 
29
29
  android {
30
- compileSdk 31
30
+ compileSdk 33
31
31
  defaultConfig {
32
- minSdkVersion 21
33
- targetSdkVersion 31
32
+ minSdkVersion 16
33
+ targetSdkVersion 33
34
34
  versionCode 1
35
35
  versionName '1.0'
36
36
  }
@@ -50,6 +50,8 @@ android {
50
50
 
51
51
  dependencies {
52
52
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
53
- implementation 'com.bitmovin.player:player:3.24.2'
53
+ implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.26.0'
54
+ implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
55
+ implementation 'com.bitmovin.player:player:3.25.2'
54
56
  implementation 'com.facebook.react:react-native:+'
55
57
  }
@@ -17,7 +17,9 @@ import kotlin.concurrent.withLock
17
17
  */
18
18
  typealias PrepareCallback = (ByteArray) -> ByteArray
19
19
 
20
- @ReactModule(name = DrmModule.name)
20
+ private const val MODULE_NAME = "DrmModule"
21
+
22
+ @ReactModule(name = MODULE_NAME)
21
23
  class DrmModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
22
24
  /**
23
25
  * In-memory mapping from `nativeId`s to `WidevineConfig` instances.
@@ -52,10 +54,7 @@ class DrmModule(private val context: ReactApplicationContext) : ReactContextBase
52
54
  /**
53
55
  * JS exported module name.
54
56
  */
55
- companion object {
56
- const val name = "DrmModule"
57
- }
58
- override fun getName() = DrmModule.name
57
+ override fun getName() = MODULE_NAME
59
58
 
60
59
  /**
61
60
  * Fetches the `WidevineConfig` instance associated with `nativeId` from internal drmConfigs.
@@ -6,7 +6,9 @@ import com.facebook.react.bridge.*
6
6
  import com.facebook.react.module.annotations.ReactModule
7
7
  import com.facebook.react.uimanager.UIManagerModule
8
8
 
9
- @ReactModule(name = PlayerModule.name)
9
+ private const val MODULE_NAME = "PlayerModule"
10
+
11
+ @ReactModule(name = MODULE_NAME)
10
12
  class PlayerModule(private val context: ReactApplicationContext) : ReactContextBaseJavaModule(context) {
11
13
  /**
12
14
  * In-memory mapping from `nativeId`s to `Player` instances.
@@ -16,10 +18,7 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
16
18
  /**
17
19
  * JS exported module name.
18
20
  */
19
- companion object {
20
- const val name = "PlayerModule"
21
- }
22
- override fun getName() = PlayerModule.name
21
+ override fun getName() = MODULE_NAME
23
22
 
24
23
  /**
25
24
  * Fetches the `Player` instance associated with `nativeId` from the internal players.
@@ -280,6 +279,43 @@ class PlayerModule(private val context: ReactApplicationContext) : ReactContextB
280
279
  }
281
280
  }
282
281
 
282
+ /**
283
+ * Schedules an `AdItem` in the `nativeId`'s associated player.
284
+ * @param nativeId Target player id.
285
+ * @param adItemJson Json representation of the `AdItem` to be scheduled.
286
+ */
287
+ @ReactMethod
288
+ fun scheduleAd(nativeId: NativeId, adItemJson: ReadableMap?) {
289
+ JsonConverter.toAdItem(adItemJson)?.let { adItem ->
290
+ uiManager()?.addUIBlock {
291
+ players[nativeId]?.scheduleAd(adItem)
292
+ }
293
+ }
294
+ }
295
+
296
+ /**
297
+ * Skips the current ad in `nativeId`'s associated player.
298
+ * Has no effect if the current ad is not skippable or if no ad is being played back.
299
+ * @param nativeId Target player id.
300
+ */
301
+ @ReactMethod
302
+ fun skipAd(nativeId: NativeId) {
303
+ uiManager()?.addUIBlock {
304
+ players[nativeId]?.skipAd()
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Returns `true` while an ad is being played back or when main content playback has been paused for ad playback.
310
+ * @param nativeId Target player id.
311
+ */
312
+ @ReactMethod
313
+ fun isAd(nativeId: NativeId, promise: Promise) {
314
+ uiManager()?.addUIBlock {
315
+ promise.resolve(players[nativeId]?.isAd)
316
+ }
317
+ }
318
+
283
319
  /**
284
320
  * Helper function that returns the initialized `UIManager` instance.
285
321
  */