@bluebillywig/react-native-bb-player 8.42.10 → 8.42.15

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/CHANGELOG.md CHANGED
@@ -5,6 +5,27 @@ All notable changes to react-native-bb-player will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [8.42.10] - 2026-01-28
9
+
10
+ ### Added
11
+ - **TurboModule support** for React Native New Architecture (Fabric)
12
+ - Added `NativeBBPlayerModule` TurboModule spec for React Native codegen
13
+ - Native module now uses `TurboModuleRegistry` when available, with automatic fallback to legacy `NativeModules`
14
+ - Added architecture-specific source sets (`newarch`/`paper`) for Android
15
+ - iOS module converted to Objective-C++ (`.mm`) for C++ interop required by TurboModules
16
+
17
+ ### Changed
18
+ - `BBPlayerPackage.kt` now implements `TurboReactPackage` for New Architecture compatibility
19
+ - `BBPlayerModule.kt` extends generated `NativeBBPlayerModuleSpec` for type-safe TurboModule implementation
20
+ - Updated `react-native-bb-player.podspec` with New Architecture compiler flags and configuration
21
+ - Added `codegenConfig` to `package.json` for React Native codegen integration
22
+
23
+ ### Technical Details
24
+ - Supports both Old Architecture (Paper) and New Architecture (Fabric/TurboModules)
25
+ - Tested with React Native 0.82.1
26
+ - No breaking changes - existing apps continue to work without modification
27
+ - New Architecture is automatically detected and used when enabled in the app
28
+
8
29
  ## [2.0.0] - 2026-01-20
9
30
 
10
31
  ### Changed
@@ -44,5 +65,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
44
65
  - Android fullscreen landscape: proper orientation locking and state restoration
45
66
  - Performance optimizations: reduced bridge traffic and memory leak fixes
46
67
 
68
+ [8.42.10]: https://github.com/bluebillywig/react-native-bb-player/releases/tag/v8.42.10
47
69
  [2.0.0]: https://github.com/bluebillywig/react-native-bb-player/releases/tag/v2.0.0
48
70
  [1.0.0]: https://github.com/bluebillywig/react-native-bb-player/releases/tag/v1.0.0
package/README.md CHANGED
@@ -18,7 +18,7 @@ Native video player for React Native - powered by Blue Billywig's iOS and Androi
18
18
  |----------|-------------|---------------|
19
19
  | **iOS** | 12.0+ | AVPlayer |
20
20
  | **Android** | API 21+ (5.0+) | ExoPlayer |
21
- | **React Native** | 0.73+ | Old & New Architecture |
21
+ | **React Native** | 0.73+ | Old & New Architecture (TurboModules) |
22
22
  | **Expo** | SDK 51+ | With config plugin (optional) |
23
23
 
24
24
  ## Installation
@@ -673,6 +673,63 @@ function CustomScreen() {
673
673
  }
