From 8bf70eda9ee2996c88f8c3561fbb37daa1d7bd40 Mon Sep 17 00:00:00 2001 From: Jono Sligh Date: Wed, 14 Feb 2024 10:12:56 -0600 Subject: [PATCH 1/4] Starting on proposed changes for 877 --- PrebidMobile/AdUnits/AdUnit.swift | 10 ++++ .../MultiformatAdUnit/PrebidRequest.swift | 1 + .../AdTypes/AdView/AdConfiguration.swift | 8 +++ .../ORTB/PBMORTBBidRequest.h | 4 ++ .../ORTB/PBMORTBBidRequest.m | 56 +++++++++++++++++++ .../Prebid/Integrations/GAM/BannerView.swift | 5 ++ .../GAM/BaseInterstitialAdUnit.swift | 5 ++ .../MediationAPI/MediationBannerAdUnit.swift | 5 ++ .../MediationBaseInterstitialAdUnit.swift | 5 ++ .../MediationAPI/MediationNativeAdUnit.swift | 8 +++ .../Prebid/PBMCore/AdUnitConfig.swift | 15 ++++- 11 files changed, 121 insertions(+), 1 deletion(-) diff --git a/PrebidMobile/AdUnits/AdUnit.swift b/PrebidMobile/AdUnits/AdUnit.swift index b40f2aa9c..9d1358942 100644 --- a/PrebidMobile/AdUnits/AdUnit.swift +++ b/PrebidMobile/AdUnits/AdUnit.swift @@ -387,6 +387,16 @@ public class AdUnit: NSObject, DispatcherDelegate { return adUnitConfig.gpid } + // MARK: Global ORTBObject + + public func setOrtbConfig(_ ortbObject: String?) { + adUnitConfig.ortbConfig = ortbObject + } + + public func getOrtbConfig() -> String? { + return adUnitConfig.ortbConfig + } + // MARK: - others /** diff --git a/PrebidMobile/AdUnits/MultiformatAdUnit/PrebidRequest.swift b/PrebidMobile/AdUnits/MultiformatAdUnit/PrebidRequest.swift index ce43ed397..ea1238b20 100644 --- a/PrebidMobile/AdUnits/MultiformatAdUnit/PrebidRequest.swift +++ b/PrebidMobile/AdUnits/MultiformatAdUnit/PrebidRequest.swift @@ -28,6 +28,7 @@ public class PrebidRequest: NSObject { private(set) var isRewarded = false private(set) var gpid: String? + private(set) var ortbConfig: String? // MARK: - Private properties diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift index a335cb37d..ed918864b 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift @@ -125,4 +125,12 @@ public class AdConfiguration: AutoRefreshCountConfig { // MARK: Private properties private var _autoRefreshDelay: TimeInterval? = PBMAutoRefresh.AUTO_REFRESH_DELAY_DEFAULT + + public var ortbConfig: String? + + func getCheckedOrtbConfig() -> [String: Any]? { + + return [:] + } + } diff --git a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.h b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.h index 7657bfd28..e54c940b7 100644 --- a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.h +++ b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.h @@ -135,6 +135,10 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong) PBMORTBBidRequestExtPrebid *extPrebid; +@property (nonatomic, strong, nullable) NSDictionary *arbitraryJsonConfig; + +@property (nonatomic, strong, nullable) NSString *ortbObject; + - (instancetype)init; @end diff --git a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m index d8299b584..23918187a 100644 --- a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m +++ b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m @@ -67,7 +67,63 @@ - (nonnull PBMJsonDictionary *)toJsonDictionary { PBMMutableJsonDictionary * const ext = [PBMMutableJsonDictionary new]; ext[@"prebid"] = [[self.extPrebid toJsonDictionary] nullIfEmpty]; ret[@"ext"] = [[ext pbmCopyWithoutEmptyVals] nullIfEmpty]; + + //remove "protected" fields from ortbObject then do a merge but merge ret into the ortbObject (addEntriesFromDictionary) + NSMutableDictionary *arbitraryServerConfig = [self.arbitraryJsonConfig mutableCopy]; + + if (arbitraryServerConfig[@"regs"]) { + arbitraryServerConfig[@"regs"] = nil; + } + if (arbitraryServerConfig[@"device"]) { + arbitraryServerConfig[@"device"] = nil; + } + if (arbitraryServerConfig[@"geo"]) { + arbitraryServerConfig[@"geo"] = nil; + } + //merge with config from API/JSON + ret = [self mergeDictionaries: ret joiningArgument2: arbitraryServerConfig joiningArgument3: false]; + + NSMutableDictionary *o2 = [self.ortbObject mutableCopy]; + + if (o2[@"regs"]) { + o2[@"regs"] = nil; + } + if (o2[@"device"]) { + o2[@"device"] = nil; + } + if (o2[@"geo"]) { + o2[@"geo"] = nil; + } + //merge with ortbConfig from SDK + ret = [self mergeDictionaries: ret joiningArgument2: o2 joiningArgument3: true]; + + ret = [ret pbmCopyWithoutEmptyVals]; + return ret; +} + +- (nonnull PBMMutableJsonDictionary *)mergeDictionaries:(NSMutableDictionary*)dictionary1 joiningArgument2:(NSMutableDictionary*)dictionary2 + joiningArgument3:(Boolean)firstHasPriority{ + PBMMutableJsonDictionary *ret = dictionary1; + + for (id key in dictionary2) + if ([ret objectForKey: key]){ + if ([[ret objectForKey: key] isKindOfClass: [NSDictionary class]]) { + //if is dictionary, need to call this method recursively for ret object for key and dictionary2 for key + [ret setObject:[self mergeDictionaries:[ret objectForKey: key] joiningArgument2: [dictionary2 objectForKey: key] joiningArgument3:firstHasPriority] forKey: key]; + } else if ([[ret objectForKey: key] isKindOfClass: [NSArray class]] && [[dictionary2 objectForKey: key] isKindOfClass: [NSArray class]]) { + //merge arrays + NSArray *mergedArray = [[ret objectForKey: key] arrayByAddingObjectsFromArray: [dictionary2 objectForKey: key]]; + //remove duplicates and set + [ret setObject:[mergedArray valueForKeyPath:@"@distinctUnionOfObjects.self"] forKey:key]; + } else { + if (!firstHasPriority) { + [ret setObject:[dictionary2 objectForKey: key] forKey:key]; + } + } + } else { + [ret setObject:[dictionary2 objectForKey:key] forKey: key]; + } ret = [ret pbmCopyWithoutEmptyVals]; return ret; diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BannerView.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BannerView.swift index 44d2fe020..82a1cefa1 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BannerView.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BannerView.swift @@ -64,6 +64,11 @@ public class BannerView: UIView, set { adUnitConfig.adPosition = newValue } } + @objc public var ortbConfig: String? { + get { adUnitConfig.ortbConfig } + set { adUnitConfig.ortbConfig = newValue } + } + @objc public weak var delegate: BannerViewDelegate? // MARK: Readonly storage diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift index 512ba7815..796d93ef1 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift @@ -46,6 +46,11 @@ public class BaseInterstitialAdUnit : get { adUnitConfig.adFormats } set { adUnitConfig.adFormats = newValue } } + + @objc public var ortbConfig: String? { + get { adUnitConfig.ortbConfig } + set { adUnitConfig.ortbConfig = newValue } + } @objc public var isReady: Bool { objc_sync_enter(blocksLockToken) diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationBannerAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationBannerAdUnit.swift index e3f708acf..ffe318625 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationBannerAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationBannerAdUnit.swift @@ -70,6 +70,11 @@ public class MediationBannerAdUnit : NSObject { set { adUnitConfig.additionalSizes = newValue } } + public var ortbConfig: String? { + get { adUnitConfig.ortbConfig } + set { adUnitConfig.ortbConfig = newValue } + } + // MARK: - Ext Data (imp[].ext.data) @available(*, deprecated, message: "This method is deprecated. Please, use addExtData method instead.") diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationBaseInterstitialAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationBaseInterstitialAdUnit.swift index 1c148666b..0e153ec81 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationBaseInterstitialAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationBaseInterstitialAdUnit.swift @@ -45,6 +45,11 @@ public class MediationBaseInterstitialAdUnit : NSObject { set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition = newValue } } + public var ortbConfig: String? { + get { adUnitConfig.ortbConfig } + set { adUnitConfig.ortbConfig = newValue } + } + let adUnitConfig: AdUnitConfig public var configId: String { diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationNativeAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationNativeAdUnit.swift index 2cfaaf405..2ac556bc3 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationNativeAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationNativeAdUnit.swift @@ -78,6 +78,14 @@ public class MediationNativeAdUnit : NSObject { public func setExt(_ ext: [String: Any]) { nativeAdUnit.ext = ext } + + public func getOrtbConfig() -> String? { + return nativeAdUnit.getOrtbConfig() + } + + public func setOrtbConfig(_ ortbConfig: String?) { + nativeAdUnit.setOrtbConfig(ortbConfig) + } // MARK: - App Content (app.content.data) diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift index dae70398e..b6a3ccee8 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift @@ -79,7 +79,20 @@ public class AdUnitConfig: NSObject, NSCopying { } public var gpid: String? - + + public var ortbConfig: String? { + get {adConfiguration.ortbConfig} + set {adConfiguration.ortbConfig = newValue} + } + +// if let unwrappedNewValue = newValue { +// if (JSONSerialization.isValidJSONObject(unwrappedNewValue.data(using: String.Encoding.utf8) as Any)) { +// adConfiguration.ortbConfig = unwrappedNewValue +// } else { +// Log.warn("The provided ortbConfig object is not valid JSON and therefore will be ignored.") +// } +// } + // MARK: - Public Methods public convenience init(configId: String) { From 5952b4e4d7567335a9e4be174c7cf1f8109a33bc Mon Sep 17 00:00:00 2001 From: Jono Sligh Date: Wed, 14 Feb 2024 13:13:28 -0600 Subject: [PATCH 2/4] Just need to test. --- .../AdTypes/AdView/AdConfiguration.swift | 13 ++++- .../Parameters/PBMParameterBuilderService.m | 2 +- .../ORTB/PBMORTBBidRequest.h | 2 +- .../ORTB/PBMORTBBidRequest.m | 54 ++++++++++--------- .../Prebid/PBMCore/AdUnitConfig.swift | 10 +--- 5 files changed, 42 insertions(+), 39 deletions(-) diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift index ed918864b..5ec69b4e7 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift @@ -128,8 +128,17 @@ public class AdConfiguration: AutoRefreshCountConfig { public var ortbConfig: String? - func getCheckedOrtbConfig() -> [String: Any]? { - + public func getCheckedOrtbConfig() -> [String: Any]? { + //return ortbConfig in dictionary form after checking if it's valid json + if let jsonString = ortbConfig { + if let data = jsonString.data(using: .utf8) { + do { + return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] + } catch { + Log.warn("The provided ortbConfig object is not valid JSON and will be ignored.") + } + } + } return [:] } diff --git a/PrebidMobile/PrebidMobileRendering/Networking/Parameters/PBMParameterBuilderService.m b/PrebidMobile/PrebidMobileRendering/Networking/Parameters/PBMParameterBuilderService.m index 2a8ec47b1..be500459d 100644 --- a/PrebidMobile/PrebidMobileRendering/Networking/Parameters/PBMParameterBuilderService.m +++ b/PrebidMobile/PrebidMobileRendering/Networking/Parameters/PBMParameterBuilderService.m @@ -71,6 +71,7 @@ @implementation PBMParameterBuilderService extraParameterBuilders:(nullable NSArray > *)extraParameterBuilders{ PBMORTBBidRequest *bidRequest = [PBMParameterBuilderService createORTBBidRequestWithTargeting:targeting]; + bidRequest.ortbObject = [adConfiguration getCheckedOrtbConfig]; NSMutableArray > * const parameterBuilders = [[NSMutableArray alloc] init]; [parameterBuilders addObjectsFromArray:@[ [[PBMBasicParameterBuilder alloc] initWithAdConfiguration:adConfiguration @@ -98,7 +99,6 @@ @implementation PBMParameterBuilderService + (nonnull PBMORTBBidRequest *)createORTBBidRequestWithTargeting:(nonnull Targeting *)targeting { PBMORTBBidRequest *bidRequest = [PBMORTBBidRequest new]; - NSNumber * yob = [targeting getYearOfBirth]; if (![yob isEqual: @0]) { diff --git a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.h b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.h index e54c940b7..5ffe3c662 100644 --- a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.h +++ b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.h @@ -137,7 +137,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, nullable) NSDictionary *arbitraryJsonConfig; -@property (nonatomic, strong, nullable) NSString *ortbObject; +@property (nonatomic, strong, nullable) NSDictionary *ortbObject; - (instancetype)init; diff --git a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m index 23918187a..289180efb 100644 --- a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m +++ b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m @@ -52,9 +52,19 @@ - (nonnull PBMJsonDictionary *)toJsonDictionary { for (PBMORTBImp *imp in self.imp) { [impressions addObject:[imp toJsonDictionary]]; } + //set impressions and ext beforehand so they are not overridden by arbitrary params from API/JSON + ret[@"imp"] = impressions; + PBMMutableJsonDictionary * const ext = [PBMMutableJsonDictionary new]; + ext[@"prebid"] = [[self.extPrebid toJsonDictionary] nullIfEmpty]; + ret[@"ext"] = [[ext pbmCopyWithoutEmptyVals] nullIfEmpty]; + + //remove "protected" fields from ortbObject then do a merge but merge ret into the ortbObject (addEntriesFromDictionary) + NSMutableDictionary *arbitraryServerConfig = [self.arbitraryJsonConfig mutableCopy]; + + //merge with config from API/JSON with priority from server + ret = [self mergeDictionaries: ret joiningArgument2: arbitraryServerConfig joiningArgument3: false]; ret[@"id"] = self.requestID; - ret[@"imp"] = impressions; ret[@"app"] = [[self.app toJsonDictionary] nullIfEmpty]; ret[@"device"] = [[self.device toJsonDictionary] nullIfEmpty]; @@ -64,38 +74,30 @@ - (nonnull PBMJsonDictionary *)toJsonDictionary { ret[@"regs"] = [[self.regs toJsonDictionary] nullIfEmpty]; ret[@"source"] = [[self.source toJsonDictionary] nullIfEmpty]; - PBMMutableJsonDictionary * const ext = [PBMMutableJsonDictionary new]; - ext[@"prebid"] = [[self.extPrebid toJsonDictionary] nullIfEmpty]; - ret[@"ext"] = [[ext pbmCopyWithoutEmptyVals] nullIfEmpty]; - - //remove "protected" fields from ortbObject then do a merge but merge ret into the ortbObject (addEntriesFromDictionary) - NSMutableDictionary *arbitraryServerConfig = [self.arbitraryJsonConfig mutableCopy]; + NSMutableDictionary *ortbObj = [self.ortbObject mutableCopy]; - if (arbitraryServerConfig[@"regs"]) { - arbitraryServerConfig[@"regs"] = nil; + //remove fields that are not meant to be overridden + if (ortbObj[@"regs"]) { + ortbObj[@"regs"] = nil; } - if (arbitraryServerConfig[@"device"]) { - arbitraryServerConfig[@"device"] = nil; + if (ortbObj[@"device"]) { + ortbObj[@"device"] = nil; } - if (arbitraryServerConfig[@"geo"]) { - arbitraryServerConfig[@"geo"] = nil; + if (ortbObj[@"geo"]) { + ortbObj[@"geo"] = nil; } - //merge with config from API/JSON - ret = [self mergeDictionaries: ret joiningArgument2: arbitraryServerConfig joiningArgument3: false]; - - NSMutableDictionary *o2 = [self.ortbObject mutableCopy]; - - if (o2[@"regs"]) { - o2[@"regs"] = nil; + if (ortbObj[@"ext"][@"gdpr"]) { + ortbObj[@"ext"][@"gdpr"] = nil; } - if (o2[@"device"]) { - o2[@"device"] = nil; + if (ortbObj[@"ext"][@"us_privacy"]) { + ortbObj[@"ext"][@"us_privacy"] = nil; } - if (o2[@"geo"]) { - o2[@"geo"] = nil; + if (ortbObj[@"ext"][@"consent"]) { + ortbObj[@"ext"][@"consent"] = nil; } - //merge with ortbConfig from SDK - ret = [self mergeDictionaries: ret joiningArgument2: o2 joiningArgument3: true]; + + //merge with ortbConfig from SDK with priority away from SDK + ret = [self mergeDictionaries: ret joiningArgument2: ortbObj joiningArgument3: true]; ret = [ret pbmCopyWithoutEmptyVals]; diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift index b6a3ccee8..d8b8707c1 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift @@ -84,15 +84,7 @@ public class AdUnitConfig: NSObject, NSCopying { get {adConfiguration.ortbConfig} set {adConfiguration.ortbConfig = newValue} } - -// if let unwrappedNewValue = newValue { -// if (JSONSerialization.isValidJSONObject(unwrappedNewValue.data(using: String.Encoding.utf8) as Any)) { -// adConfiguration.ortbConfig = unwrappedNewValue -// } else { -// Log.warn("The provided ortbConfig object is not valid JSON and therefore will be ignored.") -// } -// } - + // MARK: - Public Methods public convenience init(configId: String) { From c59ed0d9dfe9c71cbbe5115a9d964505df155acd Mon Sep 17 00:00:00 2001 From: Jono Sligh Date: Thu, 15 Feb 2024 13:43:27 -0600 Subject: [PATCH 3/4] Finished up testing. --- .../Parameters/PBMBasicParameterBuilder.m | 1 + .../ORTB/PBMORTBBidRequest.m | 6 ++--- .../PBMCore/PBMPrebidParameterBuilder.m | 1 + .../Tests/PBMORTBAbstractTest.swift | 22 ++++++++++++++++- .../PrebidParameterBuilderTest.swift | 24 +++++++++++++++++++ 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/PrebidMobile/PrebidMobileRendering/Networking/Parameters/PBMBasicParameterBuilder.m b/PrebidMobile/PrebidMobileRendering/Networking/Parameters/PBMBasicParameterBuilder.m index bbbe7919e..77f5d2920 100644 --- a/PrebidMobile/PrebidMobileRendering/Networking/Parameters/PBMBasicParameterBuilder.m +++ b/PrebidMobile/PrebidMobileRendering/Networking/Parameters/PBMBasicParameterBuilder.m @@ -128,6 +128,7 @@ - (void)buildBidRequest:(PBMORTBBidRequest *)bidRequest { bidRequest.regs.coppa = self.targeting.coppa; bidRequest.regs.ext[@"gdpr"] = [self.targeting getSubjectToGDPR]; bidRequest.regs.gpp = InternalUserConsentDataManager.gppHDRString; + bidRequest.ortbObject = [self.adConfiguration getCheckedOrtbConfig]; if (InternalUserConsentDataManager.gppSID.count > 0) { bidRequest.regs.gppSID = InternalUserConsentDataManager.gppSID; diff --git a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m index 289180efb..a52162ce8 100644 --- a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m +++ b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m @@ -62,7 +62,7 @@ - (nonnull PBMJsonDictionary *)toJsonDictionary { NSMutableDictionary *arbitraryServerConfig = [self.arbitraryJsonConfig mutableCopy]; //merge with config from API/JSON with priority from server - ret = [self mergeDictionaries: ret joiningArgument2: arbitraryServerConfig joiningArgument3: false]; + ret = [self mergeDictionaries: ret joiningArgument2: arbitraryServerConfig joiningArgument3: true]; ret[@"id"] = self.requestID; @@ -97,7 +97,7 @@ - (nonnull PBMJsonDictionary *)toJsonDictionary { } //merge with ortbConfig from SDK with priority away from SDK - ret = [self mergeDictionaries: ret joiningArgument2: ortbObj joiningArgument3: true]; + ret = [self mergeDictionaries: ret joiningArgument2: ortbObj joiningArgument3: false]; ret = [ret pbmCopyWithoutEmptyVals]; @@ -117,7 +117,7 @@ - (nonnull PBMMutableJsonDictionary *)mergeDictionaries:(NSMutableDictionary*)di //merge arrays NSArray *mergedArray = [[ret objectForKey: key] arrayByAddingObjectsFromArray: [dictionary2 objectForKey: key]]; //remove duplicates and set - [ret setObject:[mergedArray valueForKeyPath:@"@distinctUnionOfObjects.self"] forKey:key]; + [ret setObject:mergedArray forKey:key]; } else { if (!firstHasPriority) { [ret setObject:[dictionary2 objectForKey: key] forKey:key]; diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m index 7029a8fa7..b145737bd 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m @@ -73,6 +73,7 @@ - (void)buildBidRequest:(nonnull PBMORTBBidRequest *)bidRequest { bidRequest.extPrebid.storedAuctionResponse = Prebid.shared.storedAuctionResponse; bidRequest.extPrebid.dataBidders = self.targeting.accessControlList; bidRequest.extPrebid.storedBidResponses = [Prebid.shared getStoredBidResponses]; + bidRequest.ortbObject = [self.adConfiguration.adConfiguration getCheckedOrtbConfig]; if (Prebid.shared.useCacheForReportingWithRenderingAPI) { PBMMutableJsonDictionary * const cache = [PBMMutableJsonDictionary new]; diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMORTBAbstractTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMORTBAbstractTest.swift index 126b33a5c..5fa411be0 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMORTBAbstractTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMORTBAbstractTest.swift @@ -190,6 +190,26 @@ class PBMORTBAbstractTest : XCTestCase { codeAndDecode(abstract: pbmORTBBidRequest, expectedString: "{\"ext\":{\"prebid\":{\"data\":{\"bidders\":[\"openx\",\"prebid\",\"thanatos\"]},\"storedauctionresponse\":{\"id\":\"stored-auction-response-test\"},\"storedrequest\":{\"id\":\"b4eb1475-4e3d-4186-97b7-25b6a6cf8618\"},\"targeting\":{}}},\"imp\":[{\"clickbrowser\":0,\"ext\":{\"dlp\":1},\"instl\":0,\"secure\":0}]}") } + func testBidRequestWithOrtbObjectToJsonString() { + let pbmORTBBidRequest = PBMORTBBidRequest() + let uuid = UUID().uuidString + pbmORTBBidRequest.requestID = uuid + pbmORTBBidRequest.tmax = 2000 + pbmORTBBidRequest.ortbObject = ["arbitraryparamkey1": "arbitraryparamvalue1", "tmax": 3000, "id": "1231234"] + + codeAndDecode(abstract: pbmORTBBidRequest, expectedString: "{\"arbitraryparamkey1\":\"arbitraryparamvalue1\",\"id\":\"1231234\",\"imp\":[{\"clickbrowser\":0,\"ext\":{\"dlp\":1},\"instl\":0,\"secure\":0}],\"tmax\":3000}") + } + + func testBidRequestWithOrtbObjectOverridingReservedToJsonString() { + let pbmORTBBidRequest = PBMORTBBidRequest() + let uuid = UUID().uuidString + pbmORTBBidRequest.requestID = uuid + pbmORTBBidRequest.tmax = 2000 + pbmORTBBidRequest.ortbObject = ["arbitraryparamkey1": "arbitraryparamvalue1", "tmax": 3000, "id": "1231234", "device": "myTestDevice", "geo": "mylatlong", "regs": ["reg1":"reg2"]] + + codeAndDecode(abstract: pbmORTBBidRequest, expectedString: "{\"arbitraryparamkey1\":\"arbitraryparamvalue1\",\"id\":\"1231234\",\"imp\":[{\"clickbrowser\":0,\"ext\":{\"dlp\":1},\"instl\":0,\"secure\":0}],\"tmax\":3000}") + } + func testSourceToJsonString() { let pbmORTBSource = PBMORTBSource() @@ -589,7 +609,7 @@ class PBMORTBAbstractTest : XCTestCase { do { //Make a copy of the object - let newCodable = abstract.copy() as! PBMORTBAbstract + let newCodable = abstract as PBMORTBAbstract //Convert it to json let newJsonString = try newCodable.toJsonString() diff --git a/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/PrebidParameterBuilderTest.swift b/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/PrebidParameterBuilderTest.swift index 454abbbe1..d1e1700a9 100644 --- a/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/PrebidParameterBuilderTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/PrebidParameterBuilderTest.swift @@ -784,6 +784,30 @@ class PrebidParameterBuilderTest: XCTestCase { XCTAssertEqual(imp.extGPID, gpid) } } + + func testArbitraryORTBParams() { + let gpid = "/12345/home_screen#identifier" + let ortb = "{\"arbitraryparamkey1\":\"arbitraryparamvalue1\",\"imp\":[{}]}" + let adUnit = AdUnit(configId: "test", size: CGSize.zero, adFormats: [.banner]) + adUnit.setGPID(gpid) + adUnit.setOrtbConfig(ortb) + + let bidRequest = buildBidRequest(with: adUnit.adUnitConfig) + + XCTAssertEqual(bidRequest.ortbObject?["arbitraryparamkey1"] as? String, "arbitraryparamvalue1") + } + + func testArbitraryORTBParamsIncorrectJSON() { + let gpid = "/12345/home_screen#identifier" + let ortb = "{{\"arbitraryparamkey1\":\"arbitraryparamvalue1\",\"imp\":[{}]}" + let adUnit = AdUnit(configId: "test", size: CGSize.zero, adFormats: [.banner]) + adUnit.setGPID(gpid) + adUnit.setOrtbConfig(ortb) + + let bidRequest = buildBidRequest(with: adUnit.adUnitConfig) + + XCTAssert(bidRequest.ortbObject?.isEmpty == true) + } // MARK: - Helpers From 7e59281a12e53643bbbd3872019de1ec2d355322 Mon Sep 17 00:00:00 2001 From: Jono Sligh Date: Thu, 29 Feb 2024 13:14:10 -0600 Subject: [PATCH 4/4] tie in return from server to carry over arbitrary params. --- PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m index a52162ce8..4cbff955b 100644 --- a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m +++ b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBBidRequest.m @@ -156,6 +156,8 @@ - (instancetype)initWithJsonDictionary:(nonnull PBMJsonDictionary *)jsonDictiona _extPrebid = [[PBMORTBBidRequestExtPrebid alloc] initWithJsonDictionary:jsonDictionary[@"ext"][@"prebid"] ?: @{}]; + _arbitraryJsonConfig = jsonDictionary; + return self; }