@bluebillywig/react-native-bb-player 8.47.1 → 8.47.3
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/android/build.gradle +0 -10
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeplayersdk/8.46.0/bbnativeplayersdk-8.46.0.aar +0 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeplayersdk/8.46.0/bbnativeplayersdk-8.46.0.module +137 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeplayersdk/8.46.0/bbnativeplayersdk-8.46.0.pom +57 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeplayersdk-core/8.46.0/bbnativeplayersdk-core-8.46.0.aar +0 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeplayersdk-core/8.46.0/bbnativeplayersdk-core-8.46.0.module +264 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeplayersdk-core/8.46.0/bbnativeplayersdk-core-8.46.0.pom +171 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeshared/8.46.0/bbnativeshared-8.46.0.jar +0 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeshared/8.46.0/bbnativeshared-8.46.0.module +159 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeshared/8.46.0/bbnativeshared-8.46.0.pom +36 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeshared-android/8.46.0/bbnativeshared-android-8.46.0.aar +0 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeshared-android/8.46.0/bbnativeshared-android-8.46.0.module +329 -0
- package/android/repo/com/bluebillywig/bbnativeplayersdk/bbnativeshared-android/8.46.0/bbnativeshared-android-8.46.0.pom +267 -0
- package/android/src/main/java/com/bluebillywig/bbplayer/BBPlayerModule.kt +5 -0
- package/android/src/main/java/com/bluebillywig/bbplayer/BBPlayerView.kt +8 -0
- package/ios/BBCastButtonView.swift +1 -1
- package/ios/BBCastButtonViewManager.swift +3 -3
- package/ios/BBCastMiniControlsView.swift +1 -1
- package/ios/BBCastMiniControlsViewManager.swift +3 -3
- package/ios/BBPlayerExtensions.swift +1 -1
- package/ios/BBPlayerModule.mm +1 -0
- package/ios/BBPlayerModule.swift +72 -152
- package/ios/BBPlayerView.swift +21 -9
- package/ios/BBPlayerViewManager.swift +34 -73
- package/ios/BBShortsView.swift +6 -3
- package/ios/BBShortsViewManager.swift +11 -9
- package/ios/Frameworks/BBNativePlayerKit.xcframework/ios-arm64/BBNativePlayerKit.framework/_CodeSignature/CodeResources +256 -0
- package/ios/Frameworks/BBNativePlayerKit.xcframework/ios-arm64_x86_64-simulator/BBNativePlayerKit.framework/_CodeSignature/CodeResources +311 -0
- package/lib/commonjs/BBOutstreamView.js +1 -0
- package/lib/commonjs/BBOutstreamView.js.map +1 -1
- package/lib/commonjs/NativeCommands.js +4 -0
- package/lib/commonjs/NativeCommands.js.map +1 -1
- package/lib/commonjs/index.js +0 -4
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/NativeBBPlayerModule.js.map +1 -1
- package/lib/module/BBOutstreamView.js +1 -0
- package/lib/module/BBOutstreamView.js.map +1 -1
- package/lib/module/NativeCommands.js +4 -0
- package/lib/module/NativeCommands.js.map +1 -1
- package/lib/module/index.js +0 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/NativeBBPlayerModule.js.map +1 -1
- package/lib/typescript/src/BBOutstreamView.d.ts.map +1 -1
- package/lib/typescript/src/BBPlayer.types.d.ts +2 -0
- package/lib/typescript/src/BBPlayer.types.d.ts.map +1 -1
- package/lib/typescript/src/NativeCommands.d.ts +1 -0
- package/lib/typescript/src/NativeCommands.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +0 -4
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/NativeBBPlayerModule.d.ts +1 -0
- package/lib/typescript/src/specs/NativeBBPlayerModule.d.ts.map +1 -1
- package/package.json +1 -1
- package/react-native-bb-player.podspec +3 -2
- package/src/BBOutstreamView.tsx +1 -0
- package/src/BBPlayer.types.ts +2 -0
- package/src/NativeCommands.ts +4 -0
- package/src/index.ts +0 -8
- package/src/specs/NativeBBPlayerModule.ts +1 -0
package/ios/BBPlayerModule.swift
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import Foundation
|
|
2
|
-
import React
|
|
3
|
-
import BBNativePlayerKit
|
|
2
|
+
@preconcurrency import React
|
|
3
|
+
@preconcurrency import BBNativePlayerKit
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Global registry for BBPlayerView instances.
|
|
7
|
-
*
|
|
8
|
-
* with
|
|
7
|
+
* Needed because bridge.uiManager.view(forReactTag:) doesn't work
|
|
8
|
+
* with Fabric. Views register themselves when added to the window.
|
|
9
9
|
*/
|
|
10
|
-
class BBPlayerViewRegistry: NSObject {
|
|
10
|
+
final class BBPlayerViewRegistry: NSObject, @unchecked Sendable {
|
|
11
11
|
static let shared = BBPlayerViewRegistry()
|
|
12
12
|
|
|
13
13
|
private var views: [Int: BBPlayerView] = [:]
|
|
@@ -41,10 +41,10 @@ class BBPlayerViewRegistry: NSObject {
|
|
|
41
41
|
/**
|
|
42
42
|
* Native Module for BBPlayer commands.
|
|
43
43
|
* Extends RCTEventEmitter to support module-level events (modal player).
|
|
44
|
-
*
|
|
44
|
+
* Looks up BBPlayerView instances by React tag and dispatches commands.
|
|
45
45
|
*/
|
|
46
46
|
@objc(BBPlayerModule)
|
|
47
|
-
class BBPlayerModule: RCTEventEmitter {
|
|
47
|
+
class BBPlayerModule: RCTEventEmitter, @unchecked Sendable {
|
|
48
48
|
|
|
49
49
|
private var modalPlayerView: BBNativePlayerView?
|
|
50
50
|
private var modalDelegate: ModalPlayerDelegate?
|
|
@@ -79,150 +79,119 @@ class BBPlayerModule: RCTEventEmitter {
|
|
|
79
79
|
hasListeners = false
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
// MARK: -
|
|
82
|
+
// MARK: - Helpers
|
|
83
83
|
|
|
84
84
|
private func getView(_ reactTag: NSNumber) -> BBPlayerView? {
|
|
85
|
-
// First try the view registry (works with both old and new architecture)
|
|
86
85
|
if let view = BBPlayerViewRegistry.shared.getView(tag: reactTag.intValue) {
|
|
87
86
|
return view
|
|
88
87
|
}
|
|
89
|
-
|
|
90
|
-
// Fallback to bridge.uiManager for old architecture
|
|
91
88
|
if let bridge = self.bridge {
|
|
92
89
|
if let view = bridge.uiManager.view(forReactTag: reactTag) as? BBPlayerView {
|
|
93
90
|
return view
|
|
94
91
|
}
|
|
95
92
|
}
|
|
96
|
-
|
|
97
93
|
NSLog("BBPlayerModule: Could not find view with tag %@", reactTag)
|
|
98
94
|
return nil
|
|
99
95
|
}
|
|
100
96
|
|
|
97
|
+
/// Dispatch to main queue and enter @MainActor context.
|
|
98
|
+
private func onMainActor(_ work: @MainActor @Sendable @escaping () -> Void) {
|
|
99
|
+
DispatchQueue.main.async {
|
|
100
|
+
MainActor.assumeIsolated(work)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
101
104
|
// MARK: - Commands
|
|
102
105
|
|
|
103
106
|
@objc func play(_ viewTag: NSNumber) {
|
|
104
|
-
|
|
105
|
-
self.getView(viewTag)?.play()
|
|
106
|
-
}
|
|
107
|
+
onMainActor { self.getView(viewTag)?.play() }
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
@objc func pause(_ viewTag: NSNumber) {
|
|
110
|
-
|
|
111
|
-
self.getView(viewTag)?.pause()
|
|
112
|
-
}
|
|
111
|
+
onMainActor { self.getView(viewTag)?.pause() }
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
@objc func seek(_ viewTag: NSNumber, position: NSNumber) {
|
|
116
|
-
|
|
117
|
-
self.getView(viewTag)?.seek(position.intValue)
|
|
118
|
-
}
|
|
115
|
+
onMainActor { self.getView(viewTag)?.seek(position.intValue) }
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
@objc func seekRelative(_ viewTag: NSNumber, offsetSeconds: NSNumber) {
|
|
122
|
-
|
|
123
|
-
self.getView(viewTag)?.seekRelative(offsetSeconds.doubleValue)
|
|
124
|
-
}
|
|
119
|
+
onMainActor { self.getView(viewTag)?.seekRelative(offsetSeconds.doubleValue) }
|
|
125
120
|
}
|
|
126
121
|
|
|
127
122
|
@objc func setMuted(_ viewTag: NSNumber, muted: Bool) {
|
|
128
|
-
|
|
129
|
-
self.getView(viewTag)?.setMuted(muted)
|
|
130
|
-
}
|
|
123
|
+
onMainActor { self.getView(viewTag)?.setMuted(muted) }
|
|
131
124
|
}
|
|
132
125
|
|
|
133
126
|
@objc func setVolume(_ viewTag: NSNumber, volume: NSNumber) {
|
|
134
|
-
|
|
135
|
-
self.getView(viewTag)?.setVolume(volume.doubleValue)
|
|
136
|
-
}
|
|
127
|
+
onMainActor { self.getView(viewTag)?.setVolume(volume.doubleValue) }
|
|
137
128
|
}
|
|
138
129
|
|
|
139
130
|
@objc func enterFullscreen(_ viewTag: NSNumber) {
|
|
140
|
-
|
|
141
|
-
self.getView(viewTag)?.enterFullscreen()
|
|
142
|
-
}
|
|
131
|
+
onMainActor { self.getView(viewTag)?.enterFullscreen() }
|
|
143
132
|
}
|
|
144
133
|
|
|
145
134
|
@objc func enterFullscreenLandscape(_ viewTag: NSNumber) {
|
|
146
|
-
|
|
147
|
-
self.getView(viewTag)?.enterFullscreenLandscape()
|
|
148
|
-
}
|
|
135
|
+
onMainActor { self.getView(viewTag)?.enterFullscreenLandscape() }
|
|
149
136
|
}
|
|
150
137
|
|
|
151
138
|
@objc func exitFullscreen(_ viewTag: NSNumber) {
|
|
152
|
-
|
|
153
|
-
self.getView(viewTag)?.exitFullscreen()
|
|
154
|
-
}
|
|
139
|
+
onMainActor { self.getView(viewTag)?.exitFullscreen() }
|
|
155
140
|
}
|
|
156
141
|
|
|
157
142
|
@objc func collapse(_ viewTag: NSNumber) {
|
|
158
|
-
|
|
159
|
-
self.getView(viewTag)?.collapse()
|
|
160
|
-
}
|
|
143
|
+
onMainActor { self.getView(viewTag)?.collapse() }
|
|
161
144
|
}
|
|
162
145
|
|
|
163
146
|
@objc func expand(_ viewTag: NSNumber) {
|
|
164
|
-
|
|
165
|
-
self.getView(viewTag)?.expand()
|
|
166
|
-
}
|
|
147
|
+
onMainActor { self.getView(viewTag)?.expand() }
|
|
167
148
|
}
|
|
168
149
|
|
|
169
150
|
@objc func autoPlayNextCancel(_ viewTag: NSNumber) {
|
|
170
|
-
|
|
171
|
-
self.getView(viewTag)?.autoPlayNextCancel()
|
|
172
|
-
}
|
|
151
|
+
onMainActor { self.getView(viewTag)?.autoPlayNextCancel() }
|
|
173
152
|
}
|
|
174
153
|
|
|
175
154
|
@objc func destroy(_ viewTag: NSNumber) {
|
|
176
|
-
|
|
177
|
-
self.getView(viewTag)?.destroy()
|
|
178
|
-
}
|
|
155
|
+
onMainActor { self.getView(viewTag)?.destroy() }
|
|
179
156
|
}
|
|
180
157
|
|
|
181
158
|
@objc func showCastPicker(_ viewTag: NSNumber) {
|
|
159
|
+
onMainActor { self.getView(viewTag)?.showCastPicker() }
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@objc func updatePlayout(_ viewTag: NSNumber, playoutJson: String) {
|
|
182
163
|
DispatchQueue.main.async {
|
|
183
|
-
self.getView(viewTag)?.
|
|
164
|
+
self.getView(viewTag)?.updatePlayout(playoutJson)
|
|
184
165
|
}
|
|
185
166
|
}
|
|
186
167
|
|
|
187
168
|
@objc func loadWithClipId(_ viewTag: NSNumber, clipId: String?, initiator: String?, autoPlay: Bool, seekTo: NSNumber?, contextJson: String?) {
|
|
188
|
-
|
|
189
|
-
self.getView(viewTag)?.loadWithClipId(clipId ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson)
|
|
190
|
-
}
|
|
169
|
+
onMainActor { self.getView(viewTag)?.loadWithClipId(clipId ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson) }
|
|
191
170
|
}
|
|
192
171
|
|
|
193
172
|
@objc func loadWithClipListId(_ viewTag: NSNumber, clipListId: String?, initiator: String?, autoPlay: Bool, seekTo: NSNumber?, contextJson: String?) {
|
|
194
|
-
|
|
195
|
-
self.getView(viewTag)?.loadWithClipListId(clipListId ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson)
|
|
196
|
-
}
|
|
173
|
+
onMainActor { self.getView(viewTag)?.loadWithClipListId(clipListId ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson) }
|
|
197
174
|
}
|
|
198
175
|
|
|
199
176
|
@objc func loadWithProjectId(_ viewTag: NSNumber, projectId: String?, initiator: String?, autoPlay: Bool, seekTo: NSNumber?, contextJson: String?) {
|
|
200
|
-
|
|
201
|
-
self.getView(viewTag)?.loadWithProjectId(projectId ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson)
|
|
202
|
-
}
|
|
177
|
+
onMainActor { self.getView(viewTag)?.loadWithProjectId(projectId ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson) }
|
|
203
178
|
}
|
|
204
179
|
|
|
205
180
|
@objc func loadWithClipJson(_ viewTag: NSNumber, clipJson: String?, initiator: String?, autoPlay: Bool, seekTo: NSNumber?, contextJson: String?) {
|
|
206
|
-
|
|
207
|
-
self.getView(viewTag)?.loadWithClipJson(clipJson ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson)
|
|
208
|
-
}
|
|
181
|
+
onMainActor { self.getView(viewTag)?.loadWithClipJson(clipJson ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson) }
|
|
209
182
|
}
|
|
210
183
|
|
|
211
184
|
@objc func loadWithClipListJson(_ viewTag: NSNumber, clipListJson: String?, initiator: String?, autoPlay: Bool, seekTo: NSNumber?, contextJson: String?) {
|
|
212
|
-
|
|
213
|
-
self.getView(viewTag)?.loadWithClipListJson(clipListJson ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson)
|
|
214
|
-
}
|
|
185
|
+
onMainActor { self.getView(viewTag)?.loadWithClipListJson(clipListJson ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson) }
|
|
215
186
|
}
|
|
216
187
|
|
|
217
188
|
@objc func loadWithProjectJson(_ viewTag: NSNumber, projectJson: String?, initiator: String?, autoPlay: Bool, seekTo: NSNumber?, contextJson: String?) {
|
|
218
|
-
|
|
219
|
-
self.getView(viewTag)?.loadWithProjectJson(projectJson ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson)
|
|
220
|
-
}
|
|
189
|
+
onMainActor { self.getView(viewTag)?.loadWithProjectJson(projectJson ?? "", initiator: initiator, autoPlay: autoPlay, seekTo: seekTo?.doubleValue, contextJson: contextJson) }
|
|
221
190
|
}
|
|
222
191
|
|
|
223
192
|
@objc func loadWithJsonUrl(_ viewTag: NSNumber, jsonUrl: String?, autoPlay: Bool, contextJson: String?) {
|
|
224
193
|
NSLog("BBPlayerModule.loadWithJsonUrl called - viewTag: %@, jsonUrl: %@, autoPlay: %d, context: %@", viewTag, jsonUrl ?? "nil", autoPlay, contextJson ?? "nil")
|
|
225
|
-
|
|
194
|
+
onMainActor {
|
|
226
195
|
let view = self.getView(viewTag)
|
|
227
196
|
NSLog("BBPlayerModule.loadWithJsonUrl - view found: %@", view != nil ? "YES" : "NO")
|
|
228
197
|
if let view = view, let url = jsonUrl {
|
|
@@ -235,7 +204,7 @@ class BBPlayerModule: RCTEventEmitter {
|
|
|
235
204
|
}
|
|
236
205
|
|
|
237
206
|
@objc func loadWithContentIdAndType(_ viewTag: NSNumber, contentId: String?, contentType: String?, autoPlay: Bool, contextJson: String?) {
|
|
238
|
-
|
|
207
|
+
onMainActor {
|
|
239
208
|
let view = self.getView(viewTag)
|
|
240
209
|
guard let view = view, let id = contentId, let type = contentType else {
|
|
241
210
|
NSLog("BBPlayerModule.loadWithContentIdAndType - FAILED: view=%@, id=%@, type=%@",
|
|
@@ -247,101 +216,77 @@ class BBPlayerModule: RCTEventEmitter {
|
|
|
247
216
|
}
|
|
248
217
|
|
|
249
218
|
// MARK: - Getter methods with Promise support
|
|
219
|
+
// Note: nonisolated(unsafe) on resolver because RCTPromiseResolveBlock is a
|
|
220
|
+
// non-Sendable ObjC block, but RN guarantees safe cross-thread usage.
|
|
250
221
|
|
|
251
222
|
@objc func getDuration(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
resolver(duration)
|
|
255
|
-
}
|
|
223
|
+
nonisolated(unsafe) let resolve = resolver
|
|
224
|
+
onMainActor { resolve(self.getView(viewTag)?.duration()) }
|
|
256
225
|
}
|
|
257
226
|
|
|
258
227
|
@objc func getMuted(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
resolver(muted)
|
|
262
|
-
}
|
|
228
|
+
nonisolated(unsafe) let resolve = resolver
|
|
229
|
+
onMainActor { resolve(self.getView(viewTag)?.muted()) }
|
|
263
230
|
}
|
|
264
231
|
|
|
265
232
|
@objc func getVolume(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
resolver(volume)
|
|
269
|
-
}
|
|
233
|
+
nonisolated(unsafe) let resolve = resolver
|
|
234
|
+
onMainActor { resolve(self.getView(viewTag)?.volume()) }
|
|
270
235
|
}
|
|
271
236
|
|
|
272
237
|
@objc func getPhase(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
resolver(phase)
|
|
276
|
-
}
|
|
238
|
+
nonisolated(unsafe) let resolve = resolver
|
|
239
|
+
onMainActor { resolve(self.getView(viewTag)?.phase()) }
|
|
277
240
|
}
|
|
278
241
|
|
|
279
242
|
@objc func getState(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
resolver(state)
|
|
283
|
-
}
|
|
243
|
+
nonisolated(unsafe) let resolve = resolver
|
|
244
|
+
onMainActor { resolve(self.getView(viewTag)?.state()) }
|
|
284
245
|
}
|
|
285
246
|
|
|
286
247
|
@objc func getMode(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
resolver(mode)
|
|
290
|
-
}
|
|
248
|
+
nonisolated(unsafe) let resolve = resolver
|
|
249
|
+
onMainActor { resolve(self.getView(viewTag)?.mode()) }
|
|
291
250
|
}
|
|
292
251
|
|
|
293
252
|
@objc func getClipData(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
resolver(clipData)
|
|
297
|
-
}
|
|
253
|
+
nonisolated(unsafe) let resolve = resolver
|
|
254
|
+
onMainActor { resolve(self.getView(viewTag)?.clipData()) }
|
|
298
255
|
}
|
|
299
256
|
|
|
300
257
|
@objc func getProjectData(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
resolver(projectData)
|
|
304
|
-
}
|
|
258
|
+
nonisolated(unsafe) let resolve = resolver
|
|
259
|
+
onMainActor { resolve(self.getView(viewTag)?.projectData()) }
|
|
305
260
|
}
|
|
306
261
|
|
|
307
262
|
@objc func getPlayoutData(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
resolver(playoutData)
|
|
311
|
-
}
|
|
263
|
+
nonisolated(unsafe) let resolve = resolver
|
|
264
|
+
onMainActor { resolve(self.getView(viewTag)?.playoutData()) }
|
|
312
265
|
}
|
|
313
266
|
|
|
314
267
|
@objc func setInView(_ viewTag: NSNumber, inView: Bool) {
|
|
315
|
-
|
|
316
|
-
self.getView(viewTag)?.setInView(inView)
|
|
317
|
-
}
|
|
268
|
+
onMainActor { self.getView(viewTag)?.setInView(inView) }
|
|
318
269
|
}
|
|
319
270
|
|
|
320
271
|
@objc func getInView(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
resolver(inView)
|
|
324
|
-
}
|
|
272
|
+
nonisolated(unsafe) let resolve = resolver
|
|
273
|
+
onMainActor { resolve(self.getView(viewTag)?.inView()) }
|
|
325
274
|
}
|
|
326
275
|
|
|
327
276
|
@objc func getAdMediaWidth(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
resolver(width)
|
|
331
|
-
}
|
|
277
|
+
nonisolated(unsafe) let resolve = resolver
|
|
278
|
+
onMainActor { resolve(self.getView(viewTag)?.adMediaWidth()) }
|
|
332
279
|
}
|
|
333
280
|
|
|
334
281
|
@objc func getAdMediaHeight(_ viewTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
resolver(height)
|
|
338
|
-
}
|
|
282
|
+
nonisolated(unsafe) let resolve = resolver
|
|
283
|
+
onMainActor { resolve(self.getView(viewTag)?.adMediaHeight()) }
|
|
339
284
|
}
|
|
340
285
|
|
|
341
286
|
// MARK: - Modal Player API
|
|
342
287
|
|
|
343
288
|
@objc func presentModalPlayer(_ jsonUrl: String, optionsJson: String?, contextJson: String?) {
|
|
344
|
-
|
|
289
|
+
onMainActor {
|
|
345
290
|
// RCTPresentedViewController() can return nil with RCTReactNativeFactory (RN 0.83+).
|
|
346
291
|
// Fallback to UIScene-based lookup to find the root view controller.
|
|
347
292
|
guard let rootVC = RCTPresentedViewController()
|
|
@@ -371,14 +316,9 @@ class BBPlayerModule: RCTEventEmitter {
|
|
|
371
316
|
}
|
|
372
317
|
loadOptions["showBackArrow"] = options?["showBackArrow"] as? Bool ?? false
|
|
373
318
|
|
|
374
|
-
// When context has a cliplist (contextCollectionId), load clip by ID
|
|
375
|
-
// with cliplist context. ProgramController will swap to loading the
|
|
376
|
-
// cliplist and find the clip by ID (matching web standardplayer pattern).
|
|
377
|
-
// Deferred until apiReady to avoid racing with initial jsonUrl load.
|
|
378
319
|
let collectionId = context?["contextCollectionId"] as? String
|
|
379
320
|
let clipId = context?["contextEntityId"] as? String
|
|
380
321
|
|
|
381
|
-
// Create and present modal player using SDK factory method
|
|
382
322
|
let playerView = BBNativePlayer.createModalPlayerView(uiViewContoller: rootVC, jsonUrl: jsonUrl, options: loadOptions)
|
|
383
323
|
|
|
384
324
|
if let collectionId = collectionId, let clipId = clipId {
|
|
@@ -391,38 +331,16 @@ class BBPlayerModule: RCTEventEmitter {
|
|
|
391
331
|
}
|
|
392
332
|
}
|
|
393
333
|
|
|
394
|
-
// Set up delegate for event forwarding
|
|
395
334
|
let delegate = ModalPlayerDelegate(module: self)
|
|
396
335
|
playerView.delegate = delegate
|
|
397
336
|
|
|
398
337
|
self.modalPlayerView = playerView
|
|
399
338
|
self.modalDelegate = delegate
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
private func extractIdFromUrl(_ url: String, pattern: String) -> String? {
|
|
405
|
-
do {
|
|
406
|
-
let regex = try NSRegularExpression(pattern: pattern, options: [])
|
|
407
|
-
let range = NSRange(url.startIndex..., in: url)
|
|
408
|
-
if let match = regex.firstMatch(in: url, options: [], range: range) {
|
|
409
|
-
for i in 1..<match.numberOfRanges {
|
|
410
|
-
if let groupRange = Range(match.range(at: i), in: url) {
|
|
411
|
-
let extracted = String(url[groupRange])
|
|
412
|
-
if !extracted.isEmpty {
|
|
413
|
-
return extracted
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
} catch {
|
|
419
|
-
NSLog("BBPlayerModule: Regex error: %@", error.localizedDescription)
|
|
420
339
|
}
|
|
421
|
-
return nil
|
|
422
340
|
}
|
|
423
341
|
|
|
424
342
|
@objc func dismissModalPlayer() {
|
|
425
|
-
|
|
343
|
+
onMainActor {
|
|
426
344
|
self.modalPlayerView?.player.closeModalPlayer()
|
|
427
345
|
self.modalPlayerView = nil
|
|
428
346
|
self.modalDelegate = nil
|
|
@@ -446,7 +364,9 @@ class BBPlayerModule: RCTEventEmitter {
|
|
|
446
364
|
|
|
447
365
|
// MARK: - Modal Player Delegate
|
|
448
366
|
|
|
367
|
+
@MainActor
|
|
449
368
|
private class ModalPlayerDelegate: NSObject, BBNativePlayerViewDelegate {
|
|
369
|
+
// Module ref is @unchecked Sendable, safe to access from @MainActor
|
|
450
370
|
weak var module: BBPlayerModule?
|
|
451
371
|
|
|
452
372
|
init(module: BBPlayerModule) {
|
package/ios/BBPlayerView.swift
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import BBNativePlayerKit
|
|
1
|
+
@preconcurrency import BBNativePlayerKit
|
|
2
|
+
@preconcurrency import React
|
|
2
3
|
import WebKit
|
|
3
|
-
import bbnativeshared
|
|
4
|
+
@preconcurrency import bbnativeshared
|
|
4
5
|
import os
|
|
5
|
-
import GoogleCast
|
|
6
|
+
@preconcurrency import GoogleCast
|
|
6
7
|
|
|
7
8
|
// MARK: - Logging Helper
|
|
8
9
|
private enum LogLevel {
|
|
@@ -49,6 +50,8 @@ class BBPlayerView: UIView, BBNativePlayerViewDelegate {
|
|
|
49
50
|
private var independentCastButton: GCKUICastButton?
|
|
50
51
|
// Store parent view controller reference for SDK
|
|
51
52
|
private weak var parentViewController: UIViewController?
|
|
53
|
+
// Cached tag for deinit (nonisolated(unsafe) because deinit is nonisolated in Swift 6)
|
|
54
|
+
nonisolated(unsafe) private var _cachedTag: Int?
|
|
52
55
|
|
|
53
56
|
// MARK: - Props (set from React Native)
|
|
54
57
|
|
|
@@ -130,7 +133,9 @@ class BBPlayerView: UIView, BBNativePlayerViewDelegate {
|
|
|
130
133
|
|
|
131
134
|
// Register with view registry for command dispatch (supports New Architecture)
|
|
132
135
|
if let tag = self.reactTag {
|
|
133
|
-
|
|
136
|
+
let tagInt = tag.intValue
|
|
137
|
+
_cachedTag = tagInt
|
|
138
|
+
BBPlayerViewRegistry.shared.register(self, tag: tagInt)
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
// Find the parent view controller from the responder chain
|
|
@@ -163,12 +168,11 @@ class BBPlayerView: UIView, BBNativePlayerViewDelegate {
|
|
|
163
168
|
}
|
|
164
169
|
|
|
165
170
|
deinit {
|
|
166
|
-
// Unregister from view registry
|
|
167
|
-
|
|
168
|
-
|
|
171
|
+
// Unregister from view registry using cached tag
|
|
172
|
+
// (deinit is nonisolated in Swift 6, can't access @MainActor properties)
|
|
173
|
+
if let tag = _cachedTag {
|
|
174
|
+
BBPlayerViewRegistry.shared.unregister(tag: tag)
|
|
169
175
|
}
|
|
170
|
-
independentCastButton?.removeFromSuperview()
|
|
171
|
-
independentCastButton = nil
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
|
|
@@ -577,6 +581,14 @@ class BBPlayerView: UIView, BBNativePlayerViewDelegate {
|
|
|
577
581
|
// iOS SDK cleans up automatically when view is removed
|
|
578
582
|
}
|
|
579
583
|
|
|
584
|
+
func updatePlayout(_ playoutJson: String) {
|
|
585
|
+
guard playerView != nil else {
|
|
586
|
+
NSLog("BBPlayerView.updatePlayout ERROR - playerView not initialized")
|
|
587
|
+
return
|
|
588
|
+
}
|
|
589
|
+
playerView?.player.updatePlayoutWithJson(playoutJson: playoutJson)
|
|
590
|
+
}
|
|
591
|
+
|
|
580
592
|
func pause() {
|
|
581
593
|
playerView?.player.pause()
|
|
582
594
|
}
|