react-native-theoplayer 8.13.0 → 8.14.0

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 (35) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/android/src/main/java/com/theoplayer/PlayerConfigAdapter.kt +17 -0
  3. package/android/src/main/java/com/theoplayer/util/ViewResolver.kt +13 -7
  4. package/ios/THEOplayerRCTSourceDescriptionBuilder.swift +7 -0
  5. package/ios/THEOplayerRCTView.swift +24 -1
  6. package/ios/ads/THEOplayerRCTSourceDescriptionBuilder+Ads.swift +32 -21
  7. package/ios/ads/THEOplayerRCTView+Ads.swift +5 -3
  8. package/ios/backgroundAudio/THEOplayerRCTNowPlayingManager.swift +2 -1
  9. package/ios/casting/THEOplayerRCTView+Casting.swift +4 -2
  10. package/ios/presentationMode/THEOplayerRCTPresentationModeManager.swift +19 -19
  11. package/ios/theoAds/THEOplayerRCTSourceDescriptionBuilder+TheoAds.swift +62 -0
  12. package/ios/theoAds/THEOplayerRCTView+TheoAds.swift +23 -0
  13. package/lib/commonjs/api/theolive/TheoLiveConfiguration.js +2 -0
  14. package/lib/commonjs/api/theolive/TheoLiveConfiguration.js.map +1 -0
  15. package/lib/commonjs/api/theolive/barrel.js +11 -0
  16. package/lib/commonjs/api/theolive/barrel.js.map +1 -1
  17. package/lib/commonjs/manifest.json +1 -1
  18. package/lib/module/api/theolive/TheoLiveConfiguration.js +2 -0
  19. package/lib/module/api/theolive/TheoLiveConfiguration.js.map +1 -0
  20. package/lib/module/api/theolive/barrel.js +1 -0
  21. package/lib/module/api/theolive/barrel.js.map +1 -1
  22. package/lib/module/manifest.json +1 -1
  23. package/lib/typescript/api/config/PlayerConfiguration.d.ts +5 -0
  24. package/lib/typescript/api/config/PlayerConfiguration.d.ts.map +1 -1
  25. package/lib/typescript/api/theolive/TheoLiveConfiguration.d.ts +38 -0
  26. package/lib/typescript/api/theolive/TheoLiveConfiguration.d.ts.map +1 -0
  27. package/lib/typescript/api/theolive/barrel.d.ts +1 -0
  28. package/lib/typescript/api/theolive/barrel.d.ts.map +1 -1
  29. package/package.json +1 -1
  30. package/react-native-theoplayer.json +1 -1
  31. package/react-native-theoplayer.podspec +6 -1
  32. package/src/api/config/PlayerConfiguration.ts +6 -0
  33. package/src/api/theolive/TheoLiveConfiguration.ts +40 -0
  34. package/src/api/theolive/barrel.ts +1 -0
  35. package/src/manifest.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [8.14.0] - 25-02-10
9
+
10
+ ### Added
11
+
12
+ - Added a `theoLive` property to `PlayerConfiguration` to enable THEOlive configuration.
13
+
14
+ ### Fixed
15
+
16
+ - Fixed an issue on iOS where the `currentTime` on `NowPlayingInfoCenter` would go out of sync or reset when changing playback rate.
17
+ - Fixed an issue on Android where the player would crash in case resolving the `THEOplayerView` instance fails.
18
+
19
+ ## [8.13.1] - 25-01-27
20
+
21
+ ### Fixed
22
+
23
+ - Fixed an issue on iOS where fullscreen-inline transitions would cause a UIViewControllerHierarchyInconsistency when the current view's viewcController has sibling viewControllers that manage views that don't descend of the moving view.
24
+
8
25
  ## [8.13.0] - 25-01-15
9
26
 
10
27
  ### Added
@@ -10,6 +10,7 @@ import com.theoplayer.android.api.cast.CastStrategy
10
10
  import com.theoplayer.android.api.cast.CastConfiguration
11
11
  import com.theoplayer.android.api.pip.PipConfiguration
12
12
  import com.theoplayer.android.api.player.NetworkConfiguration
13
+ import com.theoplayer.android.api.theolive.THEOLiveConfig
13
14
  import com.theoplayer.media.MediaSessionConfig
14
15
  import com.theoplayer.media.MediaSessionConfigAdapter
15
16
 
@@ -38,6 +39,9 @@ private const val PROP_SESSION_ID = "sessionID"
38
39
  private const val PROP_ENABLE_DEBUG_MODE = "enableDebugMode"
39
40
  private const val PROP_BITRATE = "bitrate"
40
41
  private const val PROP_ALLOWED_MIMETYPES = "allowedMimeTypes"
42
+ private const val PROP_THEOLIVE_CONFIG = "theoLive"
43
+ private const val PROP_THEOLIVE_EXTERNAL_SESSION_ID = "externalSessionId"
44
+ private const val PROP_THEOLIVE_ANALYTICS_DISABLED = "analyticsDisabled"
41
45
 
