diff --git a/CHANGELOG.md b/CHANGELOG.md
index c17e13bca..90843e746 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
+### Added
+
+- Added support for the customData property on the Ad and AdBreak types.
+
### Fixed
- Fixed an issue on iOS where sideloaded texttracks were not stored for cached playout.
diff --git a/android/src/main/java/com/theoplayer/ads/AdAdapter.kt b/android/src/main/java/com/theoplayer/ads/AdAdapter.kt
index e003c864c..b8e62a990 100644
--- a/android/src/main/java/com/theoplayer/ads/AdAdapter.kt
+++ b/android/src/main/java/com/theoplayer/ads/AdAdapter.kt
@@ -12,6 +12,8 @@ import com.theoplayer.android.api.ads.CompanionAd
import com.theoplayer.android.api.ads.ima.GoogleImaAd
import com.theoplayer.android.api.ads.UniversalAdId
import com.theoplayer.android.api.event.ads.AdIntegrationKind
+import com.theoplayer.util.BridgeUtils
+import org.json.JSONObject
import java.lang.Exception
private const val PROP_AD_SYSTEM = "adSystem"
@@ -49,6 +51,7 @@ private const val PROP_COMPANION_HEIGHT = "height"
private const val PROP_COMPANION_RESOURCEURI = "resourceURI"
private const val PROP_UNIVERSAL_AD_ID_REGISTRY = "adIdRegistry"
private const val PROP_UNIVERSAL_AD_ID_VALUE = "adIdValue"
+private const val PROP_CUSTOM_DATA = "customData"
private const val INVALID_DOUBLE = -1.0
private const val INVALID_INT = -1
@@ -130,6 +133,12 @@ object AdAdapter {
}
adPayload.putArray(PROP_AD_WRAPPER_CREATIVE_IDS, wrapperCreativeIdsPayload)
}
+ val customData = ad.customData
+ if (customData is JSONObject) {
+ adPayload.putMap(PROP_CUSTOM_DATA, BridgeUtils.fromJSONObjectToBridge(customData))
+ } else if (customData is Map<*, *>) {
+ adPayload.putMap(PROP_CUSTOM_DATA, BridgeUtils.fromJSONObjectToBridge(JSONObject(customData)))
+ }
return adPayload
}
@@ -146,6 +155,12 @@ object AdAdapter {
adbreakPayload.putInt(PROP_ADBREAK_MAXDURATION,adbreak.maxDuration)
adbreakPayload.putInt(PROP_ADBREAK_TIMEOFFSET, adbreak.timeOffset)
adbreakPayload.putDouble(PROP_ADBREAK_MAXREMAININGDURATION, adbreak.maxRemainingDuration)
+ val customData = adbreak.customData
+ if (customData is JSONObject) {
+ adbreakPayload.putMap(PROP_CUSTOM_DATA, BridgeUtils.fromJSONObjectToBridge(customData))
+ } else if (customData is Map<*, *>) {
+ adbreakPayload.putMap(PROP_CUSTOM_DATA, BridgeUtils.fromJSONObjectToBridge(JSONObject(customData)))
+ }
val adsPayload = Arguments.createArray()
for (ad in adbreak.ads) {
// Some ads in the ad break are possibly not loaded yet.
diff --git a/android/src/main/java/com/theoplayer/util/BridgeUtils.kt b/android/src/main/java/com/theoplayer/util/BridgeUtils.kt
index e80dae236..c7ec99d44 100644
--- a/android/src/main/java/com/theoplayer/util/BridgeUtils.kt
+++ b/android/src/main/java/com/theoplayer/util/BridgeUtils.kt
@@ -26,9 +26,10 @@ object BridgeUtils {
while (iterator.hasNext()) {
val key = iterator.next()
when (val value = json.opt(key)) {
-// null -> putNull(key)
+ null, JSONObject.NULL -> putNull(key)
is Boolean -> putBoolean(key, value)
is Int -> putInt(key, value)
+ is Long -> putDouble(key, value.toDouble())
is Double -> putDouble(key, value)
is String -> putString(key, value)
is JSONObject -> putMap(key, fromJSONObjectToBridge(value))
@@ -50,9 +51,10 @@ object BridgeUtils {
try {
for (i in 0 until jsonArray.length()) {
when (val value = jsonArray.opt(i)) {
-// null -> writableArray.pushNull()
+ null, JSONObject.NULL -> pushNull()
is Boolean -> pushBoolean(value)
is Int -> pushInt(value)
+ is Long -> pushDouble(value.toDouble())
is Double -> pushDouble(value)
is String -> pushString(value)
is JSONObject -> pushMap(fromJSONObjectToBridge(value))
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
index e87cb5269..f0f6b981a 100644
--- a/example/ios/Podfile.lock
+++ b/example/ios/Podfile.lock
@@ -2,13 +2,13 @@ PODS:
- DSFRegex (3.3.1)
- FBLazyVector (0.84.1-0)
- google-cast-sdk-dynamic-xcframework (4.8.3)
- - GoogleAds-IMA-iOS-SDK (3.31.0)
- - GoogleAds-IMA-tvOS-SDK (4.16.0)
+ - GoogleAds-IMA-iOS-SDK (3.32.0)
+ - GoogleAds-IMA-tvOS-SDK (4.17.0)
- hermes-engine (250829098.0.9):
- hermes-engine/Pre-built (= 250829098.0.9)
- hermes-engine/Pre-built (250829098.0.9)
- - MillicastSDK (2.5.3)
- - PromisesObjC (2.4.0)
+ - MillicastSDK (2.6.0)
+ - PromisesObjC (2.4.1)
- RCTDeprecation (0.84.1-0)
- RCTRequired (0.84.1-0)
- RCTSwiftUI (0.84.1-0)
@@ -1484,15 +1484,15 @@ PODS:
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- - react-native-theoplayer (11.0.0):
+ - react-native-theoplayer (11.4.0):
- React-Core
- - THEOplayer-Connector-SideloadedSubtitle (~> 11.0)
- - THEOplayer-Integration-GoogleCast (~> 11.0)
- - THEOplayer-Integration-GoogleIMA (~> 11.0)
- - THEOplayer-Integration-Millicast (~> 11.0)
- - THEOplayer-Integration-THEOads (~> 11.0)
- - THEOplayer-Integration-THEOlive (~> 11.0)
- - THEOplayerSDK-core (~> 11.0)
+ - THEOplayer-Connector-SideloadedSubtitle (> 11.0.1, ~> 11.0)
+ - THEOplayer-Integration-GoogleCast (~> 11.4)
+ - THEOplayer-Integration-GoogleIMA (~> 11.4)
+ - THEOplayer-Integration-Millicast (~> 11.4)
+ - THEOplayer-Integration-THEOads (~> 11.4)
+ - THEOplayer-Integration-THEOlive (~> 11.4)
+ - THEOplayerSDK-core (~> 11.4)
- React-NativeModulesApple (0.84.1-0):
- hermes-engine
- React-callinvoker
@@ -1927,40 +1927,40 @@ PODS:
- SwiftSubtitles (0.9.1):
- DSFRegex (~> 3.3.1)
- TinyCSV (~> 0.6.1)
- - THEOplayer-Connector-SideloadedSubtitle (11.0.1):
+ - THEOplayer-Connector-SideloadedSubtitle (11.0.3):
- Swifter (= 1.5.0)
- SwiftSubtitles (= 0.9.1)
- THEOplayerSDK-core (~> 11)
- - THEOplayer-Integration-GoogleCast (11.0.0):
- - THEOplayer-Integration-GoogleCast/Base (= 11.0.0)
- - THEOplayer-Integration-GoogleCast/Dependencies (= 11.0.0)
- - THEOplayer-Integration-GoogleCast/Base (11.0.0)
- - THEOplayer-Integration-GoogleCast/Dependencies (11.0.0):
+ - THEOplayer-Integration-GoogleCast (11.7.0):
+ - THEOplayer-Integration-GoogleCast/Base (= 11.7.0)
+ - THEOplayer-Integration-GoogleCast/Dependencies (= 11.7.0)
+ - THEOplayer-Integration-GoogleCast/Base (11.7.0)
+ - THEOplayer-Integration-GoogleCast/Dependencies (11.7.0):
- google-cast-sdk-dynamic-xcframework (~> 4.8)
- - THEOplayer-Integration-GoogleIMA (11.0.0):
- - THEOplayer-Integration-GoogleIMA/Base (= 11.0.0)
- - THEOplayer-Integration-GoogleIMA/Dependencies (= 11.0.0)
- - THEOplayer-Integration-GoogleIMA/Base (11.0.0)
- - THEOplayer-Integration-GoogleIMA/Dependencies (11.0.0):
+ - THEOplayer-Integration-GoogleIMA (11.7.0):
+ - THEOplayer-Integration-GoogleIMA/Base (= 11.7.0)
+ - THEOplayer-Integration-GoogleIMA/Dependencies (= 11.7.0)
+ - THEOplayer-Integration-GoogleIMA/Base (11.7.0)
+ - THEOplayer-Integration-GoogleIMA/Dependencies (11.7.0):
+ - GoogleAds-IMA-iOS-SDK (~> 3.31)
+ - GoogleAds-IMA-tvOS-SDK (~> 4.16)
+ - THEOplayer-Integration-Millicast (11.7.0):
+ - THEOplayer-Integration-Millicast/Base (= 11.7.0)
+ - THEOplayer-Integration-Millicast/Dependencies (= 11.7.0)
+ - THEOplayer-Integration-Millicast/Base (11.7.0)
+ - THEOplayer-Integration-Millicast/Dependencies (11.7.0):
+ - MillicastSDK (~> 2.6.0)
+ - THEOplayer-Integration-THEOads (11.7.0):
+ - THEOplayer-Integration-THEOads/Base (= 11.7.0)
+ - THEOplayer-Integration-THEOads/Dependencies (= 11.7.0)
+ - THEOplayer-Integration-THEOads/Base (11.7.0)
+ - THEOplayer-Integration-THEOads/Dependencies (11.7.0):
- GoogleAds-IMA-iOS-SDK (~> 3.18)
- GoogleAds-IMA-tvOS-SDK (~> 4.8)
- - THEOplayer-Integration-Millicast (11.0.0):
- - THEOplayer-Integration-Millicast/Base (= 11.0.0)
- - THEOplayer-Integration-Millicast/Dependencies (= 11.0.0)
- - THEOplayer-Integration-Millicast/Base (11.0.0)
- - THEOplayer-Integration-Millicast/Dependencies (11.0.0):
- - MillicastSDK (= 2.5.3)
- - THEOplayer-Integration-THEOads (11.0.0):
- - THEOplayer-Integration-THEOads/Base (= 11.0.0)
- - THEOplayer-Integration-THEOads/Dependencies (= 11.0.0)
- - THEOplayer-Integration-THEOads/Base (11.0.0)
- - THEOplayer-Integration-THEOads/Dependencies (11.0.0):
- - GoogleAds-IMA-iOS-SDK (~> 3.18)
- - GoogleAds-IMA-tvOS-SDK (~> 4.8)
- - THEOplayer-Integration-THEOlive (11.0.0):
- - THEOplayer-Integration-THEOlive/Base (= 11.0.0)
- - THEOplayer-Integration-THEOlive/Base (11.0.0)
- - THEOplayerSDK-core (11.0.0)
+ - THEOplayer-Integration-THEOlive (11.7.0):
+ - THEOplayer-Integration-THEOlive/Base (= 11.7.0)
+ - THEOplayer-Integration-THEOlive/Base (11.7.0)
+ - THEOplayerSDK-core (11.7.0)
- TinyCSV (0.6.1)
- Yoga (0.0.0)
@@ -2230,11 +2230,11 @@ SPEC CHECKSUMS:
DSFRegex: 8493187c71ac199695245eb9ec98bad4f87a2f0b
FBLazyVector: a3651a4af13997df8df1bcd5af1cc7507d51dc7b
google-cast-sdk-dynamic-xcframework: d4dd8d548462f2a4874515fee68c17805d44be42
- GoogleAds-IMA-iOS-SDK: 5d0df4a9213f7f40431cd1779fd1b0cc7788d4ae
- GoogleAds-IMA-tvOS-SDK: ddbb7e717e90fecb7384066d11d7b10f002ca765
+ GoogleAds-IMA-iOS-SDK: b1b1e3b8f486cfb7c7a669a58a5380421f3bcaab
+ GoogleAds-IMA-tvOS-SDK: e43d2ddd224b04b910e42aeb5655380af56976eb
hermes-engine: 76cc5f7b150dc2db4b5d7f680e27fecbe8f3e320
- MillicastSDK: 49379c892ccc2e3d00c1a4d4adbf6ccfc2a42855
- PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
+ MillicastSDK: 690470f2108b5d67288babbebbee36c2cf196b4b
+ PromisesObjC: 752c3227f599e3467650e47ea36f433eeb10c273
RCTDeprecation: e1d3de84bd12761f1a42ae433c805c84ce3e1447
RCTRequired: 5f75a4215a8c9551b303a95b0394968ae7490f18
RCTSwiftUI: 6cfd2a6b1506648cd96493d252069bd1b49bdea4
@@ -2273,7 +2273,7 @@ SPEC CHECKSUMS:
React-microtasksnativemodule: eb714fe3d21e607954699ad1dc20dc11c0221bc8
react-native-google-cast: d7bdfd1a0eeba84afde03b9722351ec29543e74c
react-native-safe-area-context: 53f796cb6c814661bbe99fbdfd0585d07b996cdd
- react-native-theoplayer: f4bbf4433389532e99e9952698915863ea9efeeb
+ react-native-theoplayer: 28c48dcad70e374a1c234e7e889333411cc7f355
React-NativeModulesApple: c0f757b1de3a519a0ecd506ee4667c6c50dfcaf7
React-networking: 2895e61b9fb4e6cd681a319e060c79d80865faf3
React-oscompat: 2124e2fc8f45ded3d1f2b2aa4ac913f2e9c0f842
@@ -2311,13 +2311,13 @@ SPEC CHECKSUMS:
RNSVG: ab21c7dd854210d72d228737b7ddda1c6c0b5256
Swifter: e71dd674404923d7f03ebb03f3f222d1c570bc8e
SwiftSubtitles: c659af19d710a2946779015464c0577d07fe4666
- THEOplayer-Connector-SideloadedSubtitle: bfbe2f5abcc28677f3887b752811a5a115c90b7d
- THEOplayer-Integration-GoogleCast: bdc8ffaa54fec3d9f511300f4133fc38aaf12826
- THEOplayer-Integration-GoogleIMA: eb7be0e716014a4ca6d6c61966bd396bbd448c2f
- THEOplayer-Integration-Millicast: b214b7b0158d8c133324b280bc0c79abbbfc6467
- THEOplayer-Integration-THEOads: 97c43e9b01dd77dd5f48cd850f8a6e45261cfcf7
- THEOplayer-Integration-THEOlive: d0ca496ec0a3326b615f108c0b953b712ca5c574
- THEOplayerSDK-core: e6505e392563404145fdb2d418781c6260860643
+ THEOplayer-Connector-SideloadedSubtitle: 1829b0f9817949fc5ad7ebc927e2828238eebcc0
+ THEOplayer-Integration-GoogleCast: bd42dd7f64223ef7a6852c8318e32ae414ea982c
+ THEOplayer-Integration-GoogleIMA: d16edfd8331147770d63d34b1e5b468300323bbc
+ THEOplayer-Integration-Millicast: 9077a7ddb728ddd237b0d4b07efa9e99c4fd09ac
+ THEOplayer-Integration-THEOads: a802035d171315d6e691f74af6ef08b85a8cb0d8
+ THEOplayer-Integration-THEOlive: 27a29d5b0c94dddd0664c272b2adcfc60ddca312
+ THEOplayerSDK-core: 40ee41ad6303f732ba0fb48902b5f69dff79f8be
TinyCSV: fd6228edbcf1c07466ac34b76dac5e052143eaba
Yoga: e2029bb72b7cb951e09aa1ee1316c9f5f28409da
diff --git a/example/package-lock.json b/example/package-lock.json
index cc7a7c818..08e076b52 100644
--- a/example/package-lock.json
+++ b/example/package-lock.json
@@ -51,7 +51,7 @@
}
},
"..": {
- "version": "11.1.0",
+ "version": "11.4.0",
"license": "BSD-3-Clause-Clear",
"dependencies": {
"@theoplayer/cmcd-connector-web": "^1.5.0",
diff --git a/ios/ads/THEOplayerRCTAdAdapter.swift b/ios/ads/THEOplayerRCTAdAdapter.swift
index 31bfbac45..e62d66051 100644
--- a/ios/ads/THEOplayerRCTAdAdapter.swift
+++ b/ios/ads/THEOplayerRCTAdAdapter.swift
@@ -34,6 +34,7 @@ let PROP_ADBREAK_MAX_REMAINING_DURATION: String = "maxRemainingDuration"
let PROP_ADBREAK_ADS: String = "ads"
let PROP_ADBREAK_INTEGRATION: String = "integration"
let PROP_ADBREAK_CUSTOM_INTEGRATION: String = "customIntegration"
+let PROP_CUSTOM_DATA: String = "customData"
let PROP_COMPANION_AD_SLOT_ID: String = "adSlotId"
let PROP_COMPANION_ALT_TEXT: String = "altText"
let PROP_COMPANION_CLICK_THROUGH: String = "clickThrough"
@@ -49,6 +50,9 @@ class THEOplayerRCTAdAdapter {
if let customIntegration = ad.customIntegration {
adData[PROP_AD_CUSTOM_INTEGRATION] = customIntegration
}
+ if let customData = ad.customData {
+ adData[PROP_CUSTOM_DATA] = customData
+ }
adData[PROP_AD_TYPE] = ad.type
if let adId = ad.id {
adData[PROP_AD_ID] = adId
@@ -180,6 +184,9 @@ class THEOplayerRCTAdAdapter {
adBreakData[PROP_ADBREAK_MAX_REMAINING_DURATION] = adBreak.maxRemainingDuration
adBreakData[PROP_ADBREAK_INTEGRATION] = adBreak.integration
adBreakData[PROP_ADBREAK_CUSTOM_INTEGRATION] = adBreak.customIntegration
+ if let customData = adBreak.customData {
+ adBreakData[PROP_CUSTOM_DATA] = customData
+ }
// process adds when adbreak contains them
if !adBreak.ads.isEmpty {
var adList: [[String:Any]] = []
diff --git a/ios/ads/THEOplayerRCTAdsNative.swift b/ios/ads/THEOplayerRCTAdsNative.swift
index 151f2ec16..7f16d6b07 100644
--- a/ios/ads/THEOplayerRCTAdsNative.swift
+++ b/ios/ads/THEOplayerRCTAdsNative.swift
@@ -30,6 +30,8 @@ class NativeAd: THEOplayerSDK.Ad {
var clickThrough: String? = nil
/**The type of custom ad integration.*/
var customIntegration: String? = nil
+ /** Additional integration-specific data associated with this ad.*/
+ var customData: [String: Any]? = nil
init(adBreak: AdBreak, companions: [THEOplayerSDK.CompanionAd], type: String, id: String? = nil, skipOffset: Int? = nil, resourceURI: String? = nil, width: Int? = nil, height: Int? = nil, isSlate: Bool = false, integration: THEOplayerSDK.AdIntegrationKind, duration: Int? = 0, clickThrough: String?, customIntegration: String?) {
self.adBreak = adBreak
@@ -134,6 +136,8 @@ class NativeAdBreak: THEOplayerSDK.AdBreak {
- For other integrations, this may be `nil`.
*/
var id: String? = nil
+ /** Additional integration-specific data associated with this ad break.*/
+ var customData: [String: Any]? = nil
init(ads: [Ad], id: String? = nil, maxDuration: Int, maxRemainingDuration: Double, timeOffset: Int, integration: THEOplayerSDK.AdIntegrationKind, customIntegration: String? = nil) {
self.ads = ads
diff --git a/src/api/ads/Ad.ts b/src/api/ads/Ad.ts
index 0ffaf0ea0..0601f1771 100644
--- a/src/api/ads/Ad.ts
+++ b/src/api/ads/Ad.ts
@@ -129,6 +129,14 @@ export interface Ad {
*
- Only supported for `'theo'` and `'google-ima'`.
*/
universalAdIds: UniversalAdId[];
+
+ /**
+ * Additional integration-specific data associated with this ad.
+ *
+ * @remarks
+ *
- The value depends on the ad integration. It may be `undefined` if the integration does not provide any custom data.
+ */
+ customData?: Record;
}
/**
diff --git a/src/api/ads/AdBreak.ts b/src/api/ads/AdBreak.ts
index aa0712a3e..b9b22dc19 100644
--- a/src/api/ads/AdBreak.ts
+++ b/src/api/ads/AdBreak.ts
@@ -56,4 +56,12 @@ export interface AdBreak {
*
- This feature is not available in the Google IMA integration and will default to -1.
*/
maxRemainingDuration: number | undefined;
+
+ /**
+ * Additional integration-specific data associated with this ad break.
+ *
+ * @remarks
+ *
- The value depends on the ad integration. It may be `undefined` if the integration does not provide any custom data.
+ */
+ customData?: Record;
}