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.
- package/README.md +4 -4
- package/android/src/main/java/com/bitmovin/player/reactnative/BufferModule.kt +1 -4
- package/android/src/main/java/com/bitmovin/player/reactnative/PlayerModule.kt +47 -52
- package/android/src/main/java/com/bitmovin/player/reactnative/PlayerRegistry.kt +78 -0
- package/build/components/PlayerView/index.d.ts +1 -1
- package/build/components/PlayerView/index.d.ts.map +1 -1
- package/build/components/PlayerView/index.js +4 -1
- package/build/components/PlayerView/index.js.map +1 -1
- package/ios/AppLifecycleDelegate.swift +4 -1
- package/ios/OfflineModule.swift +3 -7
- package/ios/PlayerModule.swift +99 -94
- package/ios/PlayerRegistry.swift +88 -0
- package/ios/RNPlayerView.swift +2 -0
- package/package.json +1 -1
- package/plugin/build/withBitmovinIosConfig.js +25 -20
- package/plugin/src/withBitmovinIosConfig.ts +27 -21
- package/src/components/PlayerView/index.tsx +84 -82
package/ios/PlayerModule.swift
CHANGED
|
@@ -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 {
|
|
16
|
-
|
|
13
|
+
DispatchQueue.main.async {
|
|
14
|
+
PlayerRegistry.getAllPlayers().forEach { $0.destroy() }
|
|
15
|
+
PlayerRegistry.clear()
|
|
17
16
|
}
|
|
18
17
|
}
|
|
19
|
-
AsyncFunction("play") {
|
|
20
|
-
|
|
18
|
+
AsyncFunction("play") { (nativeId: NativeId) in
|
|
19
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.play()
|
|
21
20
|
}.runOnQueue(.main)
|
|
22
|
-
AsyncFunction("pause") {
|
|
23
|
-
|
|
21
|
+
AsyncFunction("pause") { (nativeId: NativeId) in
|
|
22
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.pause()
|
|
24
23
|
}.runOnQueue(.main)
|
|
25
|
-
AsyncFunction("mute") {
|
|
26
|
-
|
|
24
|
+
AsyncFunction("mute") { (nativeId: NativeId) in
|
|
25
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.mute()
|
|
27
26
|
}.runOnQueue(.main)
|
|
28
|
-
AsyncFunction("unmute") {
|
|
29
|
-
|
|
27
|
+
AsyncFunction("unmute") { (nativeId: NativeId) in
|
|
28
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.unmute()
|
|
30
29
|
}.runOnQueue(.main)
|
|
31
|
-
AsyncFunction("seek") {
|
|
32
|
-
|
|
30
|
+
AsyncFunction("seek") { (nativeId: NativeId, time: Double) in
|
|
31
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.seek(time: time)
|
|
33
32
|
}.runOnQueue(.main)
|
|
34
|
-
AsyncFunction("timeShift") {
|
|
35
|
-
|
|
33
|
+
AsyncFunction("timeShift") { (nativeId: NativeId, offset: Double) in
|
|
34
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.timeShift = offset
|
|
36
35
|
}.runOnQueue(.main)
|
|
37
|
-
AsyncFunction("destroy") {
|
|
38
|
-
if let player =
|
|
36
|
+
AsyncFunction("destroy") { (nativeId: NativeId) in
|
|
37
|
+
if let player = PlayerRegistry.getPlayer(nativeId: nativeId) {
|
|
39
38
|
player.destroy()
|
|
40
|
-
|
|
39
|
+
PlayerRegistry.unregister(nativeId: nativeId)
|
|
41
40
|
}
|
|
42
41
|
}.runOnQueue(.main)
|
|
43
|
-
AsyncFunction("setVolume") {
|
|
44
|
-
|
|
42
|
+
AsyncFunction("setVolume") { (nativeId: NativeId, volume: Int) in
|
|
43
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.volume = volume
|
|
45
44
|
}.runOnQueue(.main)
|
|
46
|
-
AsyncFunction("unload") {
|
|
47
|
-
|
|
45
|
+
AsyncFunction("unload") { (nativeId: NativeId) in
|
|
46
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.unload()
|
|
48
47
|
}.runOnQueue(.main)
|
|
49
|
-
AsyncFunction("setPlaybackSpeed") {
|
|
50
|
-
|
|
48
|
+
AsyncFunction("setPlaybackSpeed") { (nativeId: NativeId, playbackSpeed: Float) in
|
|
49
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.playbackSpeed = playbackSpeed
|
|
51
50
|
}.runOnQueue(.main)
|
|
52
|
-
AsyncFunction("setMaxSelectableBitrate") {
|
|
53
|
-
|
|
51
|
+
AsyncFunction("setMaxSelectableBitrate") { (nativeId: NativeId, maxSelectableBitrate: Int) in
|
|
52
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.maxSelectableBitrate = UInt(maxSelectableBitrate)
|
|
54
53
|
}.runOnQueue(.main)
|
|
55
|
-
AsyncFunction("getVolume") {
|
|
56
|
-
|
|
54
|
+
AsyncFunction("getVolume") { (nativeId: NativeId) -> Int? in
|
|
55
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.volume
|
|
57
56
|
}.runOnQueue(.main)
|
|
58
|
-
AsyncFunction("currentTime") {
|
|
59
|
-
let player =
|
|
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") {
|
|
66
|
-
|
|
64
|
+
AsyncFunction("isPlaying") { (nativeId: NativeId) -> Bool? in
|
|
65
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.isPlaying
|
|
67
66
|
}.runOnQueue(.main)
|
|
68
|
-
AsyncFunction("isPaused") {
|
|
69
|
-
|
|
67
|
+
AsyncFunction("isPaused") { (nativeId: NativeId) -> Bool? in
|
|
68
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.isPaused
|
|
70
69
|
}.runOnQueue(.main)
|
|
71
|
-
AsyncFunction("duration") {
|
|
72
|
-
|
|
70
|
+
AsyncFunction("duration") { (nativeId: NativeId) -> Double? in
|
|
71
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.duration
|
|
73
72
|
}.runOnQueue(.main)
|
|
74
|
-
AsyncFunction("isMuted") {
|
|
75
|
-
|
|
73
|
+
AsyncFunction("isMuted") { (nativeId: NativeId) -> Bool? in
|
|
74
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.isMuted
|
|
76
75
|
}.runOnQueue(.main)
|
|
77
|
-
AsyncFunction("getTimeShift") {
|
|
78
|
-
|
|
76
|
+
AsyncFunction("getTimeShift") { (nativeId: NativeId) -> Double? in
|
|
77
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.timeShift
|
|
79
78
|
}.runOnQueue(.main)
|
|
80
|
-
AsyncFunction("isLive") {
|
|
81
|
-
|
|
79
|
+
AsyncFunction("isLive") { (nativeId: NativeId) -> Bool? in
|
|
80
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.isLive
|
|
82
81
|
}.runOnQueue(.main)
|
|
83
|
-
AsyncFunction("getMaxTimeShift") {
|
|
84
|
-
|
|
82
|
+
AsyncFunction("getMaxTimeShift") { (nativeId: NativeId) -> Double? in
|
|
83
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.maxTimeShift
|
|
85
84
|
}.runOnQueue(.main)
|
|
86
|
-
AsyncFunction("getPlaybackSpeed") {
|
|
87
|
-
|
|
85
|
+
AsyncFunction("getPlaybackSpeed") { (nativeId: NativeId) -> Float? in
|
|
86
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.playbackSpeed
|
|
88
87
|
}.runOnQueue(.main)
|
|
89
|
-
AsyncFunction("isAd") {
|
|
90
|
-
|
|
88
|
+
AsyncFunction("isAd") { (nativeId: NativeId) -> Bool? in
|
|
89
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.isAd
|
|
91
90
|
}.runOnQueue(.main)
|
|
92
|
-
AsyncFunction("canPlayAtPlaybackSpeed") {
|
|
93
|
-
|
|
91
|
+
AsyncFunction("canPlayAtPlaybackSpeed") { (nativeId: NativeId, playbackSpeed: Float) -> Bool? in
|
|
92
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.canPlay(atPlaybackSpeed: playbackSpeed)
|
|
94
93
|
}.runOnQueue(.main)
|
|
95
|
-
AsyncFunction("getAudioTrack") {
|
|
96
|
-
RCTConvert.audioTrackJson(
|
|
94
|
+
AsyncFunction("getAudioTrack") { (nativeId: NativeId) -> [String: Any]? in
|
|
95
|
+
RCTConvert.audioTrackJson(PlayerRegistry.getPlayer(nativeId: nativeId)?.audio)
|
|
97
96
|
}.runOnQueue(.main)
|
|
98
|
-
AsyncFunction("getAvailableAudioTracks") {
|
|
99
|
-
|
|
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") {
|
|
102
|
-
|
|
101
|
+
AsyncFunction("setAudioTrack") { (nativeId: NativeId, trackIdentifier: String) in
|
|
102
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.setAudio(trackIdentifier: trackIdentifier)
|
|
103
103
|
}.runOnQueue(.main)
|
|
104
|
-
AsyncFunction("getSubtitleTrack") {
|
|
105
|
-
RCTConvert.subtitleTrackJson(
|
|
104
|
+
AsyncFunction("getSubtitleTrack") { (nativeId: NativeId) -> [String: Any]? in
|
|
105
|
+
RCTConvert.subtitleTrackJson(PlayerRegistry.getPlayer(nativeId: nativeId)?.subtitle)
|
|
106
106
|
}.runOnQueue(.main)
|
|
107
|
-
AsyncFunction("getAvailableSubtitles") {
|
|
108
|
-
|
|
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") {
|
|
111
|
-
|
|
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") {
|
|
115
|
-
RCTConvert.toJson(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") {
|
|
118
|
-
|
|
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") {
|
|
121
|
-
RCTConvert.toJson(thumbnail:
|
|
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 =
|
|
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") {
|
|
139
|
+
AsyncFunction("scheduleAd") { (nativeId: NativeId, adItemJson: [String: Any]) in
|
|
138
140
|
guard let adItem = RCTConvert.adItem(adItemJson) else { return }
|
|
139
|
-
|
|
141
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.scheduleAd(adItem: adItem)
|
|
140
142
|
}.runOnQueue(.main)
|
|
141
|
-
AsyncFunction("isAirPlayActive") {
|
|
143
|
+
AsyncFunction("isAirPlayActive") { (nativeId: NativeId) -> Bool? in
|
|
142
144
|
#if os(iOS)
|
|
143
|
-
|
|
145
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.isAirPlayActive
|
|
144
146
|
#else
|
|
145
|
-
|
|
147
|
+
nil
|
|
146
148
|
#endif
|
|
147
149
|
}.runOnQueue(.main)
|
|
148
|
-
AsyncFunction("isAirPlayAvailable") {
|
|
150
|
+
AsyncFunction("isAirPlayAvailable") { (nativeId: NativeId) -> Bool? in
|
|
149
151
|
#if os(iOS)
|
|
150
|
-
|
|
152
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.allowsAirPlay
|
|
151
153
|
#else
|
|
152
|
-
|
|
154
|
+
nil
|
|
153
155
|
#endif
|
|
154
156
|
}.runOnQueue(.main)
|
|
155
|
-
AsyncFunction("isCastAvailable") {
|
|
156
|
-
|
|
157
|
+
AsyncFunction("isCastAvailable") { (nativeId: NativeId) -> Bool? in
|
|
158
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.isCastAvailable
|
|
157
159
|
}.runOnQueue(.main)
|
|
158
|
-
AsyncFunction("isCasting") {
|
|
159
|
-
|
|
160
|
+
AsyncFunction("isCasting") { (nativeId: NativeId) -> Bool? in
|
|
161
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.isCasting
|
|
160
162
|
}.runOnQueue(.main)
|
|
161
|
-
AsyncFunction("castVideo") {
|
|
162
|
-
|
|
163
|
+
AsyncFunction("castVideo") { (nativeId: NativeId) in
|
|
164
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.castVideo()
|
|
163
165
|
}.runOnQueue(.main)
|
|
164
|
-
AsyncFunction("castStop") {
|
|
165
|
-
|
|
166
|
+
AsyncFunction("castStop") { (nativeId: NativeId) in
|
|
167
|
+
PlayerRegistry.getPlayer(nativeId: nativeId)?.castStop()
|
|
166
168
|
}.runOnQueue(.main)
|
|
167
|
-
AsyncFunction("skipAd") {
|
|
168
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
+
}
|
package/ios/RNPlayerView.swift
CHANGED
|
@@ -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,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 (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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 (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
};
|