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; }