42
46
  class PlayerConfigAdapter(private val configProps: ReadableMap?) {
43
47
 
@@ -74,6 +78,9 @@ class PlayerConfigAdapter(private val configProps: ReadableMap?) {
74
78
  if (hasKey(PROP_USE_MEDIA3)) {
75
79
  useMedia3 = getBoolean(PROP_USE_MEDIA3)
76
80
  }
81
+ if (hasKey(PROP_THEOLIVE_CONFIG)) {
82
+ theoLiveConfiguration(theoLiveConfig())
83
+ }
77
84
  pipConfiguration(PipConfiguration.Builder().build())
78
85
  }
79
86
  }.build()
@@ -217,4 +224,14 @@ class PlayerConfigAdapter(private val configProps: ReadableMap?) {
217
224
  fun mediaSessionConfig(): MediaSessionConfig {
218
225
  return MediaSessionConfigAdapter.fromProps(configProps?.getMap(PROP_MEDIA_CONTROL))
219
226
  }
227
+
228
+ private fun theoLiveConfig (): THEOLiveConfig {
229
+ val config = configProps?.getMap(PROP_THEOLIVE_CONFIG)
230
+ return THEOLiveConfig.Builder(
231
+ externalSessionId = config?.getString(PROP_THEOLIVE_EXTERNAL_SESSION_ID),
232
+ analyticsDisabled = if (config?.hasKey(PROP_THEOLIVE_ANALYTICS_DISABLED) == true)
233
+ config.getBoolean(PROP_THEOLIVE_ANALYTICS_DISABLED)
234
+ else false
235
+ ).build()
236
+ }
220
237
  }
@@ -10,21 +10,27 @@ private const val INVALID_TAG = -1
10
10
 
11
11
  @Suppress("UNCHECKED_CAST")