674
674
  ```
675
675
 
676
+ ## New Architecture (Fabric & TurboModules)
677
+
678
+ This package fully supports React Native's New Architecture, including:
679
+
680
+ - **Fabric** - The new rendering system
681
+ - **TurboModules** - The new native module system with synchronous access and lazy loading
682
+
683
+ ### Automatic Detection
684
+
685
+ The package automatically detects which architecture your app uses:
686
+ - **New Architecture enabled**: Uses `TurboModuleRegistry` for optimal performance
687
+ - **Old Architecture**: Falls back to `NativeModules` (no changes needed)
688
+
689
+ ### Enabling New Architecture
690
+
691
+ #### React Native 0.76+
692
+ New Architecture is enabled by default in React Native 0.76 and later.
693
+
694
+ #### React Native 0.73-0.75
695
+ Enable in your app's configuration:
696
+
697
+ **Android** (`android/gradle.properties`):
698
+ ```properties
699
+ newArchEnabled=true
700
+ ```
701
+
702
+ **iOS** (`ios/Podfile`):
703
+ ```ruby
704
+ ENV['RCT_NEW_ARCH_ENABLED'] = '1'
705
+ ```
706
+
707
+ Then rebuild your app:
708
+ ```bash
709
+ # iOS
710
+ cd ios && pod install && cd ..
711
+ npx react-native run-ios
712
+
713
+ # Android
714
+ cd android && ./gradlew clean && cd ..
715
+ npx react-native run-android
716
+ ```
717
+
718
+ ### No Code Changes Required
719
+
720
+ Your existing code works with both architectures. The package handles the architecture detection internally:
721
+
722
+ ```tsx
723
+ // This works on both Old and New Architecture
724
+ import { BBPlayerView } from '@bluebillywig/react-native-bb-player';
725
+
726
+ <BBPlayerView
727
+ ref={playerRef}
728
+ jsonUrl="https://demo.bbvms.com/p/default/c/4701337.json"
729
+ onDidTriggerPlay={() => console.log('Playing')}
730
+ />
731
+ ```
732
+
676
733
  ## FAQ
677
734
 
678
735
  ### Can I use this in production?
@@ -11,6 +11,11 @@ def isNewArchitectureEnabled() {
11
11
  return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
12
12
  }
13
13
 
14
+ // Apply React Native plugin for codegen when new arch is enabled
15
+ if (isNewArchitectureEnabled()) {
16
+ apply plugin: "com.facebook.react"
17
+ }
18
+
14
19
  group = 'com.bluebillywig.bbplayer'
15
20
  version = '2.0.0'
16
21
 
@@ -49,7 +54,8 @@ android {
49
54
  main {
50
55
  java.srcDirs = ['src/main/java']
51
56
  if (isNewArchitectureEnabled()) {
52
- java.srcDirs += ['src/newarch/java']
57
+ // Include codegen-generated specs first (takes precedence)
58
+ java.srcDirs += ["build/generated/source/codegen/java"]
53
59
  } else {
54
60
  java.srcDirs += ['src/paper/java']
55
61
  }
@@ -61,85 +61,85 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
61
61
  }
62
62
 
63
63
  @ReactMethod
64
- override fun play(viewTag: Int) {
65
- runOnUiThread(viewTag) { it.play() }
64
+ override fun play(viewTag: Double) {
65
+ runOnUiThread(viewTag.toInt()) { it.play() }
66
66
  }
67
67
 
68
68
  @ReactMethod
69
- override fun pause(viewTag: Int) {
70
- runOnUiThread(viewTag) { it.pause() }
69
+ override fun pause(viewTag: Double) {
70
+ runOnUiThread(viewTag.toInt()) { it.pause() }
71
71
  }
72
72
 
73
73
  @ReactMethod
74
- override fun seek(viewTag: Int, position: Double) {
75
- runOnUiThread(viewTag) { it.seek(position) }
74
+ override fun seek(viewTag: Double, position: Double) {
75
+ runOnUiThread(viewTag.toInt()) { it.seek(position) }
76
76
  }
77
77
 
78
78
  @ReactMethod
79
- override fun seekRelative(viewTag: Int, offsetSeconds: Double) {
80
- runOnUiThread(viewTag) { it.seekRelative(offsetSeconds) }
79
+ override fun seekRelative(viewTag: Double, offsetSeconds: Double) {
80
+ runOnUiThread(viewTag.toInt()) { it.seekRelative(offsetSeconds) }
81
81
  }
82
82
 
83
83
  @ReactMethod
84
- override fun setVolume(viewTag: Int, volume: Double) {
85
- runOnUiThread(viewTag) { it.setVolume(volume) }
84
+ override fun setVolume(viewTag: Double, volume: Double) {
85
+ runOnUiThread(viewTag.toInt()) { it.setVolume(volume) }
86
86
  }
87
87
 
88
88
  @ReactMethod
89
- override fun setMuted(viewTag: Int, muted: Boolean) {
90
- runOnUiThread(viewTag) { it.setMuted(muted) }
89
+ override fun setMuted(viewTag: Double, muted: Boolean) {
90
+ runOnUiThread(viewTag.toInt()) { it.setMuted(muted) }
91
91
  }
92
92
 
93
93
  @ReactMethod
94
- override fun enterFullscreen(viewTag: Int) {
95
- runOnUiThread(viewTag) { it.enterFullscreen() }
94
+ override fun enterFullscreen(viewTag: Double) {
95
+ runOnUiThread(viewTag.toInt()) { it.enterFullscreen() }
96
96
  }
97
97
 
98
98
  @ReactMethod
99
- override fun enterFullscreenLandscape(viewTag: Int) {
100
- runOnUiThread(viewTag) { it.enterFullscreenLandscape() }
99
+ override fun enterFullscreenLandscape(viewTag: Double) {
100
+ runOnUiThread(viewTag.toInt()) { it.enterFullscreenLandscape() }
101
101
  }
102
102
 
103
103
  @ReactMethod
104
- override fun exitFullscreen(viewTag: Int) {
105
- runOnUiThread(viewTag) { it.exitFullscreen() }
104
+ override fun exitFullscreen(viewTag: Double) {
105
+ runOnUiThread(viewTag.toInt()) { it.exitFullscreen() }
106
106
  }
107
107
 
108
108
  @ReactMethod
109
- override fun collapse(viewTag: Int) {
110
- runOnUiThread(viewTag) { it.collapse() }
109
+ override fun collapse(viewTag: Double) {
110
+ runOnUiThread(viewTag.toInt()) { it.collapse() }
111
111
  }
112
112
 
113
113
  @ReactMethod
114
- override fun expand(viewTag: Int) {
115
- runOnUiThread(viewTag) { it.expand() }
114
+ override fun expand(viewTag: Double) {
115
+ runOnUiThread(viewTag.toInt()) { it.expand() }
116
116
  }
117
117
 
118
118
  @ReactMethod
119
- override fun autoPlayNextCancel(viewTag: Int) {
120
- runOnUiThread(viewTag) { it.autoPlayNextCancel() }
119
+ override fun autoPlayNextCancel(viewTag: Double) {
120
+ runOnUiThread(viewTag.toInt()) { it.autoPlayNextCancel() }
121
121
  }
122
122
 
123
123
  @ReactMethod
124
- override fun destroy(viewTag: Int) {
125
- runOnUiThread(viewTag) { it.destroy() }
124
+ override fun destroy(viewTag: Double) {
125
+ runOnUiThread(viewTag.toInt()) { it.destroy() }
126
126
  }
127
127
 
128
128
  @ReactMethod
129
- override fun showCastPicker(viewTag: Int) {
130
- runOnUiThread(viewTag) { it.showCastPicker() }
129
+ override fun showCastPicker(viewTag: Double) {
130
+ runOnUiThread(viewTag.toInt()) { it.showCastPicker() }
131
131
  }
132
132
 
133
133
  @ReactMethod
134
134
  override fun loadWithClipId(
135
- viewTag: Int,
135
+ viewTag: Double,
136
136
  clipId: String,
137
137
  initiator: String?,
138
138
  autoPlay: Boolean,
139
139
  seekTo: Double
140
140
  ) {
141
141
  Log.d("BBPlayerModule", "loadWithClipId called - viewTag: $viewTag, clipId: $clipId, autoPlay: $autoPlay")
142
- runOnUiThread(viewTag) {
142
+ runOnUiThread(viewTag.toInt()) {
143
143
  it.loadWithClipId(
144
144
  clipId,
145
145
  initiator,
@@ -151,13 +151,13 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
151
151
 
152
152
  @ReactMethod
153
153
  override fun loadWithClipListId(
154
- viewTag: Int,
154
+ viewTag: Double,
155
155
  clipListId: String,
156
156
  initiator: String?,
157
157
  autoPlay: Boolean,
158
158
  seekTo: Double
159
159
  ) {
160
- runOnUiThread(viewTag) {
160
+ runOnUiThread(viewTag.toInt()) {
161
161
  it.loadWithClipListId(
162
162
  clipListId,
163
163
  initiator,
@@ -169,13 +169,13 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
169
169
 
170
170
  @ReactMethod
171
171
  override fun loadWithProjectId(
172
- viewTag: Int,
172
+ viewTag: Double,
173
173
  projectId: String,
174
174
  initiator: String?,
175
175
  autoPlay: Boolean,
176
176
  seekTo: Double
177
177
  ) {
178
- runOnUiThread(viewTag) {
178
+ runOnUiThread(viewTag.toInt()) {
179
179
  it.loadWithProjectId(
180
180
  projectId,
181
181
  initiator,
@@ -187,13 +187,13 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
187
187
 
188
188
  @ReactMethod
189
189
  override fun loadWithClipJson(
190
- viewTag: Int,
190
+ viewTag: Double,
191
191
  clipJson: String,
192
192
  initiator: String?,
193
193
  autoPlay: Boolean,
194
194
  seekTo: Double
195
195
  ) {
196
- runOnUiThread(viewTag) {
196
+ runOnUiThread(viewTag.toInt()) {
197
197
  it.loadWithClipJson(
198
198
  clipJson,
199
199
  initiator,
@@ -205,13 +205,13 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
205
205
 
206
206
  @ReactMethod
207
207
  override fun loadWithClipListJson(
208
- viewTag: Int,
208
+ viewTag: Double,
209
209
  clipListJson: String,
210
210
  initiator: String?,
211
211
  autoPlay: Boolean,
212
212
  seekTo: Double
213
213
  ) {
214
- runOnUiThread(viewTag) {
214
+ runOnUiThread(viewTag.toInt()) {
215
215
  it.loadWithClipListJson(
216
216
  clipListJson,
217
217
  initiator,
@@ -223,13 +223,13 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
223
223
 
224
224
  @ReactMethod
225
225
  override fun loadWithProjectJson(
226
- viewTag: Int,
226
+ viewTag: Double,
227
227
  projectJson: String,
228
228
  initiator: String?,
229
229
  autoPlay: Boolean,
230
230
  seekTo: Double
231
231
  ) {
232
- runOnUiThread(viewTag) {
232
+ runOnUiThread(viewTag.toInt()) {
233
233
  it.loadWithProjectJson(
234
234
  projectJson,
235
235
  initiator,
@@ -241,11 +241,11 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
241
241
 
242
242
  @ReactMethod
243
243
  override fun loadWithJsonUrl(
244
- viewTag: Int,
244
+ viewTag: Double,
245
245
  jsonUrl: String,
246
246
  autoPlay: Boolean
247
247
  ) {
248
- runOnUiThread(viewTag) {
248
+ runOnUiThread(viewTag.toInt()) {
249
249
  it.loadWithJsonUrl(jsonUrl, autoPlay)
250
250
  }
251
251
  }
@@ -255,9 +255,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
255
255
 
256
256
  // Getter methods with Promise support
257
257
  @ReactMethod
258
- override fun getDuration(viewTag: Int, promise: Promise) {
258
+ override fun getDuration(viewTag: Double, promise: Promise) {
259
259
  UiThreadUtil.runOnUiThread {
260
- val view = findPlayerView(viewTag)
260
+ val view = findPlayerView(viewTag.toInt())
261
261
  if (view != null) {
262
262
  val duration = view.getDuration()
263
263
  promise.resolve(duration)
@@ -268,9 +268,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
268
268
  }
269
269
 
270
270
  @ReactMethod
271
- override fun getCurrentTime(viewTag: Int, promise: Promise) {
271
+ override fun getCurrentTime(viewTag: Double, promise: Promise) {
272
272
  UiThreadUtil.runOnUiThread {
273
- val view = findPlayerView(viewTag)
273
+ val view = findPlayerView(viewTag.toInt())
274
274
  if (view != null) {
275
275
  val currentTime = view.getCurrentTime()
276
276
  promise.resolve(currentTime)
@@ -281,9 +281,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
281
281
  }
282
282
 
283
283
  @ReactMethod
284
- override fun getMuted(viewTag: Int, promise: Promise) {
284
+ override fun getMuted(viewTag: Double, promise: Promise) {
285
285
  UiThreadUtil.runOnUiThread {
286
- val view = findPlayerView(viewTag)
286
+ val view = findPlayerView(viewTag.toInt())
287
287
  if (view != null) {
288
288
  val muted = view.getMuted()
289
289
  promise.resolve(muted)
@@ -294,9 +294,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
294
294
  }
295
295
 
296
296
  @ReactMethod
297
- override fun getVolume(viewTag: Int, promise: Promise) {
297
+ override fun getVolume(viewTag: Double, promise: Promise) {
298
298
  UiThreadUtil.runOnUiThread {
299
- val view = findPlayerView(viewTag)
299
+ val view = findPlayerView(viewTag.toInt())
300
300
  if (view != null) {
301
301
  val volume = view.getVolume()
302
302
  promise.resolve(volume)
@@ -307,9 +307,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
307
307
  }
308
308
 
309
309
  @ReactMethod
310
- override fun getPhase(viewTag: Int, promise: Promise) {
310
+ override fun getPhase(viewTag: Double, promise: Promise) {
311
311
  UiThreadUtil.runOnUiThread {
312
- val view = findPlayerView(viewTag)
312
+ val view = findPlayerView(viewTag.toInt())
313
313
  if (view != null) {
314
314
  val phase = view.getPhase()
315
315
  promise.resolve(phase?.name)
@@ -320,9 +320,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
320
320
  }
321
321
 
322
322
  @ReactMethod
323
- override fun getState(viewTag: Int, promise: Promise) {
323
+ override fun getState(viewTag: Double, promise: Promise) {
324
324
  UiThreadUtil.runOnUiThread {
325
- val view = findPlayerView(viewTag)
325
+ val view = findPlayerView(viewTag.toInt())
326
326
  if (view != null) {
327
327
  val state = view.getState()
328
328
  promise.resolve(state?.name)
@@ -333,9 +333,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
333
333
  }
334
334
 
335
335
  @ReactMethod
336
- override fun getMode(viewTag: Int, promise: Promise) {
336
+ override fun getMode(viewTag: Double, promise: Promise) {
337
337
  UiThreadUtil.runOnUiThread {
338
- val view = findPlayerView(viewTag)
338
+ val view = findPlayerView(viewTag.toInt())
339
339
  if (view != null) {
340
340
  val mode = view.getMode()
341
341
  promise.resolve(mode)
@@ -346,9 +346,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
346
346
  }
347
347
 
348
348
  @ReactMethod
349
- override fun getClipData(viewTag: Int, promise: Promise) {
349
+ override fun getClipData(viewTag: Double, promise: Promise) {
350
350
  UiThreadUtil.runOnUiThread {
351
- val view = findPlayerView(viewTag)
351
+ val view = findPlayerView(viewTag.toInt())
352
352
  if (view != null) {
353
353
  val clipData = view.getClipData()
354
354
  if (clipData != null) {
@@ -369,9 +369,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
369
369
  }
370
370
 
371
371
  @ReactMethod
372
- override fun getProjectData(viewTag: Int, promise: Promise) {
372
+ override fun getProjectData(viewTag: Double, promise: Promise) {
373
373
  UiThreadUtil.runOnUiThread {
374
- val view = findPlayerView(viewTag)
374
+ val view = findPlayerView(viewTag.toInt())
375
375
  if (view != null) {
376
376
  val projectData = view.getProjectData()
377
377
  if (projectData != null) {
@@ -390,9 +390,9 @@ class BBPlayerModule(private val reactContext: ReactApplicationContext) :
390
390
  }
391
391
 
392
392
  @ReactMethod
393
- override fun getPlayoutData(viewTag: Int, promise: Promise) {
393
+ override fun getPlayoutData(viewTag: Double, promise: Promise) {
394
394
  UiThreadUtil.runOnUiThread {
395
- val view = findPlayerView(viewTag)
395
+ val view = findPlayerView(viewTag.toInt())
396
396
  if (view != null) {
397
397
  val playoutData = view.getPlayoutData()
398
398
  if (playoutData != null) {
@@ -212,7 +212,7 @@ class BBPlayerModule: NSObject {
212
212
 
213
213
  @objc func getClipData(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
214
214
  DispatchQueue.main.async {
215
- let clipData = self.getView(viewTag)?.adMediaClip()
215
+ let clipData = self.getView(viewTag)?.clipData()
216
216
  resolver(clipData)
217
217
  }
218
218
  }