react-native-theoplayer 1.8.0 → 1.8.1

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.
Files changed (27) hide show
  1. package/android/src/main/java/com/theoplayer/ReactTHEOplayerView.kt +1 -0
  2. package/ios/{THEOplayerRCTViewMainEventHandler.swift → THEOplayerRCTMainEventHandler.swift} +1 -1
  3. package/ios/{THEOplayerRCTViewMediaTrackEventHandler.swift → THEOplayerRCTMediaTrackEventHandler.swift} +2 -2
  4. package/ios/THEOplayerRCTSourceDescriptionBuilder.swift +19 -114
  5. package/ios/{THEOplayerRCTViewTextTrackEventHandler.swift → THEOplayerRCTTextTrackEventHandler.swift} +2 -2
  6. package/ios/THEOplayerRCTView.swift +33 -133
  7. package/ios/{THEOplayerRCTAdAggregator.swift → ads/THEOplayerRCTAdAggregator.swift} +1 -1
  8. package/ios/ads/THEOplayerRCTAdsAPI+DAI.swift +108 -0
  9. package/ios/{THEOplayerRCTAdsAPI.swift → ads/THEOplayerRCTAdsAPI.swift} +6 -96
  10. package/ios/{THEOplayerRCTViewAdEventHandler.swift → ads/THEOplayerRCTAdsEventHandler.swift} +3 -3
  11. package/ios/ads/THEOplayerRCTSourceDescriptionBuilder+Ads.swift +130 -0
  12. package/ios/ads/THEOplayerRCTView+Ads.swift +15 -0
  13. package/ios/ads/THEOplayerRCTView+AdsConfig.swift +82 -0
  14. package/ios/casting/THEOplayerRCTCastAPI+Airplay.swift +97 -0
  15. package/ios/casting/THEOplayerRCTCastAPI+Chromecast.swift +132 -0
  16. package/ios/casting/THEOplayerRCTCastAPI.swift +53 -0
  17. package/ios/{THEOplayerRCTViewCastEventHandler.swift → casting/THEOplayerRCTCastEventHandler.swift} +1 -1
  18. package/ios/casting/THEOplayerRCTView+CastConfig.swift +47 -0
  19. package/ios/casting/THEOplayerRCTView+Casting.swift +17 -0
  20. package/ios/{THEOplayerRCTContentProtectionAPI.swift → contentprotection/THEOplayerRCTContentProtectionAPI.swift} +0 -0
  21. package/ios/{THEOplayerRCTContentProtectionAggregator.swift → contentprotection/THEOplayerRCTContentProtectionAggregator.swift} +0 -0
  22. package/ios/{THEOplayerRCTProxyContentProtectionIntegration.swift → contentprotection/THEOplayerRCTProxyContentProtectionIntegration.swift} +0 -0
  23. package/ios/{THEOplayerRCTProxyContentProtectionIntegrationFactory.swift → contentprotection/THEOplayerRCTProxyContentProtectionIntegrationFactory.swift} +0 -0
  24. package/ios/custom/react-native-theoplayer_custom.podspec +6 -6
  25. package/package.json +1 -1
  26. package/react-native-theoplayer.podspec +1 -1
  27. package/ios/THEOplayerRCTCastAPI.swift +0 -275
@@ -245,6 +245,7 @@ class ReactTHEOplayerView(private val reactContext: ThemedReactContext) :
245
245
  if (BuildConfig.LOG_VIEW_EVENTS) {
246
246
  Log.d(TAG, "cleanUpResources")
247
247
  }
248
+ setFullscreen(false)
248
249
  releasePlayer()
249
250
  }
250
251
 
@@ -3,7 +3,7 @@
3
3
  import Foundation
4
4
  import THEOplayerSDK
5
5
 
