@bluebillywig/react-native-bb-player 8.45.8 → 8.45.10

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.
@@ -64,6 +64,10 @@ android {
64
64
  }
65
65
 
66
66
  repositories {
67
+ def localRepo = file("$projectDir/repo")
68
+ if (localRepo.exists()) {
69
+ maven { url localRepo.toURI() }
70
+ }
67
71
  mavenLocal()
68
72
  mavenCentral()
69
73
  google()
@@ -11,3 +11,4 @@
11
11
  #import <React/RCTBridge.h>
12
12
  #import <React/RCTEventEmitter.h>
13
13
  #import <React/RCTLog.h>
14
+ #import <React/RCTUtils.h>
@@ -303,7 +303,13 @@ class BBPlayerModule: RCTEventEmitter {
303
303
 
304
304
  @objc func presentModalPlayer(_ jsonUrl: String, optionsJson: String?, contextJson: String?) {
305
305
  DispatchQueue.main.async {
306
- guard let rootVC = RCTPresentedViewController() else {
306
+ // RCTPresentedViewController() can return nil with RCTReactNativeFactory (RN 0.83+).
307
+ // Fallback to UIScene-based lookup to find the root view controller.
308
+ guard let rootVC = RCTPresentedViewController()
309
+ ?? UIApplication.shared.connectedScenes
310
+ .compactMap({ ($0 as? UIWindowScene)?.windows.first(where: { $0.isKeyWindow })?.rootViewController })
311
+ .first
312
+ else {
307
313
  NSLog("BBPlayerModule: No root view controller found")
308
314
  return
309
315
  }
@@ -320,14 +326,11 @@ class BBPlayerModule: RCTEventEmitter {
320
326
  context = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
321
327
  }
322
328
 
323
- // Create modal player view
324
- let playerView = BBNativePlayerView(frame: rootVC.view.frame)
325
- playerView.showBackArrow = options?["showBackArrow"] as? Bool ?? false
326
-
327
329
  var loadOptions: [String: Any] = options ?? [:]
328
330
  if loadOptions["autoPlay"] == nil {
329
331
  loadOptions["autoPlay"] = true
330
332
  }
333
+ loadOptions["showBackArrow"] = options?["showBackArrow"] as? Bool ?? false
331
334
 
332
335
  // When context has a cliplist (contextCollectionId), load clip by ID
333
336
  // with cliplist context. ProgramController will swap to loading the
@@ -336,9 +339,8 @@ class BBPlayerModule: RCTEventEmitter {
336
339
  let collectionId = context?["contextCollectionId"] as? String
337
340
  let clipId = context?["contextEntityId"] as? String
338
341
 
339
- // Set up player with options (playout config, JWT, etc.)
340
- playerView.setupWithJsonUrl(jsonUrl: jsonUrl, options: loadOptions)
341
- playerView.presentModal(uiViewContoller: rootVC, animated: true)
342
+ // Create and present modal player using SDK factory method
343
+ let playerView = BBNativePlayer.createModalPlayerView(uiViewContoller: rootVC, jsonUrl: jsonUrl, options: loadOptions)
342
344
 
343
345
  if let collectionId = collectionId, let clipId = clipId {
344
346
  let clipContext: [String: Any] = [
@@ -526,7 +526,7 @@ class BBPlayerView: UIView, BBNativePlayerViewDelegate {
526
526
  return
527
527
  }
528
528
  isInFullscreen = true
529
- playerView?.presentModal(uiViewContoller: parentVC, animated: true)
529
+ playerView?.player.enterFullScreen()
530
530
  }
531
531
 
532
532
  func closeModal() {
@@ -586,7 +586,8 @@ class BBPlayerView: UIView, BBNativePlayerViewDelegate {
586
586
  }
587
587
 
588
588
  func seekRelative(_ offsetInSeconds: Double) {
589
- playerView?.player.seekRelative(offsetInSeconds: offsetInSeconds as NSNumber)
589
+ // seekRelative removed in newer BBNativePlayerKit; no-op
590
+ log("seekRelative not available in this SDK version", level: .warning)
590
591
  }
591
592
 
592
593
  func setMuted(_ muted: Bool) {
@@ -5,11 +5,38 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.BBModalPlayer = void 0;
7
7
  var _reactNative = require("react-native");
8
- const BBPlayerModule = _reactNative.NativeModules.BBPlayerModule;
9
- const eventEmitter = new _reactNative.NativeEventEmitter(BBPlayerModule);
8
+ // Resolve BBPlayerModule: TurboModuleRegistry (New Arch) with NativeModules fallback
9
+ let BBPlayerModule = null;
10
+ try {
11
+ BBPlayerModule = require('./specs/NativeBBPlayerModule').default;
12
+ } catch {
13
+ // TurboModule not available
14
+ }
15
+ if (!BBPlayerModule) {
16
+ BBPlayerModule = _reactNative.NativeModules.BBPlayerModule;
17
+ }
18
+ if (!BBPlayerModule) {
19
+ console.warn('[BBModalPlayer] Native BBPlayerModule not found. ' + 'TurboModuleRegistry and NativeModules both returned null. ' + `Platform: ${_reactNative.Platform.OS}`);
20
+ }
21
+
22
+ // NativeEventEmitter requires a non-null module on iOS to avoid warnings.
23
+ // Pass null-safe: events will simply never fire if module is missing.
24
+ const eventEmitter = BBPlayerModule ? new _reactNative.NativeEventEmitter(BBPlayerModule) : new _reactNative.NativeEventEmitter();
10
25
  const BBModalPlayer = exports.BBModalPlayer = {
26
+ /**
27
+ * Whether the native modal player module is available.
28
+ * When false, present() will be a no-op.
29
+ */
30
+ get isAvailable() {
31
+ return BBPlayerModule != null;
32
+ },
11
33
  present(jsonUrl, options, context) {
12
- BBPlayerModule?.presentModalPlayer(jsonUrl, options ? JSON.stringify(options) : null, context ? JSON.stringify(context) : null);
34
+ if (!BBPlayerModule) {
35
+ console.warn('[BBModalPlayer] present() called but native module is null — cannot open modal');
36
+ return false;
37
+ }
38
+ BBPlayerModule.presentModalPlayer(jsonUrl, options ? JSON.stringify(options) : null, context ? JSON.stringify(context) : null);
39
+ return true;
13
40
  },
14
41
  dismiss() {
15
42
  BBPlayerModule?.dismissModalPlayer();
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","BBPlayerModule","NativeModules","eventEmitter","NativeEventEmitter","BBModalPlayer","exports","present","jsonUrl","options","context","presentModalPlayer","JSON","stringify","dismiss","dismissModalPlayer","addEventListener","event","callback","addListener"],"sourceRoot":"../../src","sources":["BBModalPlayer.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,cAAc,GAAGC,0BAAa,CAACD,cAAc;AACnD,MAAME,YAAY,GAAG,IAAIC,+BAAkB,CAACH,cAAc,CAAC;AAUpD,MAAMI,aAAa,GAAAC,OAAA,CAAAD,aAAA,GAAG;EAC3BE,OAAOA,CAACC,OAAe,EAAEC,OAA4B,EAAEC,OAAgC,EAAE;IACvFT,cAAc,EAAEU,kBAAkB,CAChCH,OAAO,EACPC,OAAO,GAAGG,IAAI,CAACC,SAAS,CAACJ,OAAO,CAAC,GAAG,IAAI,EACxCC,OAAO,GAAGE,IAAI,CAACC,SAAS,CAACH,OAAO,CAAC,GAAG,IACtC,CAAC;EACH,CAAC;EAEDI,OAAOA,CAAA,EAAG;IACRb,cAAc,EAAEc,kBAAkB,CAAC,CAAC;EACtC,CAAC;EAEDC,gBAAgBA,CACdC,KAAa,EACbC,QAAkC,EAClC;IACA,OAAOf,YAAY,CAACgB,WAAW,CAACF,KAAK,EAAEC,QAAQ,CAAC;EAClD;AACF,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","BBPlayerModule","default","NativeModules","console","warn","Platform","OS","eventEmitter","NativeEventEmitter","BBModalPlayer","exports","isAvailable","present","jsonUrl","options","context","presentModalPlayer","JSON","stringify","dismiss","dismissModalPlayer","addEventListener","event","callback","addListener"],"sourceRoot":"../../src","sources":["BBModalPlayer.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA;AACA,IAAIC,cAAmB,GAAG,IAAI;AAC9B,IAAI;EACFA,cAAc,GAAGD,OAAO,CAAC,8BAA8B,CAAC,CAACE,OAAO;AAClE,CAAC,CAAC,MAAM;EACN;AAAA;AAEF,IAAI,CAACD,cAAc,EAAE;EACnBA,cAAc,GAAGE,0BAAa,CAACF,cAAc;AAC/C;AAEA,IAAI,CAACA,cAAc,EAAE;EACnBG,OAAO,CAACC,IAAI,CACV,mDAAmD,GACnD,4DAA4D,GAC5D,aAAaC,qBAAQ,CAACC,EAAE,EAC1B,CAAC;AACH;;AAEA;AACA;AACA,MAAMC,YAAY,GAAGP,cAAc,GAC/B,IAAIQ,+BAAkB,CAACR,cAAc,CAAC,GACtC,IAAIQ,+BAAkB,CAAC,CAAC;AAUrB,MAAMC,aAAa,GAAAC,OAAA,CAAAD,aAAA,GAAG;EAC3B;AACF;AACA;AACA;EACE,IAAIE,WAAWA,CAAA,EAAY;IACzB,OAAOX,cAAc,IAAI,IAAI;EAC/B,CAAC;EAEDY,OAAOA,CAACC,OAAe,EAAEC,OAA4B,EAAEC,OAAgC,EAAW;IAChG,IAAI,CAACf,cAAc,EAAE;MACnBG,OAAO,CAACC,IAAI,CAAC,gFAAgF,CAAC;MAC9F,OAAO,KAAK;IACd;IACAJ,cAAc,CAACgB,kBAAkB,CAC/BH,OAAO,EACPC,OAAO,GAAGG,IAAI,CAACC,SAAS,CAACJ,OAAO,CAAC,GAAG,IAAI,EACxCC,OAAO,GAAGE,IAAI,CAACC,SAAS,CAACH,OAAO,CAAC,GAAG,IACtC,CAAC;IACD,OAAO,IAAI;EACb,CAAC;EAEDI,OAAOA,CAAA,EAAG;IACRnB,cAAc,EAAEoB,kBAAkB,CAAC,CAAC;EACtC,CAAC;EAEDC,gBAAgBA,CACdC,KAAa,EACbC,QAAkC,EAClC;IACA,OAAOhB,YAAY,CAACiB,WAAW,CAACF,KAAK,EAAEC,QAAQ,CAAC;EAClD;AACF,CAAC","ignoreList":[]}
@@ -1,11 +1,39 @@
1
1
  "use strict";
2
2
 
3
- import { NativeEventEmitter, NativeModules } from 'react-native';
4
- const BBPlayerModule = NativeModules.BBPlayerModule;
5
- const eventEmitter = new NativeEventEmitter(BBPlayerModule);
3
+ import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
4
+
5
+ // Resolve BBPlayerModule: TurboModuleRegistry (New Arch) with NativeModules fallback
6
+ let BBPlayerModule = null;
7
+ try {
8
+ BBPlayerModule = require('./specs/NativeBBPlayerModule').default;
9
+ } catch {
10
+ // TurboModule not available
11
+ }
12
+ if (!BBPlayerModule) {
13
+ BBPlayerModule = NativeModules.BBPlayerModule;
14
+ }
15
+ if (!BBPlayerModule) {
16
+ console.warn('[BBModalPlayer] Native BBPlayerModule not found. ' + 'TurboModuleRegistry and NativeModules both returned null. ' + `Platform: ${Platform.OS}`);
17
+ }
18
+
19
+ // NativeEventEmitter requires a non-null module on iOS to avoid warnings.
20
+ // Pass null-safe: events will simply never fire if module is missing.
21
+ const eventEmitter = BBPlayerModule ? new NativeEventEmitter(BBPlayerModule) : new NativeEventEmitter();
6
22
  export const BBModalPlayer = {
23
+ /**
24
+ * Whether the native modal player module is available.
25
+ * When false, present() will be a no-op.
26
+ */
27
+ get isAvailable() {
28
+ return BBPlayerModule != null;
29
+ },
7
30
  present(jsonUrl, options, context) {
8
- BBPlayerModule?.presentModalPlayer(jsonUrl, options ? JSON.stringify(options) : null, context ? JSON.stringify(context) : null);
31
+ if (!BBPlayerModule) {
32
+ console.warn('[BBModalPlayer] present() called but native module is null — cannot open modal');
33
+ return false;
34
+ }
35
+ BBPlayerModule.presentModalPlayer(jsonUrl, options ? JSON.stringify(options) : null, context ? JSON.stringify(context) : null);
36
+ return true;
9
37
  },
10
38
  dismiss() {
11
39
  BBPlayerModule?.dismissModalPlayer();
@@ -1 +1 @@
1
- {"version":3,"names":["NativeEventEmitter","NativeModules","BBPlayerModule","eventEmitter","BBModalPlayer","present","jsonUrl","options","context","presentModalPlayer","JSON","stringify","dismiss","dismissModalPlayer","addEventListener","event","callback","addListener"],"sourceRoot":"../../src","sources":["BBModalPlayer.ts"],"mappings":";;AAAA,SAASA,kBAAkB,EAAEC,aAAa,QAAQ,cAAc;AAEhE,MAAMC,cAAc,GAAGD,aAAa,CAACC,cAAc;AACnD,MAAMC,YAAY,GAAG,IAAIH,kBAAkB,CAACE,cAAc,CAAC;AAU3D,OAAO,MAAME,aAAa,GAAG;EAC3BC,OAAOA,CAACC,OAAe,EAAEC,OAA4B,EAAEC,OAAgC,EAAE;IACvFN,cAAc,EAAEO,kBAAkB,CAChCH,OAAO,EACPC,OAAO,GAAGG,IAAI,CAACC,SAAS,CAACJ,OAAO,CAAC,GAAG,IAAI,EACxCC,OAAO,GAAGE,IAAI,CAACC,SAAS,CAACH,OAAO,CAAC,GAAG,IACtC,CAAC;EACH,CAAC;EAEDI,OAAOA,CAAA,EAAG;IACRV,cAAc,EAAEW,kBAAkB,CAAC,CAAC;EACtC,CAAC;EAEDC,gBAAgBA,CACdC,KAAa,EACbC,QAAkC,EAClC;IACA,OAAOb,YAAY,CAACc,WAAW,CAACF,KAAK,EAAEC,QAAQ,CAAC;EAClD;AACF,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["NativeEventEmitter","NativeModules","Platform","BBPlayerModule","require","default","console","warn","OS","eventEmitter","BBModalPlayer","isAvailable","present","jsonUrl","options","context","presentModalPlayer","JSON","stringify","dismiss","dismissModalPlayer","addEventListener","event","callback","addListener"],"sourceRoot":"../../src","sources":["BBModalPlayer.ts"],"mappings":";;AAAA,SAASA,kBAAkB,EAAEC,aAAa,EAAEC,QAAQ,QAAQ,cAAc;;AAE1E;AACA,IAAIC,cAAmB,GAAG,IAAI;AAC9B,IAAI;EACFA,cAAc,GAAGC,OAAO,CAAC,8BAA8B,CAAC,CAACC,OAAO;AAClE,CAAC,CAAC,MAAM;EACN;AAAA;AAEF,IAAI,CAACF,cAAc,EAAE;EACnBA,cAAc,GAAGF,aAAa,CAACE,cAAc;AAC/C;AAEA,IAAI,CAACA,cAAc,EAAE;EACnBG,OAAO,CAACC,IAAI,CACV,mDAAmD,GACnD,4DAA4D,GAC5D,aAAaL,QAAQ,CAACM,EAAE,EAC1B,CAAC;AACH;;AAEA;AACA;AACA,MAAMC,YAAY,GAAGN,cAAc,GAC/B,IAAIH,kBAAkB,CAACG,cAAc,CAAC,GACtC,IAAIH,kBAAkB,CAAC,CAAC;AAU5B,OAAO,MAAMU,aAAa,GAAG;EAC3B;AACF;AACA;AACA;EACE,IAAIC,WAAWA,CAAA,EAAY;IACzB,OAAOR,cAAc,IAAI,IAAI;EAC/B,CAAC;EAEDS,OAAOA,CAACC,OAAe,EAAEC,OAA4B,EAAEC,OAAgC,EAAW;IAChG,IAAI,CAACZ,cAAc,EAAE;MACnBG,OAAO,CAACC,IAAI,CAAC,gFAAgF,CAAC;MAC9F,OAAO,KAAK;IACd;IACAJ,cAAc,CAACa,kBAAkB,CAC/BH,OAAO,EACPC,OAAO,GAAGG,IAAI,CAACC,SAAS,CAACJ,OAAO,CAAC,GAAG,IAAI,EACxCC,OAAO,GAAGE,IAAI,CAACC,SAAS,CAACH,OAAO,CAAC,GAAG,IACtC,CAAC;IACD,OAAO,IAAI;EACb,CAAC;EAEDI,OAAOA,CAAA,EAAG;IACRhB,cAAc,EAAEiB,kBAAkB,CAAC,CAAC;EACtC,CAAC;EAEDC,gBAAgBA,CACdC,KAAa,EACbC,QAAkC,EAClC;IACA,OAAOd,YAAY,CAACe,WAAW,CAACF,KAAK,EAAEC,QAAQ,CAAC;EAClD;AACF,CAAC","ignoreList":[]}
@@ -6,7 +6,12 @@ export interface ModalPlayerOptions {
6
6
  [key: string]: unknown;
7
7
  }
8
8
  export declare const BBModalPlayer: {
9
- present(jsonUrl: string, options?: ModalPlayerOptions, context?: Record<string, string>): void;
9
+ /**
10
+ * Whether the native modal player module is available.
11
+ * When false, present() will be a no-op.
12
+ */
13
+ readonly isAvailable: boolean;
14
+ present(jsonUrl: string, options?: ModalPlayerOptions, context?: Record<string, string>): boolean;
10
15
  dismiss(): void;
11
16
  addEventListener(event: string, callback: (...args: any[]) => void): import("react-native").EmitterSubscription;
12
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"BBModalPlayer.d.ts","sourceRoot":"","sources":["../../../src/BBModalPlayer.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,aAAa;qBACP,MAAM,YAAY,kBAAkB,YAAY,OAAO,MAAM,EAAE,MAAM,CAAC;;4BAa9E,MAAM,sBACO,GAAG,EAAE,KAAK,IAAI;CAIrC,CAAC"}
1
+ {"version":3,"file":"BBModalPlayer.d.ts","sourceRoot":"","sources":["../../../src/BBModalPlayer.ts"],"names":[],"mappings":"AA2BA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,aAAa;IACxB;;;OAGG;;qBAKc,MAAM,YAAY,kBAAkB,YAAY,OAAO,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO;;4BAkBxF,MAAM,sBACO,GAAG,EAAE,KAAK,IAAI;CAIrC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluebillywig/react-native-bb-player",
3
- "version": "8.45.8",
3
+ "version": "8.45.10",
4
4
  "description": "Blue Billywig Native Video Player for React Native - iOS AVPlayer and Android ExoPlayer integration",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -32,6 +32,7 @@
32
32
  "ios",
33
33
  "android/src",
34
34
  "android/build.gradle",
35
+ "android/repo",
35
36
  "plugin/build",
36
37
  "app.plugin.js",
37
38
  "README.md",
@@ -23,12 +23,19 @@ Pod::Spec.new do |s|
23
23
  s.static_framework = true
24
24
 
25
25
  s.dependency 'React-Core'
26
- s.dependency 'BlueBillywigNativePlayerKit-iOS'
27
- s.dependency 'BlueBillywigNativePlayerKit-iOS/GoogleCastSDK'
28
26
 
29
- # Note: TurboModule/New Architecture dependencies (React-Codegen, RCT-Folly, etc.)
30
- # are automatically provided by React Native when New Architecture is enabled.
31
- # No need to specify them here as they would create duplicate/conflicting deps.
27
+ # Prefer vendored frameworks (from npm package) over CocoaPods remote
28
+ frameworks_dir = File.join(__dir__, 'ios', 'Frameworks')
29
+ if File.exist?(File.join(frameworks_dir, 'BBNativePlayerKit.xcframework'))
30
+ s.vendored_frameworks = 'ios/Frameworks/BBNativePlayerKit.xcframework',
31
+ 'ios/Frameworks/bbnativeshared.xcframework'
32
+ s.dependency 'GoogleAds-IMA-iOS-SDK', '3.23.0'
33
+ s.dependency 'GoogleUserMessagingPlatform', '~> 2.1'
34
+ s.dependency 'google-cast-sdk-dynamic-xcframework-ios-bb', '4.8.0'
35
+ else
36
+ s.dependency 'BlueBillywigNativePlayerKit-iOS'
37
+ s.dependency 'BlueBillywigNativePlayerKit-iOS/GoogleCastSDK'
38
+ end
32
39
 
33
40
  # Swift/Objective-C compatibility
34
41
  s.pod_target_xcconfig = {
@@ -36,5 +43,5 @@ Pod::Spec.new do |s|
36
43
  'SWIFT_COMPILATION_MODE' => 'wholemodule'
37
44
  }
38
45
 
39
- s.source_files = "ios/**/*.{h,m,mm,swift,hpp,cpp}"
46
+ s.source_files = "ios/*.{h,m,mm,swift,hpp,cpp}"
40
47
  end
@@ -1,7 +1,29 @@
1
- import { NativeEventEmitter, NativeModules } from 'react-native';
1
+ import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
2
2
 
3
- const BBPlayerModule = NativeModules.BBPlayerModule;
4
- const eventEmitter = new NativeEventEmitter(BBPlayerModule);
3
+ // Resolve BBPlayerModule: TurboModuleRegistry (New Arch) with NativeModules fallback
4
+ let BBPlayerModule: any = null;
5
+ try {
6
+ BBPlayerModule = require('./specs/NativeBBPlayerModule').default;
7
+ } catch {
8
+ // TurboModule not available
9
+ }
10
+ if (!BBPlayerModule) {
11
+ BBPlayerModule = NativeModules.BBPlayerModule;
12
+ }
13
+
14
+ if (!BBPlayerModule) {
15
+ console.warn(
16
+ '[BBModalPlayer] Native BBPlayerModule not found. ' +
17
+ 'TurboModuleRegistry and NativeModules both returned null. ' +
18
+ `Platform: ${Platform.OS}`,
19
+ );
20
+ }
21
+
22
+ // NativeEventEmitter requires a non-null module on iOS to avoid warnings.
23
+ // Pass null-safe: events will simply never fire if module is missing.
24
+ const eventEmitter = BBPlayerModule
25
+ ? new NativeEventEmitter(BBPlayerModule)
26
+ : new NativeEventEmitter();
5
27
 
6
28
  export interface ModalPlayerOptions {
7
29
  autoPlay?: boolean;
@@ -12,12 +34,25 @@ export interface ModalPlayerOptions {
12
34
  }
13
35
 
14
36
  export const BBModalPlayer = {
15
- present(jsonUrl: string, options?: ModalPlayerOptions, context?: Record<string, string>) {
16
- BBPlayerModule?.presentModalPlayer(
37
+ /**
38
+ * Whether the native modal player module is available.
39
+ * When false, present() will be a no-op.
40
+ */
41
+ get isAvailable(): boolean {
42
+ return BBPlayerModule != null;
43
+ },
44
+
45
+ present(jsonUrl: string, options?: ModalPlayerOptions, context?: Record<string, string>): boolean {
46
+ if (!BBPlayerModule) {
47
+ console.warn('[BBModalPlayer] present() called but native module is null — cannot open modal');
48
+ return false;
49
+ }
50
+ BBPlayerModule.presentModalPlayer(
17
51
  jsonUrl,
18
52
  options ? JSON.stringify(options) : null,
19
53
  context ? JSON.stringify(context) : null,
20
54
  );
55
+ return true;
21
56
  },
22
57
 
23
58
  dismiss() {