bitmovin-player-react-native 1.18.0 → 1.20.1

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 (34) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/com/bitmovin/player/reactnative/PlayerModule.kt +34 -1
  4. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerView.kt +43 -6
  5. package/android/src/main/java/com/bitmovin/player/reactnative/RNPlayerViewManager.kt +2 -0
  6. package/android/src/main/java/com/bitmovin/player/reactnative/ui/RNPictureInPictureHandler.kt +81 -1
  7. package/build/advertising.d.ts +20 -0
  8. package/build/advertising.d.ts.map +1 -1
  9. package/build/advertising.js.map +1 -1
  10. package/build/components/PlayerView/events.d.ts +0 -4
  11. package/build/components/PlayerView/events.d.ts.map +1 -1
  12. package/build/components/PlayerView/events.js.map +1 -1
  13. package/build/components/PlayerView/nativeEvents.d.ts +0 -4
  14. package/build/components/PlayerView/nativeEvents.d.ts.map +1 -1
  15. package/build/components/PlayerView/nativeEvents.js.map +1 -1
  16. package/build/events.d.ts +2 -2
  17. package/build/events.js.map +1 -1
  18. package/build/modules/PlayerModule.d.ts +10 -1
  19. package/build/modules/PlayerModule.d.ts.map +1 -1
  20. package/build/modules/PlayerModule.js.map +1 -1
  21. package/build/player.d.ts +2 -0
  22. package/build/player.d.ts.map +1 -1
  23. package/build/player.js +38 -0
  24. package/build/player.js.map +1 -1
  25. package/ios/RNBitmovinPlayer.podspec +1 -1
  26. package/package.json +2 -2
  27. package/plugin/build/withBitmovinIosConfig.js +3 -2
  28. package/plugin/src/withBitmovinIosConfig.ts +4 -2
  29. package/src/advertising.ts +20 -0
  30. package/src/components/PlayerView/events.ts +0 -4
  31. package/src/components/PlayerView/nativeEvents.ts +0 -4
  32. package/src/events.ts +2 -2
  33. package/src/modules/PlayerModule.ts +15 -1
  34. package/src/player.ts +42 -1
@@ -61,10 +61,12 @@ const withBitmovinIosConfig: ConfigPlugin<BitmovinConfigOptions> = (
61
61
  delete config.modResults['BitmovinPlayerOfflineSupportEnabled'];
62
62
  }
