bitmovin-player-react-native 1.0.0-alpha.0 → 1.0.0-alpha.2

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.
@@ -2,8 +2,6 @@ import BitmovinPlayer
2
2
  import ExpoModulesCore
3
3
 
4
4
  public class PlayerModule: Module {
5
- private var players: Registry<Player> = [:]
6
-
7
5
  // swiftlint:disable:next function_body_length
8
6
  public func definition() -> ModuleDefinition {
9
7
  Name("PlayerModule")
@@ -12,117 +10,121 @@ public class PlayerModule: Module {
12
10
  // Destroy all players on the main thread when the module is deallocated.
13
11
  // This is necessary when the IMA SDK is present in the app,
14
12
  // as it may crash if the players are destroyed on a background thread.
15
- DispatchQueue.main.async { [players] in
16
- players.values.forEach { $0.destroy() }
13
+ DispatchQueue.main.async {
14
+ PlayerRegistry.getAllPlayers().forEach { $0.destroy() }
15
+ PlayerRegistry.clear()
17
16
  }
18
17
  }
19
- AsyncFunction("play") { [weak self] (nativeId: NativeId) in
20
- self?.players[nativeId]?.play()
18
+ AsyncFunction("play") { (nativeId: NativeId) in
19
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.play()
21
20
  }.runOnQueue(.main)
22
- AsyncFunction("pause") { [weak self] (nativeId: NativeId) in
23
- self?.players[nativeId]?.pause()
21
+ AsyncFunction("pause") { (nativeId: NativeId) in
22
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.pause()
24
23
  }.runOnQueue(.main)
25
- AsyncFunction("mute") { [weak self] (nativeId: NativeId) in
26
- self?.players[nativeId]?.mute()
24
+ AsyncFunction("mute") { (nativeId: NativeId) in
25
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.mute()
27
26
  }.runOnQueue(.main)
28
- AsyncFunction("unmute") { [weak self] (nativeId: NativeId) in
29
- self?.players[nativeId]?.unmute()
27
+ AsyncFunction("unmute") { (nativeId: NativeId) in
28
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.unmute()
30
29
  }.runOnQueue(.main)
31
- AsyncFunction("seek") { [weak self] (nativeId: NativeId, time: Double) in
32
- self?.players[nativeId]?.seek(time: time)
30
+ AsyncFunction("seek") { (nativeId: NativeId, time: Double) in
31
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.seek(time: time)
33
32
  }.runOnQueue(.main)
34
- AsyncFunction("timeShift") { [weak self] (nativeId: NativeId, offset: Double) in
35
- self?.players[nativeId]?.timeShift = offset
33
+ AsyncFunction("timeShift") { (nativeId: NativeId, offset: Double) in
34
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.timeShift = offset
36
35
  }.runOnQueue(.main)
37
- AsyncFunction("destroy") { [weak self] (nativeId: NativeId) in
38
- if let player = self?.players[nativeId] {
36
+ AsyncFunction("destroy") { (nativeId: NativeId) in
37
+ if let player = PlayerRegistry.getPlayer(nativeId: nativeId) {
39
38
  player.destroy()
40
- self?.players[nativeId] = nil
39
+ PlayerRegistry.unregister(nativeId: nativeId)
41
40
  }
42
41
  }.runOnQueue(.main)
43
- AsyncFunction("setVolume") { [weak self] (nativeId: NativeId, volume: Int) in
44
- self?.players[nativeId]?.volume = volume
42
+ AsyncFunction("setVolume") { (nativeId: NativeId, volume: Int) in
43
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.volume = volume
45
44
  }.runOnQueue(.main)
46
- AsyncFunction("unload") { [weak self] (nativeId: NativeId) in
47
- self?.players[nativeId]?.unload()
45
+ AsyncFunction("unload") { (nativeId: NativeId) in
46
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.unload()
48
47
  }.runOnQueue(.main)
49
- AsyncFunction("setPlaybackSpeed") { [weak self] (nativeId: NativeId, playbackSpeed: Float) in
50
- self?.players[nativeId]?.playbackSpeed = playbackSpeed
48
+ AsyncFunction("setPlaybackSpeed") { (nativeId: NativeId, playbackSpeed: Float) in
49
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.playbackSpeed = playbackSpeed
51
50
  }.runOnQueue(.main)
52
- AsyncFunction("setMaxSelectableBitrate") { [weak self] (nativeId: NativeId, maxSelectableBitrate: Int) in
53
- self?.players[nativeId]?.maxSelectableBitrate = UInt(maxSelectableBitrate)
51
+ AsyncFunction("setMaxSelectableBitrate") { (nativeId: NativeId, maxSelectableBitrate: Int) in
52
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.maxSelectableBitrate = UInt(maxSelectableBitrate)
54
53
  }.runOnQueue(.main)
55
- AsyncFunction("getVolume") { [weak self] (nativeId: NativeId) -> Int? in
56
- self?.players[nativeId]?.volume
54
+ AsyncFunction("getVolume") { (nativeId: NativeId) -> Int? in
55
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.volume
57
56
  }.runOnQueue(.main)
58
- AsyncFunction("currentTime") { [weak self] (nativeId: NativeId, mode: String?) -> Double? in
59
- let player = self?.players[nativeId]
57
+ AsyncFunction("currentTime") { (nativeId: NativeId, mode: String?) -> Double? in
58
+ let player = PlayerRegistry.getPlayer(nativeId: nativeId)
60
59
  if let mode {
61
60
  return player?.currentTime(RCTConvert.timeMode(mode))
62
61
  }
63
62
  return player?.currentTime
64
63
  }.runOnQueue(.main)
65
- AsyncFunction("isPlaying") { [weak self] (nativeId: NativeId) -> Bool? in
66
- self?.players[nativeId]?.isPlaying
64
+ AsyncFunction("isPlaying") { (nativeId: NativeId) -> Bool? in
65
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.isPlaying
67
66
  }.runOnQueue(.main)
68
- AsyncFunction("isPaused") { [weak self] (nativeId: NativeId) -> Bool? in
69
- self?.players[nativeId]?.isPaused
67
+ AsyncFunction("isPaused") { (nativeId: NativeId) -> Bool? in
68
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.isPaused
70
69
  }.runOnQueue(.main)
71
- AsyncFunction("duration") { [weak self] (nativeId: NativeId) -> Double? in
72
- self?.players[nativeId]?.duration
70
+ AsyncFunction("duration") { (nativeId: NativeId) -> Double? in
71
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.duration
73
72
  }.runOnQueue(.main)
74
- AsyncFunction("isMuted") { [weak self] (nativeId: NativeId) -> Bool? in
75
- self?.players[nativeId]?.isMuted
73
+ AsyncFunction("isMuted") { (nativeId: NativeId) -> Bool? in
74
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.isMuted
76
75
  }.runOnQueue(.main)
77
- AsyncFunction("getTimeShift") { [weak self] (nativeId: NativeId) -> Double? in
78
- self?.players[nativeId]?.timeShift
76
+ AsyncFunction("getTimeShift") { (nativeId: NativeId) -> Double? in
77
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.timeShift
79
78
  }.runOnQueue(.main)
80
- AsyncFunction("isLive") { [weak self] (nativeId: NativeId) -> Bool? in
81
- self?.players[nativeId]?.isLive
79
+ AsyncFunction("isLive") { (nativeId: NativeId) -> Bool? in
80
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.isLive
82
81
  }.runOnQueue(.main)
83
- AsyncFunction("getMaxTimeShift") { [weak self] (nativeId: NativeId) -> Double? in
84
- self?.players[nativeId]?.maxTimeShift
82
+ AsyncFunction("getMaxTimeShift") { (nativeId: NativeId) -> Double? in
83
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.maxTimeShift
85
84
  }.runOnQueue(.main)
86
- AsyncFunction("getPlaybackSpeed") { [weak self] (nativeId: NativeId) -> Float? in
87
- self?.players[nativeId]?.playbackSpeed
85
+ AsyncFunction("getPlaybackSpeed") { (nativeId: NativeId) -> Float? in
86
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.playbackSpeed
88
87
  }.runOnQueue(.main)
89
- AsyncFunction("isAd") { [weak self] (nativeId: NativeId) -> Bool? in
90
- self?.players[nativeId]?.isAd
88
+ AsyncFunction("isAd") { (nativeId: NativeId) -> Bool? in
89
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.isAd
91
90
  }.runOnQueue(.main)
92
- AsyncFunction("canPlayAtPlaybackSpeed") { [weak self] (nativeId: NativeId, playbackSpeed: Float) -> Bool? in
93
- self?.players[nativeId]?.canPlay(atPlaybackSpeed: playbackSpeed)
91
+ AsyncFunction("canPlayAtPlaybackSpeed") { (nativeId: NativeId, playbackSpeed: Float) -> Bool? in
92
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.canPlay(atPlaybackSpeed: playbackSpeed)
94
93
  }.runOnQueue(.main)
95
- AsyncFunction("getAudioTrack") { [weak self] (nativeId: NativeId) -> [String: Any]? in
96
- RCTConvert.audioTrackJson(self?.players[nativeId]?.audio)
94
+ AsyncFunction("getAudioTrack") { (nativeId: NativeId) -> [String: Any]? in
95
+ RCTConvert.audioTrackJson(PlayerRegistry.getPlayer(nativeId: nativeId)?.audio)
97
96
  }.runOnQueue(.main)
98
- AsyncFunction("getAvailableAudioTracks") { [weak self] (nativeId: NativeId) -> [[String: Any]] in
99
- self?.players[nativeId]?.availableAudio.compactMap { RCTConvert.audioTrackJson($0) } ?? []
97
+ AsyncFunction("getAvailableAudioTracks") { (nativeId: NativeId) -> [[String: Any]] in
98
+ PlayerRegistry.getPlayer(nativeId: nativeId)?
99
+ .availableAudio.compactMap { RCTConvert.audioTrackJson($0) } ?? []
100
100
  }.runOnQueue(.main)
101
- AsyncFunction("setAudioTrack") { [weak self] (nativeId: NativeId, trackIdentifier: String) in
102
- self?.players[nativeId]?.setAudio(trackIdentifier: trackIdentifier)
101
+ AsyncFunction("setAudioTrack") { (nativeId: NativeId, trackIdentifier: String) in
102
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.setAudio(trackIdentifier: trackIdentifier)
103
103
  }.runOnQueue(.main)
104
- AsyncFunction("getSubtitleTrack") { [weak self] (nativeId: NativeId) -> [String: Any]? in
105
- RCTConvert.subtitleTrackJson(self?.players[nativeId]?.subtitle)
104
+ AsyncFunction("getSubtitleTrack") { (nativeId: NativeId) -> [String: Any]? in
105
+ RCTConvert.subtitleTrackJson(PlayerRegistry.getPlayer(nativeId: nativeId)?.subtitle)
106
106
  }.runOnQueue(.main)
107
- AsyncFunction("getAvailableSubtitles") { [weak self] (nativeId: NativeId) -> [[String: Any]] in
108
- self?.players[nativeId]?.availableSubtitles.compactMap { RCTConvert.subtitleTrackJson($0) } ?? []
107
+ AsyncFunction("getAvailableSubtitles") { (nativeId: NativeId) -> [[String: Any]] in
108
+ PlayerRegistry.getPlayer(nativeId: nativeId)?
109
+ .availableSubtitles.compactMap { RCTConvert.subtitleTrackJson($0) } ?? []
109
110
  }.runOnQueue(.main)
110
- AsyncFunction("setSubtitleTrack") { [weak self] (nativeId: NativeId, trackIdentifier: String?) in
111
- self?.players[nativeId]?.setSubtitle(trackIdentifier: trackIdentifier)
111
+ AsyncFunction("setSubtitleTrack") { (nativeId: NativeId, trackIdentifier: String?) in
112
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.setSubtitle(trackIdentifier: trackIdentifier)
112
113
  }.runOnQueue(.main)
113
114
 
114
- AsyncFunction("getVideoQuality") { [weak self] (nativeId: NativeId) -> [String: Any]? in
115
- RCTConvert.toJson(videoQuality: self?.players[nativeId]?.videoQuality)
115
+ AsyncFunction("getVideoQuality") { (nativeId: NativeId) -> [String: Any]? in
116
+ RCTConvert.toJson(videoQuality: PlayerRegistry.getPlayer(nativeId: nativeId)?.videoQuality)
116
117
  }.runOnQueue(.main)
117
- AsyncFunction("getAvailableVideoQualities") { [weak self] (nativeId: NativeId) -> [[String: Any]] in
118
- self?.players[nativeId]?.availableVideoQualities.compactMap { RCTConvert.toJson(videoQuality: $0) } ?? []
118
+ AsyncFunction("getAvailableVideoQualities") { (nativeId: NativeId) -> [[String: Any]] in
119
+ PlayerRegistry.getPlayer(nativeId: nativeId)?
120
+ .availableVideoQualities.compactMap { RCTConvert.toJson(videoQuality: $0) } ?? []
119
121
  }.runOnQueue(.main)
120
- AsyncFunction("getThumbnail") { [weak self] (nativeId: NativeId, time: Double) -> [String: Any]? in
121
- RCTConvert.toJson(thumbnail: self?.players[nativeId]?.thumbnail(forTime: time))
122
+ AsyncFunction("getThumbnail") { (nativeId: NativeId, time: Double) -> [String: Any]? in
123
+ RCTConvert.toJson(thumbnail: PlayerRegistry.getPlayer(nativeId: nativeId)?.thumbnail(forTime: time))
122
124
  }.runOnQueue(.main)
123
125
  AsyncFunction("loadOfflineContent") { [weak self] (nativeId: NativeId, bridgeId: String, options: [String: Any]?) in // swiftlint:disable:this line_length
124
126
  #if os(iOS)
125
- guard let player = self?.players[nativeId],
127
+ guard let player = PlayerRegistry.getPlayer(nativeId: nativeId),
126
128
  let offlineModule = self?.appContext?.moduleRegistry.get(OfflineModule.self),
127
129
  let offlineContentManagerBridge = offlineModule.retrieve(bridgeId) else { return }
128
130
  let optionsDictionary = options ?? [:]
@@ -134,55 +136,57 @@ public class PlayerModule: Module {
134
136
  player.load(sourceConfig: offlineSourceConfig)
135
137
  #endif
136
138
  }.runOnQueue(.main)
137
- AsyncFunction("scheduleAd") { [weak self] (nativeId: NativeId, adItemJson: [String: Any]) in
139
+ AsyncFunction("scheduleAd") { (nativeId: NativeId, adItemJson: [String: Any]) in
138
140
  guard let adItem = RCTConvert.adItem(adItemJson) else { return }
139
- self?.players[nativeId]?.scheduleAd(adItem: adItem)
141
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.scheduleAd(adItem: adItem)
140
142
  }.runOnQueue(.main)
141
- AsyncFunction("isAirPlayActive") { [weak self] (nativeId: NativeId) -> Bool? in
143
+ AsyncFunction("isAirPlayActive") { (nativeId: NativeId) -> Bool? in
142
144
  #if os(iOS)
143
- return self?.players[nativeId]?.isAirPlayActive
145
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.isAirPlayActive
144
146
  #else
145
- return nil
147
+ nil
146
148
  #endif
147
149
  }.runOnQueue(.main)
148
- AsyncFunction("isAirPlayAvailable") { [weak self] (nativeId: NativeId) -> Bool? in
150
+ AsyncFunction("isAirPlayAvailable") { (nativeId: NativeId) -> Bool? in
149
151
  #if os(iOS)
150
- return self?.players[nativeId]?.allowsAirPlay
152
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.allowsAirPlay
151
153
  #else
152
- return nil
154
+ nil
153
155
  #endif
154
156
  }.runOnQueue(.main)
155
- AsyncFunction("isCastAvailable") { [weak self] (nativeId: NativeId) -> Bool? in
156
- self?.players[nativeId]?.isCastAvailable
157
+ AsyncFunction("isCastAvailable") { (nativeId: NativeId) -> Bool? in
158
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.isCastAvailable
157
159
  }.runOnQueue(.main)
158
- AsyncFunction("isCasting") { [weak self] (nativeId: NativeId) -> Bool? in
159
- self?.players[nativeId]?.isCasting
160
+ AsyncFunction("isCasting") { (nativeId: NativeId) -> Bool? in
161
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.isCasting
160
162
  }.runOnQueue(.main)
161
- AsyncFunction("castVideo") { [weak self] (nativeId: NativeId) in
162
- self?.players[nativeId]?.castVideo()
163
+ AsyncFunction("castVideo") { (nativeId: NativeId) in
164
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.castVideo()
163
165
  }.runOnQueue(.main)
164
- AsyncFunction("castStop") { [weak self] (nativeId: NativeId) in
165
- self?.players[nativeId]?.castStop()
166
+ AsyncFunction("castStop") { (nativeId: NativeId) in
167
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.castStop()
166
168
  }.runOnQueue(.main)
167
- AsyncFunction("skipAd") { [weak self] (nativeId: NativeId) in
168
- self?.players[nativeId]?.skipAd()
169
+ AsyncFunction("skipAd") { (nativeId: NativeId) in
170
+ PlayerRegistry.getPlayer(nativeId: nativeId)?.skipAd()
169
171
  }.runOnQueue(.main)
170
172
  AsyncFunction(
171
173
  "initializeWithConfig"
172
174
  ) { [weak self] (nativeId: NativeId, config: [String: Any]?, networkNativeId: NativeId?, _: String?) in // swiftlint:disable:this line_length
173
- guard self?.players[nativeId] == nil, let playerConfig = RCTConvert.playerConfig(config) else { return }
175
+ guard !PlayerRegistry.hasPlayer(nativeId: nativeId),
176
+ let playerConfig = RCTConvert.playerConfig(config) else { return }
174
177
  #if os(iOS)
175
178
  self?.setupRemoteControlConfig(playerConfig.remoteControlConfig)
176
179
  #endif
177
180
  if let networkNativeId, let networkConfig = self?.setupNetworkConfig(nativeId: networkNativeId) {
178
181
  playerConfig.networkConfig = networkConfig
179
182
  }
180
- self?.players[nativeId] = PlayerFactory.create(playerConfig: playerConfig)
183
+ let player = PlayerFactory.create(playerConfig: playerConfig)
184
+ PlayerRegistry.register(player: player, nativeId: nativeId)
181
185
  }.runOnQueue(.main)
182
186
  AsyncFunction(
183
187
  "initializeWithAnalyticsConfig"
184
188
  ) { [weak self] (nativeId: NativeId, analyticsConfig: [String: Any]?, config: [String: Any]?, networkNativeId: NativeId?, _: String?) in // swiftlint:disable:this line_length
185
- guard self?.players[nativeId] == nil,
189
+ guard !PlayerRegistry.hasPlayer(nativeId: nativeId),
186
190
  let playerConfig = RCTConvert.playerConfig(config),
187
191
  let analyticsConfig = RCTConvert.analyticsConfig(analyticsConfig) else { return } // swiftlint:disable:this line_length
188
192
  #if os(iOS)
@@ -192,14 +196,15 @@ public class PlayerModule: Module {
192
196
  playerConfig.networkConfig = networkConfig
193
197
  }
194
198
  let defaultMetadata = RCTConvert.analyticsDefaultMetadataFromAnalyticsConfig(analyticsConfig)
195
- self?.players[nativeId] = PlayerFactory.create(
199
+ let player = PlayerFactory.create(
196
200
  playerConfig: playerConfig,
197
201
  analyticsConfig: analyticsConfig,
198
202
  defaultMetadata: defaultMetadata ?? DefaultMetadata()
199
203
  )
204
+ PlayerRegistry.register(player: player, nativeId: nativeId)
200
205
  }.runOnQueue(.main)
201
206
  AsyncFunction("loadSource") { [weak self] (nativeId: NativeId, sourceNativeId: NativeId) in
202
- guard let player = self?.players[nativeId],
207
+ guard let player = PlayerRegistry.getPlayer(nativeId: nativeId),
203
208
  let sourceModule = self?.appContext?.moduleRegistry.get(SourceModule.self), // swiftlint:disable:this line_length
204
209
  let source = sourceModule.retrieve(sourceNativeId) else { return }
205
210
  player.load(source: source)
@@ -209,7 +214,7 @@ public class PlayerModule: Module {
209
214
  /// This needs to stay stable to maintain compatibility for cross-module access..
210
215
  @objc
211
216
  public func retrieve(_ nativeId: NativeId) -> Player? {
212
- players[nativeId]
217
+ PlayerRegistry.getPlayer(nativeId: nativeId)
213
218
  }
214
219
 
215
220
  private func setupRemoteControlConfig(_ remoteControlConfig: RemoteControlConfig) {
@@ -0,0 +1,88 @@
1
+ import BitmovinPlayer
2
+ import ExpoModulesCore
3
+
4
+ /**
5
+ * Global registry for Player instances that allows static access from anywhere in native code
6
+ * without requiring access to the PlayerModule instance or Expo runtime.
7
+ */
8
+ public class PlayerRegistry {
9
+ private static let shared = PlayerRegistry()
10
+ private var players: Registry<Player> = [:]
11
+ private let queue = DispatchQueue(label: "PlayerRegistry", attributes: .concurrent)
12
+
13
+ private init() {}
14
+
15
+ /**
16
+ * Register a player instance with the given native ID.
17
+ */
18
+ public static func register(player: Player, nativeId: NativeId) {
19
+ shared.queue.async(flags: .barrier) {
20
+ shared.players[nativeId] = player
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Unregister a player instance with the given native ID.
26
+ */
27
+ public static func unregister(nativeId: NativeId) {
28
+ shared.queue.async(flags: .barrier) {
29
+ shared.players[nativeId] = nil
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Get a player instance by native ID.
35
+ * Returns nil if no player is registered with the given ID.
36
+ */
37
+ public static func getPlayer(nativeId: NativeId) -> Player? {
38
+ shared.queue.sync {
39
+ shared.players[nativeId]
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Get all registered player instances.
45
+ */
46
+ public static func getAllPlayers() -> [Player] {
47
+ shared.queue.sync {
48
+ Array(shared.players.values)
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Get all registered native IDs.
54
+ */
55
+ public static func getAllNativeIds() -> [NativeId] {
56
+ shared.queue.sync {
57
+ Array(shared.players.keys)
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Check if a player is registered with the given native ID.
63
+ */
64
+ public static func hasPlayer(nativeId: NativeId) -> Bool {
65
+ shared.queue.sync {
66
+ shared.players[nativeId] != nil
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Clear all registered players.
72
+ * Note: This does not destroy the players, just removes them from the registry.
73
+ */
74
+ public static func clear() {
75
+ shared.queue.async(flags: .barrier) {
76
+ shared.players.removeAll()
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Get the count of registered players.
82
+ */
83
+ public static func count() -> Int {
84
+ shared.queue.sync {
85
+ shared.players.count
86
+ }
87
+ }
88
+ }
@@ -558,6 +558,7 @@ private extension RNPlayerView {
558
558
  return nil
559
559
  }
560
560
 
561
+ #if os(iOS)
561
562
  func attachCustomMessageHandlerBridge(
562
563
  id customMessageHandlerBridgeId: NativeId,
563
564
  to bitmovinUserInterfaceConfig: BitmovinUserInterfaceConfig
@@ -573,6 +574,7 @@ private extension RNPlayerView {
573
574
 
574
575
  bitmovinUserInterfaceConfig.customMessageHandler = customMessageHandlerBridge.customMessageHandler
575
576
  }
577
+ #endif
576
578
 
577
579
  @MainActor
578
580
  func maybeEmitPictureInPictureAvailabilityEvent(previousState: Bool) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitmovin-player-react-native",
3
- "version": "1.0.0-alpha.0",
3
+ "version": "1.0.0-alpha.2",
4
4
  "description": "Official React Native bindings for Bitmovin's mobile Player SDKs.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const config_plugins_1 = require("expo/config-plugins");
4
+ const isTV = !!process.env.EXPO_TV;
4
5
  const withBitmovinIosConfig = (config, { playerLicenseKey, features }) => {
5
6
  const offlineFeatureConfig = typeof features.offline === 'object'
6
7
  ? features.offline
@@ -25,29 +26,33 @@ const withBitmovinIosConfig = (config, { playerLicenseKey, features }) => {
25
26
  backgroundModes.add('audio');
26
27
  config.modResults['UIBackgroundModes'] = Array.from(backgroundModes);
27
28
  }
28
- if (offlineFeatureConfig?.ios?.isEnabled) {
29
- config.modResults['BitmovinPlayerOfflineSupportEnabled'] = true;
30
- }
31
- if (googleCastIosConfig) {
32
- const appId = googleCastIosConfig.appId || 'FFE417E5';
33
- const localNetworkUsageDescription = googleCastIosConfig.localNetworkUsageDescription ||
34
- '${PRODUCT_NAME} uses the local network to discover Cast-enabled devices on your WiFi network.';
35
- config.modResults['NSBonjourServices'] = [
36
- '_googlecast._tcp',
37
- `_${appId}._googlecast._tcp`,
38
- ];
39
- config.modResults['NSLocalNetworkUsageDescription'] =
40
- localNetworkUsageDescription;
41
- }
42
- return config;
43
- });
44
- config = (0, config_plugins_1.withPodfileProperties)(config, (config) => {
45
- if (googleCastIosConfig) {
46
- config.modResults['BITMOVIN_GOOGLE_CAST_SDK_VERSION'] =
47
- googleCastIosConfig.version;
29
+ if (!isTV) {
30
+ if (offlineFeatureConfig?.ios?.isEnabled) {
31
+ config.modResults['BitmovinPlayerOfflineSupportEnabled'] = true;
32
+ }
33
+ if (googleCastIosConfig) {
34
+ const appId = googleCastIosConfig.appId || 'FFE417E5';
35
+ const localNetworkUsageDescription = googleCastIosConfig.localNetworkUsageDescription ||
36
+ '${PRODUCT_NAME} uses the local network to discover Cast-enabled devices on your WiFi network.';
37
+ config.modResults['NSBonjourServices'] = [
38
+ '_googlecast._tcp',
39
+ `_${appId}._googlecast._tcp`,
40
+ ];
41
+ config.modResults['NSLocalNetworkUsageDescription'] =
42
+ localNetworkUsageDescription;
43
+ }
48
44
  }
49
45
  return config;
50
46
  });
47
+ if (!isTV) {
48
+ config = (0, config_plugins_1.withPodfileProperties)(config, (config) => {
49
+ if (googleCastIosConfig) {
50
+ config.modResults['BITMOVIN_GOOGLE_CAST_SDK_VERSION'] =
51
+ googleCastIosConfig.version;
52
+ }
53
+ return config;
54
+ });
55
+ }
51
56
  return config;
52
57
  };
53
58
  exports.default = withBitmovinIosConfig;
@@ -5,6 +5,8 @@ import {
5
5
  } from 'expo/config-plugins';
6
6
  import FeatureFlags from './FeatureFlags';
7
7
 
8
+ const isTV = !!process.env.EXPO_TV;
9
+
8
10
  const withBitmovinIosConfig: ConfigPlugin<{
9
11
  playerLicenseKey: string;
10
12
  features: FeatureFlags;
@@ -38,32 +40,36 @@ const withBitmovinIosConfig: ConfigPlugin<{
38
40
  backgroundModes.add('audio');
39
41
  config.modResults['UIBackgroundModes'] = Array.from(backgroundModes);
40
42
  }
41
- if (offlineFeatureConfig?.ios?.isEnabled) {
42
- config.modResults['BitmovinPlayerOfflineSupportEnabled'] = true;
43
- }
44
- if (googleCastIosConfig) {
45
- const appId = googleCastIosConfig.appId || 'FFE417E5';
46
- const localNetworkUsageDescription =
47
- googleCastIosConfig.localNetworkUsageDescription ||
48
- '${PRODUCT_NAME} uses the local network to discover Cast-enabled devices on your WiFi network.';
43
+ if (!isTV) {
44
+ if (offlineFeatureConfig?.ios?.isEnabled) {
45
+ config.modResults['BitmovinPlayerOfflineSupportEnabled'] = true;
46
+ }
47
+ if (googleCastIosConfig) {
48
+ const appId = googleCastIosConfig.appId || 'FFE417E5';
49
+ const localNetworkUsageDescription =
50
+ googleCastIosConfig.localNetworkUsageDescription ||
51
+ '${PRODUCT_NAME} uses the local network to discover Cast-enabled devices on your WiFi network.';
49
52
 
50
- config.modResults['NSBonjourServices'] = [
51
- '_googlecast._tcp',
52
- `_${appId}._googlecast._tcp`,
53
- ];
54
- config.modResults['NSLocalNetworkUsageDescription'] =
55
- localNetworkUsageDescription;
53
+ config.modResults['NSBonjourServices'] = [
54
+ '_googlecast._tcp',
55
+ `_${appId}._googlecast._tcp`,
56
+ ];
57
+ config.modResults['NSLocalNetworkUsageDescription'] =
58
+ localNetworkUsageDescription;
59
+ }
56
60
  }
57
61
  return config;
58
62
  });
59
63
 
60
- config = withPodfileProperties(config, (config) => {
61
- if (googleCastIosConfig) {
62
- config.modResults['BITMOVIN_GOOGLE_CAST_SDK_VERSION'] =
63
- googleCastIosConfig.version;
64
- }
65
- return config;
66
- });
64
+ if (!isTV) {
65
+ config = withPodfileProperties(config, (config) => {
66
+ if (googleCastIosConfig) {
67
+ config.modResults['BITMOVIN_GOOGLE_CAST_SDK_VERSION'] =
68
+ googleCastIosConfig.version;
69
+ }
70
+ return config;
71
+ });
72
+ }
67
73
 
68
74
  return config;
69
75
  };