12
12
  class ViewResolver(private val reactContext: ReactApplicationContext) {
13
- fun <T: View> resolveViewByTag(tag: Int, onResolved: (view: T?) -> Unit) {
13
+ fun <T : View> resolveViewByTag(tag: Int, onResolved: (view: T?) -> Unit) {
14
14
  if (tag == INVALID_TAG) {
15
15
  // Don't bother trying to resolve an invalid tag.
16
16
  onResolved(null)
17
17
  }
18
- try {
19
- reactContext.runOnUiQueueThread {
18
+ reactContext.runOnUiQueueThread {
19
+ try {
20
+ /**
21
+ * UIManager replaces the UIManagerModule. UIManager is retrieved through the static methods
22
+ * in UIManagerHelper. Most legacy operations remain intact for backwards compatibility.
23
+ *
24
+ * https://github.com/reactwg/react-native-new-architecture/discussions/201
25
+ */
20
26
  UIManagerHelper.getUIManagerForReactTag(reactContext, tag)?.let {
21
27
  onResolved(it.resolveView(tag) as? T?)
22
28
  }
29
+ } catch (e: Exception) {
30
+ // The ReactTHEOplayerView instance could not be resolved: log but do not forward exception.
31
+ Log.w(TAG, "Failed to resolve ReactTHEOplayerView tag $tag: $e")
32
+ onResolved(null)
23
33
  }
24
- } catch (e: Exception) {
25
- // The ReactTHEOplayerView instance could not be resolved: log but do not forward exception.
26
- Log.e(TAG, "Failed to resolve ReactTHEOplayerView tag $tag: $e")
27
- onResolved(null)
28
34
  }
29
35
  }
30
36
  }
@@ -50,6 +50,13 @@ let SD_PROP_METADATA_TITLE: String = "title"
50
50
  let SD_PROP_METADATA_SUBTITLE: String = "subtitle"
51
51
  let SD_PROP_PTS: String = "subtitlePTS"
52
52
  let SD_PROP_LOCALTIME: String = "subtitleLocaltime"
53
+ let SD_PROP_NETWORK_CODE: String = "networkCode"
54
+ let SD_PROP_CUSTOM_ASSET_KEY: String = "customAssetKey"
55
+ let SD_PROP_BACKDROP_DOUBLE_BOX: String = "backdropDoubleBox"
56
+ let SD_PROP_BACKDROP_L_SHAPE: String = "backdropLShape"
57
+ let SD_PROP_OVERRIDE_LAYOUT: String = "overrideLayout"
58
+ let SD_PROP_OVERRIDE_AD_SRC: String = "overrideAdSrc"
59
+ let SD_PROP_USE_ID3: String = "useId3"
53
60
 
54
61
  let EXTENSION_HLS: String = ".m3u8"
55
62
  let EXTENSION_MP4: String = ".mp4"
@@ -3,7 +3,18 @@
3
3
  import Foundation
4
4
  import UIKit
5
5
  import THEOplayerSDK
6
-
6
+
7
+ #if canImport(THEOplayerTHEOadsIntegration)
8
+ import THEOplayerTHEOadsIntegration
9
+ #endif
10
+ #if canImport(THEOplayerGoogleIMAIntegration)
11
+ import THEOplayerGoogleIMAIntegration
12
+ import GoogleInteractiveMediaAds
13
+ #endif
14
+ #if canImport(THEOplayerGoogleCastIntegration)
15
+ import THEOplayerGoogleCastIntegration
16
+ #endif
17
+
7
18
  public class THEOplayerRCTView: UIView {
8
19
  // MARK: Members
9
20
  public private(set) var player: THEOplayer?
@@ -25,6 +36,17 @@ public class THEOplayerRCTView: UIView {
25
36
  var castConfig = CastConfig()
26
37
  var uiConfig = UIConfig()
27
38
 
39
+ // integrations
40
+ #if canImport(THEOplayerTHEOadsIntegration)
41
+ var theoAdsIntegration: THEOplayerTHEOadsIntegration.THEOadsIntegration?
42
+ #endif
43
+ #if canImport(THEOplayerGoogleIMAIntegration)
44
+ var imaIntegration: THEOplayerGoogleIMAIntegration.GoogleImaIntegration?
45
+ #endif
46
+ #if canImport(THEOplayerGoogleCastIntegration)
47
+ var castIntegration: THEOplayerGoogleCastIntegration.CastIntegration?
48
+ #endif
49
+
28
50
  var mediaControlConfig = MediaControlConfig() {
29
51
  didSet {
30
52
  self.remoteCommandsManager.setMediaControlConfig(mediaControlConfig)
@@ -149,6 +171,7 @@ public class THEOplayerRCTView: UIView {
149
171
 
150
172
  self.initAdsIntegration()
151
173
  self.initCastIntegration()
174
+ self.initTheoAdsIntegration()
152
175
  self.initBackgroundAudio()
153
176
  self.initPip()
154
177
  return self.player
@@ -1,4 +1,4 @@
1
- // THEOplayerRCTSourceDescriptionBuilder.swift
1
+ // THEOplayerRCTSourceDescriptionBuilder+Ads.swift
2
2
 
3
3
  import Foundation
4
4
  import THEOplayerSDK
@@ -15,7 +15,6 @@ extension THEOplayerRCTSourceDescriptionBuilder {
15
15
  static func buildAdDescriptions(_ sourceData: NSDictionary) -> [AdDescription]? {
16
16
  var adsDescriptions: [AdDescription]?
17
17
 
18
- #if canImport(THEOplayerGoogleIMAIntegration)
19
18
  if let ads = sourceData[SD_PROP_ADS] {
20
19
  adsDescriptions = []
21
20
  // case: array of ads objects
@@ -43,36 +42,48 @@ extension THEOplayerRCTSourceDescriptionBuilder {
43
42
  }
44
43
  }
45
44
  }
46
- #endif
47
45
 
48
46
  return adsDescriptions
49
47
  }
50
48
 
49
+ /**
50
+ Creates a THEOplayer AdDescription. This requires an ads property in the RN source description.
51
+ - returns: a THEOplayerAdDescription
52
+ */
53
+ static func buildSingleAdDescription(_ adsData: [String:Any]) -> AdDescription? {
54
+ if let integration = adsData[SD_PROP_INTEGRATION] as? String {
55
+ switch integration {
56
+ case "google-ima":
57
+ return THEOplayerRCTSourceDescriptionBuilder.buildSingleGoogleIMAAdsDescription(adsData)
58
+ case "theoads":
59
+ return THEOplayerRCTSourceDescriptionBuilder.buildSingleTheoAdsDescription(adsData)
60
+ default:
61
+ if DEBUG_SOURCE_DESCRIPTION_BUIDER { PrintUtils.printLog(logText: "[NATIVE] We currently require and only support the 'google-ima' or 'sgai' integration in the 'ads' description.") }
62
+ }
63
+ }
64
+ return nil
65
+ }
66
+
51
67
  /**
52
68
  Creates a THEOplayer GoogleImaAdDescription. This requires an ads property in the RN source description.
53
69
  - returns: a THEOplayer GoogleImaAdDescription
54
70
  */
55
- static func buildSingleAdDescription(_ adsData: [String:Any]) -> AdDescription? {
71
+ static func buildSingleGoogleIMAAdsDescription(_ adsData: [String:Any]) -> AdDescription? {
56
72
  #if canImport(THEOplayerGoogleIMAIntegration)
57
- if let integration = adsData[SD_PROP_INTEGRATION] as? String,
58
- integration == AdIntegration.google_ima._rawValue {
59
- // timeOffset can be Int or String: 10, "01:32:54.78", "1234.56", "start", "end", "10%", ...
60
- let timeOffset = adsData[SD_PROP_TIME_OFFSET] as? String ?? String(adsData[SD_PROP_TIME_OFFSET] as? Int ?? 0)
61
- var srcString: String?
62
- if let sourcesData = adsData[SD_PROP_SOURCES] as? [String:Any] {
63
- srcString = sourcesData[SD_PROP_SRC] as? String
64
- } else if let sourcesData = adsData[SD_PROP_SOURCES] as? String {
65
- srcString = sourcesData
66
- }
67
- if let src = srcString {
68
- return GoogleImaAdDescription(src: src, timeOffset: timeOffset)
69
- } else {
70
- if DEBUG_SOURCE_DESCRIPTION_BUIDER { PrintUtils.printLog(logText: "[NATIVE] AdDescription requires 'src' property in 'ads' description.") }
71
- }
73
+ // timeOffset can be Int or String: 10, "01:32:54.78", "1234.56", "start", "end", "10%", ...
74
+ let timeOffset = adsData[SD_PROP_TIME_OFFSET] as? String ?? String(adsData[SD_PROP_TIME_OFFSET] as? Int ?? 0)
75
+ var srcString: String?
76
+ if let sourcesData = adsData[SD_PROP_SOURCES] as? [String:Any] {
77
+ srcString = sourcesData[SD_PROP_SRC] as? String
78
+ } else if let sourcesData = adsData[SD_PROP_SOURCES] as? String {
79
+ srcString = sourcesData
80
+ }
81
+ if let src = srcString {
82
+ return GoogleImaAdDescription(src: src, timeOffset: timeOffset)
83
+ } else {
84
+ if DEBUG_SOURCE_DESCRIPTION_BUIDER { PrintUtils.printLog(logText: "[NATIVE] AdDescription requires 'src' property in 'ads' description.") }
72
85
  }
73
- if DEBUG_SOURCE_DESCRIPTION_BUIDER { PrintUtils.printLog(logText: "[NATIVE] We currently require and only support the 'google-ima' integration in the 'ads' description.") }
74
86
  #endif
75
-
76
87
  return nil
77
88
  }
78
89
 
@@ -62,9 +62,11 @@ extension THEOplayerRCTView {
62
62
  }
63
63
 
64
64
  // setup integration
65
- let imaIntegration = GoogleIMAIntegrationFactory.createIntegration(on: player, with: imaSettings)
66
- imaIntegration.renderingSettings = imaRenderSettings
67
- player.addIntegration(imaIntegration)
65
+ self.imaIntegration = GoogleIMAIntegrationFactory.createIntegration(on: player, with: imaSettings)
66
+ if let newImaIntegration = self.imaIntegration {
67
+ newImaIntegration.renderingSettings = imaRenderSettings
68
+ player.addIntegration(newImaIntegration)
69
+ }
68
70
  #endif
69
71
  }
70
72
  }
@@ -241,7 +241,8 @@ class THEOplayerRCTNowPlayingManager {
241
241
  self.rateChangeListener = player.addEventListener(type: PlayerEventTypes.RATE_CHANGE) { [weak self, weak player] event in
242
242
  if let welf = self,
243
243
  let wplayer = player {
244
- welf.nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = NSNumber(value: wplayer.playbackRate)
244
+ welf.updatePlaybackRate(wplayer.playbackRate)
245
+ welf.updateCurrentTime(wplayer.currentTime)
245
246
  if DEBUG_NOWINFO { PrintUtils.printLog(logText: "[NATIVE] RATE_CHANGE: Updating playbackRate on NowPlayingInfoCenter...") }
246
247
  welf.processNowPlayingToInfoCenter()
247
248
  }
@@ -23,8 +23,10 @@ extension THEOplayerRCTView {
23
23
  }
24
24
  #if os(iOS) && canImport(THEOplayerGoogleCastIntegration)
25
25
  if let castConfiguration = self.playerCastConfiguration() {
26
- let castIntegration = GoogleCastIntegrationFactory.createIntegration(on: player, with: castConfiguration)
27
- player.addIntegration(castIntegration)
26
+ self.castIntegration = GoogleCastIntegrationFactory.createIntegration(on: player, with: castConfiguration)
27
+ if let newCastIntegration = self.castIntegration {
28
+ player.addIntegration(newCastIntegration)
29
+ }
28
30
  }
29
31
  #endif
30
32
  }
@@ -11,7 +11,6 @@ public class THEOplayerRCTPresentationModeManager {
11
11
  var presentationModeContext = THEOplayerRCTPresentationModeContext()
12
12
  private var presentationMode: THEOplayerSDK.PresentationMode = .inline
13
13
  private var rnInlineMode: THEOplayerSDK.PresentationMode = .inline // while native player is inline, RN player can be inline or fullsceen
14
- private var movingChildVCs: [UIViewController] = [] // list of playerView's child VCs that need to be reparented while moving the playerView
15
14
 
16
15
 
17
16
  private weak var containerView: UIView? // view containing the playerView and it's siblings (e.g. UI)
@@ -27,7 +26,6 @@ public class THEOplayerRCTPresentationModeManager {
27
26
  func destroy() {
28
27
  // dettach listeners
29
28
  self.dettachListeners()
30
- self.clearMovingVCs()
31
29
  }
32
30
 
33
31
  // MARK: - player setup / breakdown
@@ -40,21 +38,22 @@ public class THEOplayerRCTPresentationModeManager {
40
38
  }
41
39
 
42
40
  // MARK: - logic
43
- private func storeMovingVCs(for view: UIView) {
41
+ private func movingVCs(for view: UIView) -> [UIViewController] {
42
+ var viewControllers: [UIViewController] = []
44
43
  if let viewController = view.findViewController() {
45
44
  viewController.children.forEach { childVC in
46
- self.movingChildVCs.append(childVC)
45
+ if childVC.view.isDescendant(of: view) {
46
+ viewControllers.append(childVC)
47
+ }
47
48
  }
48
49
  }
49
- }
50
-
51
- private func clearMovingVCs() {
52
- self.movingChildVCs = []
50
+ return viewControllers
53
51
  }
54
52
 
55
53
  private func moveView(_ movingView: UIView, to targetView: UIView) {
56
54
  // detach the moving viewControllers from their parent
57
- self.movingChildVCs.forEach { movedVC in
55
+ let movingViewControllers = self.movingVCs(for: movingView)
56
+ movingViewControllers.forEach { movedVC in
58
57
  movedVC.removeFromParent()
59
58
  }
60
59
 
@@ -65,7 +64,7 @@ public class THEOplayerRCTPresentationModeManager {
65
64
 
66
65
  // attach the moving viewControllers to their new parent
67
66
  if let targetViewController = targetView.findViewController() {
68
- self.movingChildVCs.forEach { movedVC in
67
+ movingViewControllers.forEach { movedVC in
69
68
  targetViewController.addChild(movedVC)
70
69
  movedVC.didMove(toParent: targetViewController)
71
70
  }
@@ -73,13 +72,12 @@ public class THEOplayerRCTPresentationModeManager {
73
72
  }
74
73
 
75
74
  private func enterFullscreen() {
76
- self.containerView = self.view?.findParentViewOfType(RCTView.self)
77
- self.inlineParentView = self.containerView?.findParentViewOfType(RCTView.self)
75
+ self.containerView = self.view?.findParentViewOfType(["RCTView", "RCTViewComponentView"])
76
+ self.inlineParentView = self.containerView?.superview
78
77
 
79
78
  // move the player
80
79
  if let containerView = self.containerView,
81
- let fullscreenParentView = self.view?.findParentViewOfType(RCTRootContentView.self) {
82
- self.storeMovingVCs(for: containerView)
80
+ let fullscreenParentView = self.view?.findParentViewOfType(["RCTRootContentView", "RCTRootComponentView"]) {
83
81
  self.moveView(containerView, to: fullscreenParentView)
84
82
 
85
83
  // start hiding home indicator
@@ -96,14 +94,13 @@ public class THEOplayerRCTPresentationModeManager {
96
94
  if let containerView = self.containerView,
97
95
  let inlineParentView = self.inlineParentView {
98
96
  self.moveView(containerView, to: inlineParentView)
99
- self.clearMovingVCs()
100
97
  }
101
98
  self.rnInlineMode = .inline
102
99
  }
103
100
 
104
101
  private func setHomeIndicatorHidden(_ hidden: Bool) {
105
102
  #if os(iOS)
106
- if let fullscreenParentView = self.view?.findParentViewOfType(RCTRootContentView.self),
103
+ if let fullscreenParentView = self.view?.findParentViewOfType(["RCTRootContentView", "RCTRootComponentView"]),
107
104
  let customRootViewController = fullscreenParentView.findViewController() as? HomeIndicatorViewController {
108
105
  customRootViewController.prefersAutoHidden = hidden
109
106
  customRootViewController.setNeedsUpdateOfHomeIndicatorAutoHidden()
@@ -216,11 +213,14 @@ public class THEOplayerRCTPresentationModeManager {
216
213
 
217
214
  // UIView extension to look for parent views
218
215
  extension UIView {
219
- func findParentViewOfType<T: UIView>(_ viewType: T.Type) -> T? {
216
+ func findParentViewOfType(_ viewTypeNames: [String]) -> UIView? {
220
217
  var currentView: UIView? = self
221
218
  while let view = currentView {
222
- if let parentView = view.superview as? T {
223
- return parentView
219
+ if let parentView = view.superview {
220
+ let instanceTypeName = String(describing: type(of: parentView))
221
+ if viewTypeNames.contains(instanceTypeName) {
222
+ return parentView
223
+ }
224
224
  }
225
225
  currentView = view.superview
226
226
  }
@@ -0,0 +1,62 @@
1
+ // THEOplayerRCTSourceDescriptionBuilder+TheoAds.swift
2
+
3
+ import Foundation
4
+ import THEOplayerSDK
5
+ import UIKit
6
+
7
+ #if canImport(THEOplayerTHEOadsIntegration)
8
+ import THEOplayerTHEOadsIntegration
9
+ #endif
10
+
11
+ extension THEOplayerRCTSourceDescriptionBuilder {
12
+
13
+ /**
14
+ Creates a THEOplayer GoogleImaAdDescription. This requires an ads property in the RN source description.
15
+ - returns: a THEOplayer GoogleImaAdDescription
16
+ */
17
+ static func buildSingleTheoAdsDescription(_ adsData: [String:Any]) -> AdDescription? {
18
+ #if canImport(THEOplayerTHEOadsIntegration)
19
+ //...
20
+ let networkCode = adsData[SD_PROP_NETWORK_CODE] as? String
21
+ let customAssetKey = adsData[SD_PROP_CUSTOM_ASSET_KEY] as? String
22
+ var backdropDoubleBox: URL?
23
+ if let backdropDoubleBoxString = adsData[SD_PROP_BACKDROP_DOUBLE_BOX] as? String {
24
+ backdropDoubleBox = URL(string: backdropDoubleBoxString)
25
+ }
26
+ var backdropLShape: URL?
27
+ if let backdropLShapeString = adsData[SD_PROP_BACKDROP_L_SHAPE] as? String {
28
+ backdropLShape = URL(string: backdropLShapeString)
29
+ }
30
+ var overrideLayout: THEOAdDescription.LayoutOverride?
31
+ if let overrideLayoutString = adsData[SD_PROP_OVERRIDE_LAYOUT] as? String {
32
+ switch overrideLayoutString {
33
+ case "single":
34
+ overrideLayout = .single
35
+ case "l-shape":
36
+ overrideLayout = .lShape
37
+ case "double":
38
+ overrideLayout = .double
39
+ default:
40
+ overrideLayout = nil
41
+ }
42
+ }
43
+ var overrideAdSrc: URL?
44
+ if let overrideAdSrcString = adsData[SD_PROP_OVERRIDE_AD_SRC] as? String {
45
+ overrideAdSrc = URL(string: overrideAdSrcString)
46
+ }
47
+ let adTagParameters = adsData[SD_PROP_AD_TAG_PARAMETERS] as? [String:String]
48
+ let useId3 = adsData[SD_PROP_USE_ID3] as? Bool
49
+ return THEOAdDescription(networkCode: networkCode,
50
+ customAssetKey: customAssetKey,
51
+ backdropDoubleBox: backdropDoubleBox,
52
+ backdropLShape: backdropLShape,
53
+ overrideLayout: overrideLayout,
54
+ overrideAdSrc: overrideAdSrc,
55
+ adTagParameters: adTagParameters,
56
+ useId3: useId3)
57
+ #else
58
+ return nil
59
+ #endif
60
+
61
+ }
62
+ }
@@ -0,0 +1,23 @@
1
+ // THEOplayerRCTView+TheoAds.swift
2
+
3
+ import Foundation
4
+ import THEOplayerSDK
5
+
6
+ #if canImport(THEOplayerTHEOadsIntegration)
7
+ import THEOplayerTHEOadsIntegration
8
+ #endif
9
+
10
+ extension THEOplayerRCTView {
11
+ func initTheoAdsIntegration() {
12
+ guard let player = self.player else {
13
+ return
14
+ }
15
+
16
+ #if canImport(THEOplayerTHEOadsIntegration)
17
+ // setup integration
18
+ self.theoAdsIntegration = THEOadsIntegrationFactory.createIntegration(on: player)
19
+ player.addIntegration(self.theoAdsIntegration!)
20
+ #endif
21
+
22
+ }
23
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=TheoLiveConfiguration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../../src","sources":["api/theolive/TheoLiveConfiguration.ts"],"mappings":"","ignoreList":[]}
@@ -14,4 +14,15 @@ Object.keys(_TheoLiveSource).forEach(function (key) {
14
14
  }
15
15
  });
16
16
  });
17
+ var _TheoLiveConfiguration = require("./TheoLiveConfiguration");
18
+ Object.keys(_TheoLiveConfiguration).forEach(function (key) {
19
+ if (key === "default" || key === "__esModule") return;
20
+ if (key in exports && exports[key] === _TheoLiveConfiguration[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _TheoLiveConfiguration[key];
25
+ }
26
+ });
27
+ });
17
28
  //# sourceMappingURL=barrel.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_TheoLiveSource","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get"],"sourceRoot":"../../../../src","sources":["api/theolive/barrel.ts"],"mappings":";;;;;AAAA,IAAAA,eAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,eAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,eAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,eAAA,CAAAK,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
1
+ {"version":3,"names":["_TheoLiveSource","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_TheoLiveConfiguration"],"sourceRoot":"../../../../src","sources":["api/theolive/barrel.ts"],"mappings":";;;;;AAAA,IAAAA,eAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,eAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,eAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,eAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,sBAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,sBAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,sBAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,sBAAA,CAAAL,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":"8.13.0","buildDate":"2025-01-15T19:38:29.644Z"}
1
+ {"version":"8.14.0","buildDate":"2025-02-10T14:16:54.983Z"}
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=TheoLiveConfiguration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../../src","sources":["api/theolive/TheoLiveConfiguration.ts"],"mappings":"","ignoreList":[]}
@@ -1,2 +1,3 @@
1
1
  export * from './TheoLiveSource';
2
+ export * from './TheoLiveConfiguration';
2
3
  //# sourceMappingURL=barrel.js.map
@@ -1 +1 @@
1
- {"version":3,"names":[],"sourceRoot":"../../../../src","sources":["api/theolive/barrel.ts"],"mappings":"AAAA,cAAc,kBAAkB","ignoreList":[]}
1
+ {"version":3,"names":[],"sourceRoot":"../../../../src","sources":["api/theolive/barrel.ts"],"mappings":"AAAA,cAAc,kBAAkB;AAChC,cAAc,yBAAyB","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":"8.13.0","buildDate":"2025-01-15T19:38:29.644Z"}
1
+ {"version":"8.14.0","buildDate":"2025-02-10T14:16:54.983Z"}
@@ -3,6 +3,7 @@ import type { CastConfiguration } from '../cast/CastConfiguration';
3
3
  import type { MediaControlConfiguration } from '../media/MediaControlConfiguration';
4
4
  import type { RetryConfiguration } from '../utils/RetryConfiguration';
5
5
  import type { UIConfiguration } from '../ui/UIConfiguration';
6
+ import { TheoLiveConfiguration } from '../theolive/TheoLiveConfiguration';
6
7
  export interface PlayerConfiguration {
7
8
  /**
8
9
  * The directory in which the THEOplayer library worker files are located.
@@ -93,6 +94,10 @@ export interface PlayerConfiguration {
93
94
  * @deprecated: THEOlive support is always enabled, there is no need to explicitly enable it.
94
95
  */
95
96
  enableTHEOlive?: boolean;
97
+ /**
98
+ * The THEOlive configuration for the player.
99
+ */
100
+ theoLive?: TheoLiveConfiguration;
96
101
  }
97
102
  /**
98
103
  * The muted autoplay policy of a player for web.
@@ -1 +1 @@
1
- {"version":3,"file":"PlayerConfiguration.d.ts","sourceRoot":"","sources":["../../../../src/api/config/PlayerConfiguration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,0BAA0B,CAAC;IAE3C;;OAEG;IACH,GAAG,CAAC,EAAE,gBAAgB,CAAC;IAEvB;;OAEG;IACH,IAAI,CAAC,EAAE,iBAAiB,CAAC;IAEzB;;OAEG;IACH,EAAE,CAAC,EAAE,eAAe,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,yBAAyB,CAAC;IAEzC;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAE7B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAEhC;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAEjD;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,0BAA0B,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC"}
1
+ {"version":3,"file":"PlayerConfiguration.d.ts","sourceRoot":"","sources":["../../../../src/api/config/PlayerConfiguration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,0BAA0B,CAAC;IAE3C;;OAEG;IACH,GAAG,CAAC,EAAE,gBAAgB,CAAC;IAEvB;;OAEG;IACH,IAAI,CAAC,EAAE,iBAAiB,CAAC;IAEzB;;OAEG;IACH,EAAE,CAAC,EAAE,eAAe,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,yBAAyB,CAAC;IAEzC;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAE7B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAEhC;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAEjD;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;OAEG;IACH,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,0BAA0B,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The configuration THEOlive playback.
3
+ *
4
+ * @public
5
+ */
6
+ export interface TheoLiveConfiguration {
7
+ /**
8
+ * An id used to report usage analytics, if not explicitly given a random UUID is used.
9
+ *
10
+ * @remarks
11
+ * <br/> - Available on Web and Android only.
12
+ */
13
+ readonly externalSessionId?: string;
14
+ /**
15
+ * Whether this player should fallback or not when it has a fallback configured.
16
+ *
17
+ * @remarks
18
+ * <br/> - Available on Web only.
19
+ */
20
+ readonly fallbackEnabled?: boolean;
21
+ /**
22
+ * An optional header that can be passed during discovery.
23
+ *
24
+ * @remarks
25
+ * <br/> - Available on Web only.
26
+ */
27
+ readonly discoveryHeader?: string;
28
+ /**
29
+ * Whether THEOlive analytics should be disabled or not.
30
+ *
31
+ * @remarks
32
+ * <br/> - Available on Android only.
33
+ *
34
+ * @defaultValue `false`
35
+ */
36
+ readonly analyticsDisabled?: boolean;
37
+ }
38
+ //# sourceMappingURL=TheoLiveConfiguration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TheoLiveConfiguration.d.ts","sourceRoot":"","sources":["../../../../src/api/theolive/TheoLiveConfiguration.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAEpC;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAEnC;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAElC;;;;;;;OAOG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CACtC"}
@@ -1,2 +1,3 @@
1
1
  export * from './TheoLiveSource';
2
+ export * from './TheoLiveConfiguration';
2
3
  //# sourceMappingURL=barrel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../../../../src/api/theolive/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"barrel.d.ts","sourceRoot":"","sources":["../../../../src/api/theolive/barrel.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-theoplayer",
3
- "version": "8.13.0",
3
+ "version": "8.14.0",
4
4
  "description": "A THEOplayer video component for react-native.",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "ios": {
3
- "features": ["GOOGLE_IMA", "CHROMECAST", "SIDELOADED_TEXTTRACKS"]
3
+ "features": ["GOOGLE_IMA", "CHROMECAST", "SIDELOADED_TEXTTRACKS", "THEO_ADS"]
4
4
  }
5
5
  }
@@ -25,7 +25,7 @@ Pod::Spec.new do |s|
25
25
  s.platforms = { :ios => "13.4", :tvos => "13.4" }
26
26
  s.source = { :git => "https://www.theoplayer.com/.git", :tag => "#{s.version}" }
27
27
 
28
- s.source_files = 'ios/*.{h,m,swift}', 'ios/ads/*.swift', 'ios/casting/*.swift', 'ios/contentprotection/*.swift', 'ios/pip/*.swift', 'ios/backgroundAudio/*.swift', 'ios/cache/*.swift', 'ios/sideloadedMetadata/*.swift', 'ios/eventBroadcasting/*.swift' , 'ios/ui/*.swift', 'ios/presentationMode/*.swift', 'ios/viewController/*.swift', 'ios/theolive/*.swift'
28
+ s.source_files = 'ios/*.{h,m,swift}', 'ios/ads/*.swift', 'ios/casting/*.swift', 'ios/contentprotection/*.swift', 'ios/pip/*.swift', 'ios/backgroundAudio/*.swift', 'ios/cache/*.swift', 'ios/sideloadedMetadata/*.swift', 'ios/eventBroadcasting/*.swift' , 'ios/ui/*.swift', 'ios/presentationMode/*.swift', 'ios/viewController/*.swift', 'ios/theolive/*.swift', 'ios/theoAds/*.swift'
29
29
  s.resources = ['ios/*.css']
30
30
 
31
31
  # ReactNative Dependency
@@ -50,6 +50,11 @@ Pod::Spec.new do |s|
50
50
  s.ios.dependency "THEOplayer-Integration-GoogleCast", "~> 8.6"
51
51
  end
52
52
 
53
+ if theofeatures.include?("THEO_ADS")
54
+ puts "Adding THEOplayer-Integration-THEOads"
55
+ s.dependency "THEOplayer-Integration-THEOads", "~> 8.6"
56
+ end
57
+
53
58
  if theofeatures.include?("SIDELOADED_TEXTTRACKS")
54
59
  puts "Adding THEOplayer-Connector-SideloadedSubtitle"
55
60
  s.dependency "THEOplayer-Connector-SideloadedSubtitle", "~> 8.6"
@@ -3,6 +3,7 @@ import type { CastConfiguration } from '../cast/CastConfiguration';
3
3
  import type { MediaControlConfiguration } from '../media/MediaControlConfiguration';
4
4
  import type { RetryConfiguration } from '../utils/RetryConfiguration';
5
5
  import type { UIConfiguration } from '../ui/UIConfiguration';
6
+ import { TheoLiveConfiguration } from '../theolive/TheoLiveConfiguration';
6
7
 
7
8
  export interface PlayerConfiguration {
8
9
  /**
@@ -107,6 +108,11 @@ export interface PlayerConfiguration {
107
108
  * @deprecated: THEOlive support is always enabled, there is no need to explicitly enable it.
108
109
  */
109
110
  enableTHEOlive?: boolean;
111
+
112
+ /**
113
+ * The THEOlive configuration for the player.
114
+ */
115
+ theoLive?: TheoLiveConfiguration;
110
116
  }
111
117
 
112
118
  /**
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The configuration THEOlive playback.
3
+ *
4
+ * @public
5
+ */
6
+ export interface TheoLiveConfiguration {
7
+ /**
8
+ * An id used to report usage analytics, if not explicitly given a random UUID is used.
9
+ *
10
+ * @remarks
11
+ * <br/> - Available on Web and Android only.
12
+ */
13
+ readonly externalSessionId?: string;
14
+
15
+ /**
16
+ * Whether this player should fallback or not when it has a fallback configured.
17
+ *
18
+ * @remarks
19
+ * <br/> - Available on Web only.
20
+ */
21
+ readonly fallbackEnabled?: boolean;
22
+
23
+ /**
24
+ * An optional header that can be passed during discovery.
25
+ *
26
+ * @remarks
27
+ * <br/> - Available on Web only.
28
+ */
29
+ readonly discoveryHeader?: string;
30
+
31
+ /**
32
+ * Whether THEOlive analytics should be disabled or not.
33
+ *
34
+ * @remarks
35
+ * <br/> - Available on Android only.
36
+ *
37
+ * @defaultValue `false`
38
+ */
39
+ readonly analyticsDisabled?: boolean;
40
+ }
@@ -1 +1,2 @@
1
1
  export * from './TheoLiveSource';
2
+ export * from './TheoLiveConfiguration';
package/src/manifest.json CHANGED
@@ -1 +1 @@
1
- {"version":"8.13.0","buildDate":"2025-01-15T19:38:29.644Z"}
1
+ {"version":"8.14.0","buildDate":"2025-02-10T14:16:54.983Z"}