63
63
  if (googleCastConfig?.ios != null) {
64
+ const defaultLocalNetworkUsageDescription =
65
+ '${PRODUCT_NAME} uses the local network to discover Cast-enabled devices on your WiFi network.';
64
66
  const localNetworkUsageDescription =
65
- typeof googleCastConfig?.ios === 'object'
67
+ (typeof googleCastConfig?.ios === 'object'
66
68
  ? googleCastConfig?.ios?.localNetworkUsageDescription
67
- : '${PRODUCT_NAME} uses the local network to discover Cast-enabled devices on your WiFi network.';
69
+ : undefined) ?? defaultLocalNetworkUsageDescription;
68
70
 
69
71
  config.modResults['BitmovinPlayerGoogleCastApplicationId'] =
70
72
  googleCastAppId;
@@ -113,6 +113,26 @@ export interface AdvertisingConfig {
113
113
  * - `false` → the ad item will be skipped and removed from the playback schedule.
114
114
  */
115
115
  shouldLoadAdItem?: (adItem: AdItem) => boolean;
116
+ /**
117
+ * Called right before a scheduled ad break starts playback.
118
+ *
119
+ * Use this callback to conditionally allow or skip ad breaks at runtime
120
+ * (e.g., when starting playback from a time offset and discarding past breaks).
121
+ *
122
+ * @param adBreak - The ad break that is about to start.
123
+ *
124
+ * @returns
125
+ * - `true` → the ad break will start playback.
126
+ * - `false` → the ad break will be skipped.
127
+ *
128
+ * @remarks
129
+ * If the callback does not return within the platform's internal timeout,
130
+ * the ad break will play.
131
+ * The callback must be synchronous.
132
+ *
133
+ * @platform Android
134
+ */
135
+ shouldPlayAdBreak?: (adBreak: AdBreak) => boolean;
116
136
  /**
117
137
  * Configuration to customize Google IMA SDK integration.
118
138
  */
@@ -247,8 +247,6 @@ export type PlayerViewEvents = {
247
247
  onPictureInPictureEnter?: (event: PictureInPictureEnterEvent) => void;
248
248
  /**
249
249
  * Event emitted when the player entered Picture in Picture mode.
250
- *
251
- * @platform iOS
252
250
  */
253
251
  onPictureInPictureEntered?: (event: PictureInPictureEnteredEvent) => void;
254
252
  /**
@@ -257,8 +255,6 @@ export type PlayerViewEvents = {
257
255
  onPictureInPictureExit?: (event: PictureInPictureExitEvent) => void;
258
256
  /**
259
257
  * Event emitted when the player exited Picture in Picture mode.
260
- *
261
- * @platform iOS
262
258
  */
263
259
  onPictureInPictureExited?: (event: PictureInPictureExitedEvent) => void;
264
260
  /**
@@ -262,8 +262,6 @@ export type NativePlayerViewEvents = {
262
262
  }) => void;
263
263
  /**
264
264
  * Event emitted when the player entered Picture in Picture mode.
265
- *
266
- * @platform iOS
267
265
  */
268
266
  onBmpPictureInPictureEntered?: (event: {
269
267
  nativeEvent: PictureInPictureEnteredEvent;
@@ -276,8 +274,6 @@ export type NativePlayerViewEvents = {
276
274
  }) => void;
277
275
  /**
278
276
  * Event emitted when the player exited Picture in Picture mode.
279
- *
280
- * @platform iOS
281
277
  */
282
278
  onBmpPictureInPictureExited?: (event: {
283
279
  nativeEvent: PictureInPictureExitedEvent;
package/src/events.ts CHANGED
@@ -383,14 +383,14 @@ export type PictureInPictureExitEvent = Event;
383
383
  /**
384
384
  * Emitted when the player has finished entering Picture in Picture mode on iOS.
385
385
  *
386
- * @platform iOS
386
+ * @platform iOS, Android
387
387
  */
388
388
  export type PictureInPictureEnteredEvent = Event;
389
389
 
390
390
  /**
391
391
  * Emitted when the player has finished exiting Picture in Picture mode on iOS.
392
392
  *
393
- * @platform iOS
393
+ * @platform iOS, Android
394
394
  */
395
395
  export type PictureInPictureExitedEvent = Event;
396
396
 
@@ -1,5 +1,5 @@
1
1
  import { NativeModule, requireNativeModule } from 'expo-modules-core';
2
- import { AdItem, ImaSettings } from '../advertising';
2
+ import { AdBreak, AdItem, ImaSettings } from '../advertising';
3
3
 
4
4
  export type PlayerModuleEvents = {
5
5
  onShouldLoadAdItem: ({
@@ -11,6 +11,15 @@ export type PlayerModuleEvents = {
11
11
  id: number;
12
12
  adItem: AdItem;
13
13
  }) => void;
14
+ onShouldPlayAdBreak: ({
15
+ nativeId,
16
+ id,
17
+ adBreak,
18
+ }: {
19
+ nativeId: string;
20
+ id: number;
21
+ adBreak: AdBreak;
22
+ }) => void;
14
23
  onImaBeforeInitialization: ({
15
24
  nativeId,
16
25
  id,
@@ -173,6 +182,11 @@ declare class PlayerModule extends NativeModule<PlayerModuleEvents> {
173
182
  */
174
183
  setShouldLoadAdItem(id: number, shouldLoad: boolean): Promise<void>;
175
184
 
185
+ /**
186
+ * Applies the JS decision for an ad break playback callback.
187
+ */
188
+ setShouldPlayAdBreak(id: number, shouldPlay: boolean): Promise<void>;
189
+
176
190
  /**
177
191
  * Applies the JS-updated IMA settings for a before-initialization callback.
178
192
  */
package/src/player.ts CHANGED
@@ -9,7 +9,7 @@ import { OfflineContentManager, OfflineSourceOptions } from './offline';
9
9
  import { Thumbnail } from './thumbnail';
10
10
  import { AnalyticsApi } from './analytics/player';
11
11
  import { PlayerConfig } from './playerConfig';
12
- import { AdItem, ImaSettings } from './advertising';
12
+ import { AdBreak, AdItem, ImaSettings } from './advertising';
13
13
  import { BufferApi } from './bufferApi';
14
14
  import { VideoQuality } from './media';
15
15
  import { Network } from './network';
@@ -52,6 +52,7 @@ export class Player extends NativeInstance<PlayerConfig> {
52
52
 
53
53
  private decoderConfig?: DecoderConfigBridge;
54
54
  private onShouldLoadAdItemSubscription?: EventSubscription;
55
+ private onShouldPlayAdBreakSubscription?: EventSubscription;
55
56
  private onImaBeforeInitializationSubscription?: EventSubscription;
56
57
  /**
57
58
  * Allocates the native `Player` instance and its resources natively.
@@ -59,6 +60,7 @@ export class Player extends NativeInstance<PlayerConfig> {
59
60
  initialize = async (): Promise<void> => {
60
61
  if (!this.isInitialized) {
61
62
  this.ensureShouldLoadAdItemListener();
63
+ this.ensureShouldPlayAdBreakListener();
62
64
  this.ensureImaBeforeInitializationListener();
63
65
  if (this.config?.networkConfig) {
64
66
  this.network = new Network(this.config.networkConfig);
@@ -99,8 +101,10 @@ export class Player extends NativeInstance<PlayerConfig> {
99
101
  void this.network?.destroy();
100
102
  void this.decoderConfig?.destroy();
101
103
  this.onShouldLoadAdItemSubscription?.remove();
104
+ this.onShouldPlayAdBreakSubscription?.remove();
102
105
  this.onImaBeforeInitializationSubscription?.remove();
103
106
  this.onShouldLoadAdItemSubscription = undefined;
107
+ this.onShouldPlayAdBreakSubscription = undefined;
104
108
  this.onImaBeforeInitializationSubscription = undefined;
105
109
  this.isDestroyed = true;
106
110
  }
@@ -238,6 +242,43 @@ export class Player extends NativeInstance<PlayerConfig> {
238
242
  void PlayerModule.setVolume(this.nativeId, volume);
239
243
  };
240
244
 
245
+ private ensureShouldPlayAdBreakListener = () => {
246
+ if (Platform.OS !== 'android') {
247
+ return;
248
+ }
249
+ const callback = this.config?.advertisingConfig?.shouldPlayAdBreak;
250
+ if (!callback) {
251
+ return;
252
+ }
253
+ if (this.onShouldPlayAdBreakSubscription) {
254
+ return;
255
+ }
256
+ this.onShouldPlayAdBreakSubscription = PlayerModule.addListener(
257
+ 'onShouldPlayAdBreak',
258
+ ({ nativeId, id, adBreak }) => {
259
+ if (nativeId !== this.nativeId) {
260
+ return;
261
+ }
262
+ const cloned: AdBreak = {
263
+ ...adBreak,
264
+ ads: adBreak.ads.map((ad) => ({
265
+ ...ad,
266
+ data: ad.data ? { ...ad.data } : undefined,
267
+ })),
268
+ };
269
+ let shouldPlay = true;
270
+ try {
271
+ const shouldPlayResult = callback(cloned);
272
+ shouldPlay =
273
+ typeof shouldPlayResult === 'boolean' ? shouldPlayResult : true;
274
+ } catch {
275
+ shouldPlay = true;
276
+ }
277
+ void PlayerModule.setShouldPlayAdBreak(id, shouldPlay);
278
+ }
279
+ );
280
+ };
281
+
241
282
  private ensureImaBeforeInitializationListener = () => {
242
283
  const callback = this.config?.advertisingConfig?.ima?.beforeInitialization;
243
284
  if (!callback) {