6
- class THEOplayerRCTViewMainEventHandler {
6
+ class THEOplayerRCTMainEventHandler {
7
7
  // MARK: Members
8
8
  private weak var player: THEOplayer?
9
9
  private var currentPresentationMode = THEOplayerSDK.PresentationMode.inline // TheoPlayer's initial presentationMode
@@ -1,9 +1,9 @@
1
- // THEOplayerRCTViewMediaTrackEventHandler.swift
1
+ // THEOplayerRCTMediaTrackEventHandler.swift
2
2
 
3
3
  import Foundation
4
4
  import THEOplayerSDK
5
5
 
6
- class THEOplayerRCTViewMediaTrackEventHandler {
6
+ class THEOplayerRCTMediaTrackEventHandler {
7
7
  // MARK: Members
8
8
  private weak var player: THEOplayer?
9
9
 
@@ -7,7 +7,6 @@ import UIKit
7
7
  let SD_PROP_SOURCES: String = "sources"
8
8
  let SD_PROP_POSTER: String = "poster"
9
9
  let SD_PROP_TEXTTRACKS: String = "textTracks"
10
- let SD_PROP_ADS: String = "ads"
11
10
  let SD_PROP_METADATA: String = "metadata"
12
11
  let SD_PROP_SRC: String = "src"
13
12
  let SD_PROP_TYPE: String = "type"
@@ -115,38 +114,8 @@ class THEOplayerRCTSourceDescriptionBuilder {
115
114
  }
116
115
 
117
116
  // 4. extract Google IMA "ads"
118
- var adsDescriptions: [AdDescription]?
119
-
120
- #if ADS && GOOGLE_IMA
121
- if let ads = sourceData[SD_PROP_ADS] {
122
- adsDescriptions = []
123
- // case: array of ads objects
124
- if let adsDataArray = ads as? [[String:Any]] {
125
- for adsData in adsDataArray {
126
- if let adDescription = THEOplayerRCTSourceDescriptionBuilder.buildAdDescription(adsData) {
127
- adsDescriptions?.append(adDescription)
128
- } else {
129
- if DEBUG_SOURCE_DESCRIPTION_BUIDER {
130
- print("[NATIVE] Could not create THEOplayer GoogleImaAdDescription from adsData array")
131
- }
132
- return nil
133
- }
134
- }
135
- }
136
- // case: single ads object
137
- else if let adsData = ads as? [String:Any] {
138
- if let adDescription = THEOplayerRCTSourceDescriptionBuilder.buildAdDescription(adsData) {
139
- adsDescriptions?.append(adDescription)
140
- } else {
141
- if DEBUG_SOURCE_DESCRIPTION_BUIDER {
142
- print("[NATIVE] Could not create THEOplayer GoogleImaAdDescription from adsData")
143
- }
144
- return nil
145
- }
146
- }
147
- }
148
- #endif
149
-
117
+ let adsDescriptions: [AdDescription]? = self.buildAdDescriptions(sourceData) // Ads Extension
118
+
150
119
  // 5. extract metadata
151
120
  var metadataDescription: MetadataDescription?
152
121
  if let metadataData = sourceData[SD_PROP_METADATA] as? [String:Any] {
@@ -168,72 +137,35 @@ class THEOplayerRCTSourceDescriptionBuilder {
168
137
  - returns: a THEOplayer TypedSource. In case of SSAI we support GoogleDAITypedSource with GoogleDAIVodConfiguration or GoogleDAILiveConfiguration
169
138
  */
170
139
  private static func buildTypedSource(_ typedSourceData: [String:Any]) -> TypedSource? {
140
+ let contentProtection = extractDrmConfiguration(from: typedSourceData)
171
141
  if let src = typedSourceData[SD_PROP_SRC] as? String {
172
142
  // extract the type
173
143
  let type = typedSourceData[SD_PROP_TYPE] as? String ?? THEOplayerRCTSourceDescriptionBuilder.extractMimeType(src)
174
- // check for a contentProtection
175
- var contentProtection: MultiplatformDRMConfiguration?
176
- if let contentProtectionData = typedSourceData[SD_PROP_CONTENT_PROTECTION] as? [String:Any] {
177
- let sanitisedContentProtectionData = THEOplayerRCTSourceDescriptionBuilder.sanitiseContentProtectionData(contentProtectionData)
178
- contentProtection = THEOplayerRCTSourceDescriptionBuilder.buildContentProtection(sanitisedContentProtectionData)
179
- }
180
-
181
144
  return TypedSource(src: src,
182
145
  type: type,
183
146
  drm: contentProtection)
184
147
  }
185
148
 
186
- #if os(iOS) && ADS && GOOGLE_DAI
187
- // check for alternative Google DAI SSAI
188
- if let ssaiData = typedSourceData[SD_PROP_SSAI] as? [String:Any] {
189
- if let integration = ssaiData[SD_PROP_INTEGRATION] as? String,
190
- integration == SSAIIntegrationId.GoogleDAISSAIIntegrationID._rawValue {
191
- if let availabilityType = ssaiData[SD_PROP_AVAILABILITY_TYPE] as? String {
192
- // build a GoogleDAIConfiguration
193
- var googleDaiConfig: GoogleDAIConfiguration?
194
- let authToken = ssaiData[SD_PROP_AUTH_TOKEN] as? String
195
- let streamActivityMonitorID = ssaiData[SD_PROP_STREAM_ACTIVITY_MONITOR_ID] as? String
196
- let adTagParameters = ssaiData[SD_PROP_AD_TAG_PARAMETERS] as? [String:String]
197
- let apiKey = ssaiData[SD_PROP_APIKEY] as? String ?? ""
198
- switch availabilityType {
199
- case StreamType.vod._rawValue:
200
- if let videoId = ssaiData[SD_PROP_VIDEOID] as? String,
201
- let contentSourceID = ssaiData[SD_PROP_CONTENT_SOURCE_ID] as? String {
202
- googleDaiConfig = GoogleDAIVodConfiguration(videoID: videoId,
203
- contentSourceID: contentSourceID,
204
- apiKey: apiKey,
205
- authToken: authToken,
206
- streamActivityMonitorID: streamActivityMonitorID,
207
- adTagParameters: adTagParameters)
208
- }
209
- case StreamType.live._rawValue:
210
- if let assetKey = ssaiData[SD_PROP_ASSET_KEY] as? String {
211
- googleDaiConfig = GoogleDAILiveConfiguration(assetKey: assetKey,
212
- apiKey: apiKey,
213
- authToken: authToken,
214
- streamActivityMonitorID: streamActivityMonitorID,
215
- adTagParameters: adTagParameters)
216
- }
217
- default:
218
- if DEBUG_SOURCE_DESCRIPTION_BUIDER {
219
- print("[NATIVE] THEOplayer ssai 'availabilityType' must be 'live' or 'vod'")
220
- }
221
- return nil
222
- }
223
- // when valid, create a GoogleDAITypedSource from the GoogleDAIConfiguration
224
- if let config = googleDaiConfig {
225
- return GoogleDAITypedSource(ssai: config)
226
- }
227
- }
228
- }
149
+ // Check if we can extract a DAI source
150
+ if let daiSource = self.buildDAITypedSource(typedSourceData, contentProtection: contentProtection) {
151
+ return daiSource
229
152
  }
230
- #endif
153
+
231
154
  if DEBUG_SOURCE_DESCRIPTION_BUIDER {
232
155
  print("[NATIVE] THEOplayer TypedSource requires 'src' property in 'sources' description")
233
156
  }
234
157
  return nil
235
158
  }
236
159
 
160
+ private static func extractDrmConfiguration(from typedSourceData: [String:Any]) -> MultiplatformDRMConfiguration? {
161
+ // check for a contentProtection
162
+ guard let contentProtectionData = typedSourceData[SD_PROP_CONTENT_PROTECTION] as? [String:Any] else {
163
+ return nil
164
+ }
165
+ let sanitisedContentProtectionData = THEOplayerRCTSourceDescriptionBuilder.sanitiseContentProtectionData(contentProtectionData)
166
+ return THEOplayerRCTSourceDescriptionBuilder.buildContentProtection(sanitisedContentProtectionData)
167
+ }
168
+
237
169
  /**
238
170
  Creates a THEOplayer TextTrackDescription. This requires a textTracks property in the RN source description.
239
171
  - returns: a THEOplayer TextTrackDescription
@@ -255,33 +187,6 @@ class THEOplayerRCTSourceDescriptionBuilder {
255
187
  return nil
256
188
  }
257
189
 
258
- #if ADS && GOOGLE_IMA
259
- /**
260
- Creates a THEOplayer GoogleImaAdDescription. This requires an ads property in the RN source description.
261
- - returns: a THEOplayer GoogleImaAdDescription
262
- */
263
- static func buildAdDescription(_ adsData: [String:Any]) -> AdDescription? {
264
- if let integration = adsData[SD_PROP_INTEGRATION] as? String,
265
- integration == AdIntegration.google_ima._rawValue {
266
- // timeOffset can be Int or String: 10, "01:32:54.78", "1234.56", "start", "end", "10%", ...
267
- let timeOffset = adsData[SD_PROP_TIME_OFFSET] as? String ?? String(adsData[SD_PROP_TIME_OFFSET] as? Int ?? 0)
268
- var srcString: String?
269
- if let sourcesData = adsData[SD_PROP_SOURCES] as? [String:Any] {
270
- srcString = sourcesData[SD_PROP_SRC] as? String
271
- } else if let sourcesData = adsData[SD_PROP_SOURCES] as? String {
272
- srcString = sourcesData
273
- }
274
- if let src = srcString {
275
- return GoogleImaAdDescription(src: src, timeOffset: timeOffset)
276
- } else {
277
- if DEBUG_SOURCE_DESCRIPTION_BUIDER { print("[NATIVE] AdDescription requires 'src' property in 'ads' description.") }
278
- }
279
- }
280
- if DEBUG_SOURCE_DESCRIPTION_BUIDER { print("[NATIVE] We currently require and only support the 'google-ima' integration in the 'ads' description.") }
281
- return nil
282
- }
283
- #endif
284
-
285
190
  /**
286
191
  Creates a THEOplayer MetadataDescription. This requires a metadata property in the RN source description.
287
192
  - returns: a THEOplayer MetadataDescription
@@ -314,7 +219,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
314
219
  return MetadataDescription(metadataKeys: metadataData, title: title)
315
220
  #endif
316
221
  }
317
-
222
+
318
223
  #if os(iOS)
319
224
  static func buildChromecastMetadataType(_ metadataType: String?) -> ChromecastMetadataType {
320
225
  guard let typeString = metadataType else {
@@ -329,7 +234,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
329
234
  default: return ChromecastMetadataType.GENERIC
330
235
  }
331
236
  }
332
-
237
+
333
238
  static func buildChromecastMetaDataImagesArray(_ metadataImagesArrayData: [[String:Any]]) -> [ChromecastMetadataImage]? {
334
239
  var images: [ChromecastMetadataImage] = []
335
240
  for metadataImageData in metadataImagesArrayData {
@@ -339,7 +244,7 @@ class THEOplayerRCTSourceDescriptionBuilder {
339
244
  }
340
245
  return images.count > 0 ? images : nil
341
246
  }
342
-
247
+
343
248
  static func buildChromecastMetaDataImage(_ metadataImageData: [String:Any]) -> ChromecastMetadataImage? {
344
249
  if let src = metadataImageData[SD_PROP_SRC] as? String,
345
250
  let width = metadataImageData[SD_PROP_METADATA_IMAGE_WIDTH] as? Int,
@@ -1,9 +1,9 @@
1
- // THEOplayerRCTViewTextTrackEventHandler.swift
1
+ // THEOplayerRCTTextTrackEventHandler.swift
2
2
 
3
3
  import Foundation
4
4
  import THEOplayerSDK
5
5
 
6
- class THEOplayerRCTViewTextTrackEventHandler {
6
+ class THEOplayerRCTTextTrackEventHandler {
7
7
  // MARK: Members
8
8
  private weak var player: THEOplayer?
9
9
 
@@ -3,19 +3,17 @@
3
3
  import Foundation
4
4
  import UIKit
5
5
  import THEOplayerSDK
6
-
7
- #if CHROMECAST
8
- import GoogleCast
9
- #endif
10
6
 
11
7
  class THEOplayerRCTView: UIView {
12
8
  // MARK: Members
13
- private var player: THEOplayer?
14
- private var mainEventHandler: THEOplayerRCTViewMainEventHandler
15
- private var textTrackEventHandler: THEOplayerRCTViewTextTrackEventHandler
16
- private var mediaTrackEventHandler: THEOplayerRCTViewMediaTrackEventHandler
17
- private var adEventHandler: THEOplayerRCTViewAdEventHandler
18
- private var castEventHandler: THEOplayerRCTViewCastEventHandler
9
+ var player: THEOplayer?
10
+ var mainEventHandler: THEOplayerRCTMainEventHandler
11
+ var textTrackEventHandler: THEOplayerRCTTextTrackEventHandler
12
+ var mediaTrackEventHandler: THEOplayerRCTMediaTrackEventHandler
13
+ var adEventHandler: THEOplayerRCTAdsEventHandler
14
+ var castEventHandler: THEOplayerRCTCastEventHandler
15
+ var adsConfig = AdsConfig()
16
+ var castConfig = CastConfig()
19
17
 
20
18
  // MARK: Bridged props
21
19
  private var src: SourceDescription?
@@ -31,25 +29,15 @@ class THEOplayerRCTView: UIView {
31
29
  private var selectedAudioTrackUid: Int = 0
32
30
  private var seek: Double? = nil // in msec
33
31
  private var fullscreen: Bool = false
34
- private var chromecastReceiverApplicationId: String?
35
-
36
- #if os(iOS)
37
- private var castStrategy: THEOplayerSDK.CastStrategy = THEOplayerSDK.CastStrategy.manual
38
- #endif
39
- #if os(iOS) && ADS && (GOOGLE_IMA || GOOGLE_DAI)
40
- private var adSUIEnabled: Bool = true
41
- private var googleImaUsesNativeIma: Bool = true
42
- private var adPreloadType: THEOplayerSDK.AdPreloadType = .MIDROLL_AND_POSTROLL
43
- #endif
44
32
 
45
33
  // MARK: - Initialisation / view setup
46
34
  init() {
47
35
  // create event handlers to maintain event props
48
- self.mainEventHandler = THEOplayerRCTViewMainEventHandler()
49
- self.textTrackEventHandler = THEOplayerRCTViewTextTrackEventHandler()
50
- self.mediaTrackEventHandler = THEOplayerRCTViewMediaTrackEventHandler()
51
- self.adEventHandler = THEOplayerRCTViewAdEventHandler()
52
- self.castEventHandler = THEOplayerRCTViewCastEventHandler()
36
+ self.mainEventHandler = THEOplayerRCTMainEventHandler()
37
+ self.textTrackEventHandler = THEOplayerRCTTextTrackEventHandler()
38
+ self.mediaTrackEventHandler = THEOplayerRCTMediaTrackEventHandler()
39
+ self.adEventHandler = THEOplayerRCTAdsEventHandler()
40
+ self.castEventHandler = THEOplayerRCTCastEventHandler()
53
41
 
54
42
  super.init(frame: .zero)
55
43
  }
@@ -66,22 +54,6 @@ class THEOplayerRCTView: UIView {
66
54
  if DEBUG_THEOPLAYER_INTERACTION { print("[NATIVE] THEOplayer instance destroyed.") }
67
55
  }
68
56
 
69
- func ads() -> Ads? {
70
- guard let player = self.player else {
71
- return nil
72
- }
73
- return player.ads
74
- }
75
-
76
- #if os(iOS)
77
- func cast() -> Cast? {
78
- guard let player = self.player else {
79
- return nil
80
- }
81
- return player.cast
82
- }
83
- #endif
84
-
85
57
  required init?(coder aDecoder: NSCoder) {
86
58
  fatalError("[NATIVE] init(coder:) has not been implemented")
87
59
  }
@@ -122,14 +94,8 @@ class THEOplayerRCTView: UIView {
122
94
  return
123
95
  }
124
96
 
125
- var isCasting = false
126
- #if os(iOS)
127
- isCasting = self.player?.cast?.casting ?? false // TO FIX: remove 'isCasting' workaround
128
- #endif
129
-
130
- if !isCasting || self.player == nil {
131
- self.player?.destroy()
132
- self.player = nil
97
+ if !self.isCasting() || self.player == nil {
98
+ self.destroy()
133
99
  DispatchQueue.main.async {
134
100
  self.initPlayer()
135
101
  if let player = self.player {
@@ -151,61 +117,24 @@ class THEOplayerRCTView: UIView {
151
117
 
152
118
  private func initPlayer() {
153
119
  if DEBUG_THEOPLAYER_INTERACTION { print("[NATIVE] 'lazy' init THEOplayer instance") }
154
- #if os(tvOS)
155
- self.player = THEOplayer(configuration: THEOplayerConfiguration(chromeless: self.chromeless,
156
- ads: self.initAdsConfiguration(),
157
- license: self.license,
158
- licenseUrl: self.licenseUrl,
159
- pip: nil))
160
- #else
120
+ #if os(iOS)
161
121
  let stylePath = Bundle.main.path(forResource:"style", ofType: "css")
162
122
  let cssPaths = stylePath != nil ? [stylePath!] : []
163
123
  self.player = THEOplayer(configuration: THEOplayerConfiguration(chromeless: self.chromeless,
164
124
  cssPaths: cssPaths,
165
125
  pip: nil,
166
- ads: self.initAdsConfiguration(),
167
- cast: self.initCastConfiguration(),
126
+ ads: self.playerAdsConfiguration(),
127
+ cast: self.playerCastConfiguration(),
168
128
  license: self.license,
169
129
  licenseUrl: self.licenseUrl))
170
- #endif
171
- }
172
-
173
- private func initAdsConfiguration() -> AdsConfiguration? {
174
- #if os(iOS) && ADS && (GOOGLE_IMA || GOOGLE_DAI)
175
- // NOTE: GoogleIMAAdsConfiguration, GoogleDAIAdsConfigurationBuilder, GoogleDAIAdsConfigurationBuilder require iOS SDK 4.5.1 or higher
176
- let googleIMAAdsConfiguration = GoogleIMAAdsConfiguration()
177
- googleIMAAdsConfiguration.useNativeIma = self.googleImaUsesNativeIma
178
- googleIMAAdsConfiguration.disableUI = !self.adSUIEnabled
179
- let daiBuilder = GoogleDAIAdsConfigurationBuilder()
180
- daiBuilder.disableUI = !self.adSUIEnabled
181
- daiBuilder.enableBackgroundPlayback = true
182
- let googleDaiAdsConfiguration = daiBuilder.build()
183
- return AdsConfiguration(showCountdown: self.adSUIEnabled,
184
- preload: self.adPreloadType,
185
- googleIma: googleIMAAdsConfiguration,
186
- googleDai: googleDaiAdsConfiguration)
187
-
188
- // For lower iOS SDK versions replace the above with:
189
- /*let googleIMAConfiguration = GoogleIMAConfiguration()
190
- googleIMAConfiguration.useNativeIma = self.googleImaUsesNativeIma
191
- googleIMAConfiguration.disableUI = !self.adSUIEnabled
192
- return AdsConfiguration(showCountdown: self.adSUIEnabled,
193
- preload: self.adPreloadType,
194
- googleImaConfiguration: googleIMAConfiguration)*/
195
-
196
- #elseif os(tvOS) && ADS && GOOGLE_IMA
197
- return AdsConfiguration()
198
130
  #else
199
- return nil
131
+ self.player = THEOplayer(configuration: THEOplayerConfiguration(chromeless: self.chromeless,
132
+ ads: self.playerAdsConfiguration(),
133
+ license: self.license,
134
+ licenseUrl: self.licenseUrl,
135
+ pip: nil))
200
136
  #endif
201
137
  }
202
-
203
- #if os(iOS)
204
- private func initCastConfiguration() -> CastConfiguration? {
205
- // prepare the config
206
- return CastConfiguration(strategy: self.castStrategy)
207
- }
208
- #endif
209
138
 
210
139
  private func syncPlayerSrc() {
211
140
  // set sourceDescription on player
@@ -221,37 +150,8 @@ class THEOplayerRCTView: UIView {
221
150
  self.license = configDict["license"] as? String
222
151
  self.licenseUrl = configDict["licenseUrl"] as? String
223
152
  self.chromeless = configDict["chromeless"] as? Bool ?? true
224
- #if os(iOS) && ADS && (GOOGLE_IMA || GOOGLE_DAI)
225
- if let adsConfig = configDict["ads"] as? NSDictionary {
226
- self.adSUIEnabled = adsConfig["uiEnabled"] as? Bool ?? true
227
- if let adPreloadType = adsConfig["preload"] as? String {
228
- self.adPreloadType = adPreloadType == "none" ? THEOplayerSDK.AdPreloadType.NONE : THEOplayerSDK.AdPreloadType.MIDROLL_AND_POSTROLL
229
- }
230
- if let googleImaConfiguration = adsConfig["googleImaConfiguration"] as? NSDictionary {
231
- self.googleImaUsesNativeIma = googleImaConfiguration["useNativeIma"] as? Bool ?? true
232
- }
233
- }
234
- #endif
235
- #if os(iOS)
236
- if let castConfig = configDict["cast"] as? NSDictionary {
237
- if let castStrategy = castConfig["strategy"] as? String {
238
- switch castStrategy {
239
- case "auto":
240
- self.castStrategy = THEOplayerSDK.CastStrategy.auto
241
- case "manual":
242
- self.castStrategy = THEOplayerSDK.CastStrategy.manual
243
- case "disabled":
244
- self.castStrategy = THEOplayerSDK.CastStrategy.disabled
245
- default :
246
- self.castStrategy = THEOplayerSDK.CastStrategy.manual
247
- }
248
- }
249
- if let chromecastConfig = castConfig["chromecast"] as? NSDictionary,
250
- let castReceiverApplicationId = chromecastConfig["appID"] as? String {
251
- self.chromecastReceiverApplicationId = castReceiverApplicationId
252
- }
253
- }
254
- #endif
153
+ self.parseAdsConfig(configDict: configDict)
154
+ self.parseCastConfig(configDict: configDict)
255
155
  if DEBUG_PROP_UPDATES { print("[NATIVE] config prop updated.") }
256
156
  }
257
157
 
@@ -571,14 +471,6 @@ class THEOplayerRCTView: UIView {
571
471
  if DEBUG_PROP_UPDATES { print("[NATIVE] nativeMediaTrackEvent prop set.") }
572
472
  }
573
473
 
574
- // MARK: - Listener based AD event bridging
575
-
576
- @objc(setOnNativeAdEvent:)
577
- func setOnNativeAdEvent(nativeAdEvent: @escaping RCTDirectEventBlock) {
578
- self.adEventHandler.onNativeAdEvent = nativeAdEvent
579
- if DEBUG_PROP_UPDATES { print("[NATIVE] nativeAdEvent prop set.") }
580
- }
581
-
582
474
  // MARK: - Listener based CAST event bridging
583
475
 
584
476
  @objc(setOnNativeCastEvent:)
@@ -586,4 +478,12 @@ class THEOplayerRCTView: UIView {
586
478
  self.castEventHandler.onNativeCastEvent = nativeCastEvent
587
479
  if DEBUG_PROP_UPDATES { print("[NATIVE] nativeCastEvent prop set.") }
588
480
  }
481
+
482
+ // MARK: - Listener based AD event bridging
483
+
484
+ @objc(setOnNativeAdEvent:)
485
+ func setOnNativeAdEvent(nativeAdEvent: @escaping RCTDirectEventBlock) {
486
+ self.adEventHandler.onNativeAdEvent = nativeAdEvent
487
+ if DEBUG_PROP_UPDATES { print("[NATIVE] nativeAdEvent prop set.") }
488
+ }
589
489
  }
@@ -40,7 +40,7 @@ let PROP_COMPANION_RESOURCE_URI: String = "resourceURI"
40
40
 
41
41
  class THEOplayerRCTAdAggregator {
42
42
 
43
- #if ADS && (GOOGLE_IMA || GOOGLE_DAI)
43
+ #if (GOOGLE_IMA || GOOGLE_DAI)
44
44
  class func aggregateAd(ad: Ad, processAdBreak: Bool = true) -> [String:Any] {
45
45
  var adData: [String:Any] = [:]
46
46
  adData[PROP_AD_INTEGRATION] = ad.integration._rawValue
@@ -0,0 +1,108 @@
1
+ // THEOplayerRCTAdsAPI+DAI.swift
2
+
3
+ import Foundation
4
+ import UIKit
5
+
6
+ let ERROR_CODE_DAI_ACCESS_FAILURE = "dai_access_failure"
7
+ let ERROR_CODE_DAI_GET_SNAPBACK_FAILED = "dai_get_snapback_failed"
8
+ let ERROR_CODE_DAI_GET_SNAPBACK_UNDEFINED = "dai_get_snapback_undefined"
9
+ let ERROR_MESSAGE_DAI_ACCESS_FAILURE = "Could not access THEOplayer Ads DAI Module"
10
+ let ERROR_MESSAGE_DAI_GET_SNAPBACK_UNDEFINED = "Undefined dai snapback"
11
+
12
+ extension THEOplayerRCTAdsAPI {
13
+
14
+ #if GOOGLE_DAI
15
+ @objc(daiSnapback:resolver:rejecter:)
16
+ func daiSnapback(_ node: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
17
+ DispatchQueue.main.async {
18
+ let theView = self.bridge.uiManager.view(forReactTag: node) as! THEOplayerRCTView
19
+ if let ads = theView.ads(),
20
+ let dai = ads.dai {
21
+ dai.requestSnapBack { enabled, error in
22
+ if let err = error {
23
+ reject(ERROR_CODE_DAI_GET_SNAPBACK_FAILED, err.localizedDescription, error)
24
+ if DEBUG_ADS_API { print("[NATIVE] Retrieving dai snapback status failed: \(err.localizedDescription)") }
25
+ } else if let snapBack = enabled {
26
+ resolve(snapBack)
27
+ } else {
28
+ reject(ERROR_CODE_DAI_GET_SNAPBACK_UNDEFINED, ERROR_MESSAGE_DAI_GET_SNAPBACK_UNDEFINED, nil)
29
+ if DEBUG_ADS_API { print("[NATIVE] Retrieving dai snapback status failed.") }
30
+ }
31
+ }
32
+ } else {
33
+ reject(ERROR_CODE_DAI_ACCESS_FAILURE, ERROR_MESSAGE_DAI_ACCESS_FAILURE, nil)
34
+ if DEBUG_ADS_API { print("[NATIVE] Could not retrieve dai snapback status (ads DAI module unavailable).") }
35
+ }
36
+ }
37
+ }
38
+
39
+ @objc(daiSetSnapback:enabled:)
40
+ func daiSetSnapback(_ node: NSNumber, enabled: Bool) -> Void {
41
+ DispatchQueue.main.async {
42
+ let theView = self.bridge.uiManager.view(forReactTag: node) as! THEOplayerRCTView
43
+ if let ads = theView.ads(),
44
+ let dai = ads.dai {
45
+ dai.setSnapBack(enabled, completionHandler: nil)
46
+ } else {
47
+ if DEBUG_ADS_API { print("[NATIVE] Could not update dai snapback status (ads DAI module unavailable).") }
48
+ }
49
+ }
50
+ }
51
+
52
+ @objc(daiContentTimeForStreamTime:time:resolver:rejecter:)
53
+ func daiContentTimeForStreamTime(_ node: NSNumber, timeValue: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
54
+ DispatchQueue.main.async {
55
+ let theView = self.bridge.uiManager.view(forReactTag: node) as! THEOplayerRCTView
56
+ if let ads = theView.ads(),
57
+ let dai = ads.dai {
58
+ let streamTime = timeValue.doubleValue * 0.001 // msec -> sec
59
+ let contentTime = dai.contentTime(from: streamTime) * 1000.0 // sec -> msec
60
+ resolve(contentTime)
61
+ } else {
62
+ reject(ERROR_CODE_DAI_ACCESS_FAILURE, ERROR_MESSAGE_DAI_ACCESS_FAILURE, nil)
63
+ if DEBUG_ADS_API { print("[NATIVE] Could not convert stream time to content time (ads DAI module unavailable).") }
64
+ }
65
+ }
66
+ }
67
+
68
+ @objc(daiStreamTimeForContentTime:time:resolver:rejecter:)
69
+ func daiStreamTimeForContentTime(_ node: NSNumber, timeValue: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
70
+ DispatchQueue.main.async {
71
+ let theView = self.bridge.uiManager.view(forReactTag: node) as! THEOplayerRCTView
72
+ if let ads = theView.ads(),
73
+ let dai = ads.dai {
74
+ let contentTime = timeValue.doubleValue * 0.001 // msec -> sec
75
+ let streamTime = dai.streamTime(from: contentTime) * 1000.0 // sec -> msec
76
+ resolve(streamTime)
77
+ } else {
78
+ reject(ERROR_CODE_DAI_ACCESS_FAILURE, ERROR_MESSAGE_DAI_ACCESS_FAILURE, nil)
79
+ if DEBUG_ADS_API { print("[NATIVE] Could not convert content time to stream time (ads DAI module unavailable).") }
80
+ }
81
+ }
82
+ }
83
+
84
+ #else
85
+
86
+ @objc(daiSnapback:resolver:rejecter:)
87
+ func daiSnapback(_ node: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
88
+ if DEBUG_ADS_API { print(ERROR_MESSAGE_ADS_UNSUPPORTED_FEATURE) }
89
+ resolve(false)
90
+ }
91
+
92
+ @objc(daiContentTimeForStreamTime:time:resolver:rejecter:)
93
+ func daiContentTimeForStreamTime(_ node: NSNumber, timeValue: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
94
+ if DEBUG_ADS_API { print(ERROR_MESSAGE_ADS_UNSUPPORTED_FEATURE) }
95
+ resolve(timeValue.doubleValue)
96
+ }
97
+
98
+ @objc(daiStreamTimeForContentTime:time:resolver:rejecter:)
99
+ func daiStreamTimeForContentTime(_ node: NSNumber, timeValue: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
100
+ if DEBUG_ADS_API { print(ERROR_MESSAGE_ADS_UNSUPPORTED_FEATURE) }
101
+ resolve(timeValue.doubleValue)
102
+ }
103
+
104
+ #endif
105
+ }
106
+
107
+
108
+