From 0303de4aea5a495e860d65a01d6b86e823eea784 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Thu, 3 Oct 2024 13:10:16 +0300 Subject: [PATCH 01/18] refactor: isOptIn -> isRewarded --- .../Sources/PrebidAdMobRewardedVideoAdapter.swift | 2 +- ...r+MAInterstitialAdapter+MARewardedAdapter.swift | 2 +- .../AdUnits/MultiformatAdUnit/PrebidAdUnit.swift | 2 +- .../AdTypes/AdView/AdConfiguration.swift | 2 +- .../AdTypes/AdView/Modals/PBMModalViewController.m | 4 ++-- .../AdTypes/AdView/PBMAdViewManager.m | 2 +- .../AdTypes/AdView/PBMVideoCreative.m | 2 +- .../AdTypes/AdView/PBMVideoView.m | 14 +++++++------- .../MediationAPI/MediationRewardedAdUnit.swift | 2 +- .../PBMCacheRenderers/InterstitialController.swift | 10 +++++----- .../Prebid/PBMCore/AdUnitConfig.swift | 2 +- .../Prebid/PBMCore/PBMPrebidParameterBuilder.m | 2 +- .../AdUnitTests/PrebidAdUnitTests.swift | 4 ++-- .../Tests/PBMModalViewControllerTest.swift | 2 +- .../PBMRewardedVideoCreativeTestCloseDelay.swift | 2 +- .../Tests/PBMVideoCreativeTestCloseDelay.swift | 4 ++-- .../MediationAPI/MediationRewardedAdUnitTest.swift | 2 +- .../RewardedVideo/PBMRewardedVideoViewTest.swift | 2 +- .../RewardedVideo_CompanionTest.swift | 2 +- .../Tests/VASTTests/PBMVideoCreativeTest.swift | 2 +- .../Tests/VASTTests/RewardedVideoEventsTest.swift | 2 +- 21 files changed, 34 insertions(+), 34 deletions(-) diff --git a/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedVideoAdapter.swift b/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedVideoAdapter.swift index 181e6cdbd..6e7a1790e 100644 --- a/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedVideoAdapter.swift +++ b/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedVideoAdapter.swift @@ -81,7 +81,7 @@ public class PrebidAdMobRewardedVideoAdapter: interstitialController?.loadingDelegate = self interstitialController?.interactionDelegate = self interstitialController?.adFormats = [.video] - interstitialController?.isOptIn = true + interstitialController?.isRewarded = true if let videoAdConfig = eventExtrasDictionary[PBMMediationVideoAdConfiguration] as? VideoControlsConfiguration { interstitialController?.videoControlsConfig = videoAdConfig diff --git a/EventHandlers/PrebidMobileMAXAdapters/Sources/PrebidMAXMediationAdapter+MAInterstitialAdapter+MARewardedAdapter.swift b/EventHandlers/PrebidMobileMAXAdapters/Sources/PrebidMAXMediationAdapter+MAInterstitialAdapter+MARewardedAdapter.swift index aa2c3b495..2da86f5aa 100644 --- a/EventHandlers/PrebidMobileMAXAdapters/Sources/PrebidMAXMediationAdapter+MAInterstitialAdapter+MARewardedAdapter.swift +++ b/EventHandlers/PrebidMobileMAXAdapters/Sources/PrebidMAXMediationAdapter+MAInterstitialAdapter+MARewardedAdapter.swift @@ -118,7 +118,7 @@ extension PrebidMAXMediationAdapter: MAInterstitialAdapter, interstitialController = InterstitialController(bid: bid, configId: configId) interstitialController?.loadingDelegate = self interstitialController?.interactionDelegate = self - interstitialController?.isOptIn = true + interstitialController?.isRewarded = true if let videoAdConfig = parameters.localExtraParameters[PBMMediationVideoAdConfiguration] as? VideoControlsConfiguration { interstitialController?.videoControlsConfig = videoAdConfig diff --git a/PrebidMobile/AdUnits/MultiformatAdUnit/PrebidAdUnit.swift b/PrebidMobile/AdUnits/MultiformatAdUnit/PrebidAdUnit.swift index 97c9c1b0b..cddc6f131 100644 --- a/PrebidMobile/AdUnits/MultiformatAdUnit/PrebidAdUnit.swift +++ b/PrebidMobile/AdUnits/MultiformatAdUnit/PrebidAdUnit.swift @@ -125,7 +125,7 @@ public class PrebidAdUnit: NSObject { } adUnit.adUnitConfig.adConfiguration.isInterstitialAd = request.isInterstitial - adUnit.adUnitConfig.adConfiguration.isOptIn = request.isRewarded + adUnit.adUnitConfig.adConfiguration.isRewarded = request.isRewarded if request.isInterstitial || request.isRewarded { adUnit.adUnitConfig.adPosition = .fullScreen diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift index 5ec69b4e7..13ba3afb6 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift @@ -73,7 +73,7 @@ public class AdConfiguration: AutoRefreshCountConfig { public var size = CGSize.zero /** - Sets a video interstitial ad unit as an opt-in video + Sets an ad unit as an rewarded */ public var isOptIn = false diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m index a89bd89fd..692189676 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m @@ -242,7 +242,7 @@ - (void)configureCloseButton { - (void)setupCloseButtonVisibility { // Set the close button view visibilty based on th view context (i.e. normal, clickthrough browser, rewarded video) [self.closeButtonDecorator bringButtonToFront]; - if (self.modalState.adConfiguration.isOptIn) { + if (self.modalState.adConfiguration.isRewarded) { return; // Must be hidden } else if (self.displayProperties && self.displayProperties.closeDelay > 0) { @@ -260,7 +260,7 @@ - (void)setupCloseButtonVisibility { } - (void)creativeDisplayCompleted:(PBMAbstractCreative *)creative { - if (self.modalState.adConfiguration.isOptIn) { + if (self.modalState.adConfiguration.isRewarded) { self.closeButtonDecorator.button.hidden = NO; } } diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManager.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManager.m index 90bd7ee4f..1de3674a8 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManager.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManager.m @@ -209,7 +209,7 @@ - (void)creativeWasClicked:(PBMAbstractCreative *)creative { } - (void)creativeInterstitialDidClose:(PBMAbstractCreative *) creative { - if (self.adConfiguration.isOptIn) { + if (self.adConfiguration.isRewarded) { // In Rewarded Video, the Video remains on the screen with the last frame showing. // Cleaning up here when the Interstial is closed.; if (self.currentCreative.view && self.currentCreative.view.superview) { diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.m index 33798fc32..c163eedd3 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.m @@ -288,7 +288,7 @@ - (PBMInterstitialDisplayProperties *)createInterstitialPropertiesForCurrentVide // TODO: - Clarify the requirements and fix calculation logic - (NSTimeInterval)calculateCloseDelayForPubCloseDelay:(NSTimeInterval)pubCloseDelay { - if (self.creativeModel.adConfiguration.isOptIn || self.creativeModel.hasCompanionAd) { + if (self.creativeModel.adConfiguration.isRewarded || self.creativeModel.hasCompanionAd) { return [self.creativeModel.displayDurationInSeconds doubleValue]; } else if (self.creativeModel.adConfiguration.videoControlsConfig.skipDelay && self.creativeModel.adConfiguration.videoControlsConfig.skipDelay <= self.creativeModel.displayDurationInSeconds.doubleValue) { return self.creativeModel.adConfiguration.videoControlsConfig.skipDelay; diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m index fb875ce08..4a1543101 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m @@ -157,7 +157,7 @@ - (void)setupWithEventManager:(PBMEventManager *)eventManager { self.accessibilityIdentifier = @"PBMVideoView"; if (!self.creative.creativeModel.adConfiguration.isInterstitialAd || - (self.creative.creativeModel.adConfiguration.isOptIn && !self.creative.creativeModel.hasCompanionAd)) { + (self.creative.creativeModel.adConfiguration.isRewarded && !self.creative.creativeModel.hasCompanionAd)) { [self setupTapRecognizer]; } @@ -220,7 +220,7 @@ - (void)updateLearnMoreButtonVisibility { } // For rewarded ad learn more should be hidden - if (self.creative.creativeModel.adConfiguration.isOptIn) { + if (self.creative.creativeModel.adConfiguration.isRewarded) { self.showLearnMore = NO; return; } @@ -355,7 +355,7 @@ - (void)updateProgressBar { [self.progressBar removeFromSuperview]; } - if (!self.creative.creativeModel.adConfiguration.isOptIn) { + if (!self.creative.creativeModel.adConfiguration.isRewarded) { return; } @@ -493,7 +493,7 @@ - (void)handleSkipDelay:(NSTimeInterval)skipDelay videoDuration:(NSTimeInterval) return; } - if (!self.creative.creativeModel.hasCompanionAd || self.creative.creativeModel.adConfiguration.isOptIn || self.creative.creativeModel.adConfiguration.isBuiltInVideo) { + if (!self.creative.creativeModel.hasCompanionAd || self.creative.creativeModel.adConfiguration.isRewarded || self.creative.creativeModel.adConfiguration.isBuiltInVideo) { return; } @@ -638,7 +638,7 @@ - (void)initTimeObserver { }]; } - if (self.creative.creativeModel.adConfiguration.isOptIn) { + if (self.creative.creativeModel.adConfiguration.isRewarded) { self.progressBar.duration = [self requiredVideoDuration]; } } @@ -759,7 +759,7 @@ - (void)completeVideoViewDisplayWith:(PBMTrackingEvent)trackingEvent { [self.videoViewDelegate videoViewCompletedDisplay]; - if (self.creative.creativeModel.adConfiguration.isOptIn) { + if (self.creative.creativeModel.adConfiguration.isRewarded) { self.progressBar.hidden = YES; } @@ -829,7 +829,7 @@ - (CGFloat)handlePeriodicTimeEvent { CGFloat playingTime = CMTimeGetSeconds(currentTime); CGFloat remainingTime = [self requiredVideoDuration] - playingTime; - if (self.creative.creativeModel.adConfiguration.isOptIn) { + if (self.creative.creativeModel.adConfiguration.isRewarded) { [self.progressBar updateProgress:remainingTime]; } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationRewardedAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationRewardedAdUnit.swift index 3b8179710..cec66e397 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationRewardedAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/MediationAPI/MediationRewardedAdUnit.swift @@ -29,7 +29,7 @@ public class MediationRewardedAdUnit : MediationBaseInterstitialAdUnit { public override init(configId: String, mediationDelegate: PrebidMediationDelegate) { super.init(configId: configId, mediationDelegate: mediationDelegate) - adUnitConfig.adConfiguration.isOptIn = true + adUnitConfig.adConfiguration.isRewarded = true adUnitConfig.adFormats = [.video] } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift index b4108bcdf..3f2643a7c 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift @@ -25,10 +25,10 @@ public class InterstitialController: NSObject, PBMAdViewManagerDelegate { set { adConfiguration.adFormats = newValue } } - /// Sets a video interstitial ad unit as an opt-in video - @objc public var isOptIn: Bool { - get { adConfiguration.adConfiguration.isOptIn } - set { adConfiguration.adConfiguration.isOptIn = newValue } + /// Sets an ad unit as a rewarded + @objc public var isRewarded: Bool { + get { adConfiguration.adConfiguration.isRewarded } + set { adConfiguration.adConfiguration.isRewarded = newValue } } @objc public var videoControlsConfig: VideoControlsConfiguration { @@ -173,7 +173,7 @@ public class InterstitialController: NSObject, PBMAdViewManagerDelegate { modalManagerDelegate: nil) adViewManager?.adViewManagerDelegate = self adViewManager?.adConfiguration.isInterstitialAd = true - adViewManager?.adConfiguration.isOptIn = adConfiguration.adConfiguration.isOptIn + adViewManager?.adConfiguration.isRewarded = adConfiguration.adConfiguration.isRewarded adViewManager?.handleExternalTransaction(transaction) } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift index 68cbf069a..8012fe616 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift @@ -304,7 +304,7 @@ public class AdUnitConfig: NSObject, NSCopying { clone.adFormats = self.adFormats clone.adConfiguration.adFormats = self.adConfiguration.adFormats clone.adConfiguration.isInterstitialAd = self.adConfiguration.isInterstitialAd - clone.adConfiguration.isOptIn = self.adConfiguration.isOptIn + clone.adConfiguration.isRewarded = self.adConfiguration.isRewarded clone.nativeAdConfiguration = self.nativeAdConfiguration clone.adConfiguration.bannerParameters = self.adConfiguration.bannerParameters clone.adConfiguration.videoParameters = self.adConfiguration.videoParameters diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m index edae54fd6..a8978e73d 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m @@ -185,7 +185,7 @@ - (void)buildBidRequest:(nonnull PBMORTBBidRequest *)bidRequest { nextImp.impID = [NSUUID UUID].UUIDString; nextImp.extPrebid.storedRequestID = self.adConfiguration.configId; nextImp.extPrebid.storedAuctionResponse = Prebid.shared.storedAuctionResponse; - nextImp.extPrebid.isRewardedInventory = self.adConfiguration.adConfiguration.isOptIn; + nextImp.extPrebid.isRewardedInventory = self.adConfiguration.adConfiguration.isRewarded; nextImp.extGPID = self.adConfiguration.gpid; if ([self.adConfiguration getExtData].count > 0) { diff --git a/PrebidMobileTests/AdUnitTests/PrebidAdUnitTests.swift b/PrebidMobileTests/AdUnitTests/PrebidAdUnitTests.swift index 168240bec..4f1840d40 100644 --- a/PrebidMobileTests/AdUnitTests/PrebidAdUnitTests.swift +++ b/PrebidMobileTests/AdUnitTests/PrebidAdUnitTests.swift @@ -210,7 +210,7 @@ class PrebidAdUnitTests: XCTestCase { // fetchDemand(request:completion) adUnit.fetchDemand(request: request) { _ in XCTAssertTrue(config.adConfiguration.isInterstitialAd) - XCTAssertTrue(config.adConfiguration.isOptIn) + XCTAssertTrue(config.adConfiguration.isRewarded) XCTAssertEqual(config.adPosition, .fullScreen) XCTAssertEqual(config.adConfiguration.videoParameters.placement, .Interstitial) @@ -223,7 +223,7 @@ class PrebidAdUnitTests: XCTestCase { // fetchDemand(adObject:request:completion) adUnit.fetchDemand(adObject: testObject, request: request) { _ in XCTAssertTrue(config.adConfiguration.isInterstitialAd) - XCTAssertTrue(config.adConfiguration.isOptIn) + XCTAssertTrue(config.adConfiguration.isRewarded) XCTAssertEqual(config.adPosition, .fullScreen) XCTAssertEqual(config.adConfiguration.videoParameters.placement, .Interstitial) diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMModalViewControllerTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMModalViewControllerTest.swift index 0d4bb9244..be4d20836 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMModalViewControllerTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMModalViewControllerTest.swift @@ -131,7 +131,7 @@ class PBMModalViewControllerTest: XCTestCase, PBMModalViewControllerDelegate { displayProperties.closeDelayLeft = 3 let adConfiguration = AdConfiguration() - adConfiguration.isOptIn = true + adConfiguration.isRewarded = true let modalState = PBMModalState(view: UIView(), adConfiguration: adConfiguration, displayProperties:displayProperties, onStatePopFinished: nil, onStateHasLeftApp: nil) controller.modalState = modalState diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMRewardedVideoCreativeTestCloseDelay.swift b/PrebidMobileTests/RenderingTests/Tests/PBMRewardedVideoCreativeTestCloseDelay.swift index 2ecacf4ee..73b27a64d 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMRewardedVideoCreativeTestCloseDelay.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMRewardedVideoCreativeTestCloseDelay.swift @@ -24,7 +24,7 @@ class PBMRewardedVideoCreativeTestCloseDelay : XCTestCase { var actual: TimeInterval let model = PBMCreativeModel(adConfiguration:AdConfiguration()) - model.adConfiguration?.isOptIn = true + model.adConfiguration?.isRewarded = true model.displayDurationInSeconds = 10 actual = calculateCloseDelay(with:model, pubCloseDelay:5) diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMVideoCreativeTestCloseDelay.swift b/PrebidMobileTests/RenderingTests/Tests/PBMVideoCreativeTestCloseDelay.swift index df4f64d3f..f7580af00 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMVideoCreativeTestCloseDelay.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMVideoCreativeTestCloseDelay.swift @@ -27,7 +27,7 @@ class PBMVideoCreativeTestCloseDelay : XCTestCase { model.displayDurationInSeconds = 10 //if model is opt in or has companion ad - return display duration - model.adConfiguration?.isOptIn = true + model.adConfiguration?.isRewarded = true model.hasCompanionAd = true expected = 10 @@ -35,7 +35,7 @@ class PBMVideoCreativeTestCloseDelay : XCTestCase { PBMAssertEq(actual, expected) //reset - model.adConfiguration?.isOptIn = false + model.adConfiguration?.isRewarded = false model.hasCompanionAd = false //for video without end cart use skip delay diff --git a/PrebidMobileTests/RenderingTests/Tests/Prebid/MediationAPI/MediationRewardedAdUnitTest.swift b/PrebidMobileTests/RenderingTests/Tests/Prebid/MediationAPI/MediationRewardedAdUnitTest.swift index b48793728..d9478ce3b 100644 --- a/PrebidMobileTests/RenderingTests/Tests/Prebid/MediationAPI/MediationRewardedAdUnitTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/Prebid/MediationAPI/MediationRewardedAdUnitTest.swift @@ -26,7 +26,7 @@ class MediationRewardedAdUnitTest: XCTestCase { let adUnitConfig = adUnit.adUnitConfig XCTAssertTrue(adUnitConfig.adConfiguration.isInterstitialAd) - XCTAssertTrue(adUnitConfig.adConfiguration.isOptIn) + XCTAssertTrue(adUnitConfig.adConfiguration.isRewarded) PBMAssertEq(adUnitConfig.adPosition, .fullScreen) XCTAssertTrue(adUnitConfig.adFormats.contains(.video)) } diff --git a/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/PBMRewardedVideoViewTest.swift b/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/PBMRewardedVideoViewTest.swift index 46da3a1b6..535a51e62 100644 --- a/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/PBMRewardedVideoViewTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/PBMRewardedVideoViewTest.swift @@ -162,7 +162,7 @@ class PBMRewardedVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCr let model = PBMCreativeModel(adConfiguration:AdConfiguration()) model.videoFileURL = videoFileURL model.displayDurationInSeconds = 6 - model.adConfiguration?.isOptIn = true + model.adConfiguration?.isRewarded = true self.expectationDownloadCompleted = self.expectation(description: "expectationDownloadVideoData") diff --git a/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/RewardedVideo_CompanionTest.swift b/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/RewardedVideo_CompanionTest.swift index f4f886075..d4a973fad 100644 --- a/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/RewardedVideo_CompanionTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/RewardedVideo_CompanionTest.swift @@ -180,7 +180,7 @@ class RewardedVideo_CompanionTest: XCTestCase { adConfiguration.adFormats = [.video] adConfiguration.isInterstitialAd = true - adConfiguration.isOptIn = true + adConfiguration.isRewarded = true return adConfiguration } } diff --git a/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMVideoCreativeTest.swift b/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMVideoCreativeTest.swift index d6f1bc9a3..aa4416d65 100644 --- a/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMVideoCreativeTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMVideoCreativeTest.swift @@ -231,7 +231,7 @@ class VideoCreativeDelegateTest: XCTestCase, PBMCreativeResolutionDelegate, PBMC let mockModalManager = MockModalManager() self.videoCreative.modalManager = mockModalManager self.videoCreative.creativeModel?.hasCompanionAd = false - self.videoCreative.creativeModel?.adConfiguration?.isOptIn = false + self.videoCreative.creativeModel?.adConfiguration?.isRewarded = false self.videoCreative.creativeModel?.adConfiguration?.videoControlsConfig.skipDelay = 1000 mockModalManager.mock_pushModalClosure = { (modalState, _, _, _, completionHandler) in expectation.fulfill() diff --git a/PrebidMobileTests/RenderingTests/Tests/VASTTests/RewardedVideoEventsTest.swift b/PrebidMobileTests/RenderingTests/Tests/VASTTests/RewardedVideoEventsTest.swift index 1ff5165e7..5bc5588c7 100644 --- a/PrebidMobileTests/RenderingTests/Tests/VASTTests/RewardedVideoEventsTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/VASTTests/RewardedVideoEventsTest.swift @@ -261,7 +261,7 @@ class RewardedVideoEventsTest : XCTestCase, PBMCreativeViewDelegate { let adConfiguration = AdConfiguration() adConfiguration.adFormats = [.video] adConfiguration.isInterstitialAd = true - adConfiguration.isOptIn = true + adConfiguration.isRewarded = true return adConfiguration } From 21e1bcf1940dfa63a6cda061ea4f81a8e18a5fc4 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Thu, 3 Oct 2024 13:11:06 +0300 Subject: [PATCH 02/18] feat: introduce Prebid reward --- PrebidMobile.xcodeproj/project.pbxproj | 26 ++++---- .../AdTypes/AdView/AdConfiguration.swift | 2 +- ...InterstitialEventInteractionDelegate.swift | 16 ++--- .../Integrations/GAM/PrebidReward.swift | 30 +++++++++ .../Integrations/GAM/RewardedAdUnit.swift | 66 +++++++------------ .../GAM/RewardedAdUnitDelegate.swift | 2 +- .../RewardedEventInteractionDelegate.swift | 7 +- 7 files changed, 77 insertions(+), 72 deletions(-) create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift diff --git a/PrebidMobile.xcodeproj/project.pbxproj b/PrebidMobile.xcodeproj/project.pbxproj index 7e5fcc3e5..7df05f2f4 100644 --- a/PrebidMobile.xcodeproj/project.pbxproj +++ b/PrebidMobile.xcodeproj/project.pbxproj @@ -100,6 +100,7 @@ 53A368E92AB2E38200A03B3E /* BidInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A368E82AB2E38200A03B3E /* BidInfo.swift */; }; 53A368EB2AB2E95E00A03B3E /* NativeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A368EA2AB2E95E00A03B3E /* NativeParameters.swift */; }; 53A368F12AB83C9D00A03B3E /* PrebidRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A368F02AB83C9D00A03B3E /* PrebidRequestTests.swift */; }; + 53A447CD2CAE9F8E008DE6C0 /* PrebidReward.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A447CC2CAE9F8E008DE6C0 /* PrebidReward.swift */; }; 53A6579E2A860F5800AE0B4F /* CacheExpiryDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A6579D2A860F5800AE0B4F /* CacheExpiryDelegate.swift */; }; 53A657A02A860F7200AE0B4F /* CacheExpiryDelegateWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A6579F2A860F7200AE0B4F /* CacheExpiryDelegateWrapper.swift */; }; 53A657B02A8B64C200AE0B4F /* PBMORTBSDKConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A657AF2A8B64C200AE0B4F /* PBMORTBSDKConfiguration.m */; }; @@ -962,6 +963,7 @@ 53A368E82AB2E38200A03B3E /* BidInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BidInfo.swift; sourceTree = ""; }; 53A368EA2AB2E95E00A03B3E /* NativeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeParameters.swift; sourceTree = ""; }; 53A368F02AB83C9D00A03B3E /* PrebidRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidRequestTests.swift; sourceTree = ""; }; + 53A447CC2CAE9F8E008DE6C0 /* PrebidReward.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidReward.swift; sourceTree = ""; }; 53A6579D2A860F5800AE0B4F /* CacheExpiryDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheExpiryDelegate.swift; sourceTree = ""; }; 53A6579F2A860F7200AE0B4F /* CacheExpiryDelegateWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheExpiryDelegateWrapper.swift; sourceTree = ""; }; 53A657AE2A8B64B300AE0B4F /* PBMORTBSDKConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBSDKConfiguration.h; sourceTree = ""; }; @@ -2534,26 +2536,27 @@ 5BC37841271F1CFF00444D5E /* GAM */ = { isa = PBXGroup; children = ( + 5BC37855271F1CFF00444D5E /* AdLoading */, + 5BC37851271F1CFF00444D5E /* BannerEventHandler.swift */, + 5BC37848271F1CFF00444D5E /* BannerEventInteractionDelegate.swift */, 5BC37842271F1CFF00444D5E /* BannerEventLoadingDelegate.swift */, 5BC37843271F1CFF00444D5E /* BannerView.swift */, - 5BC37844271F1CFF00444D5E /* InterstitialEventInteractionDelegate.swift */, - 5BC37845271F1CFF00444D5E /* RewardedAdUnitDelegate.swift */, - 5BC37846271F1CFF00444D5E /* RewardedEventInteractionDelegate.swift */, 5BC37847271F1CFF00444D5E /* BannerViewDelegate.swift */, - 5BC37848271F1CFF00444D5E /* BannerEventInteractionDelegate.swift */, - 5BC37849271F1CFF00444D5E /* BaseInterstitialAdUnitProtocol.swift */, - 5BC3784A271F1CFF00444D5E /* InterstitialRenderingAdUnit.swift */, - 5BC3784B271F1CFF00444D5E /* RewardedAdUnit.swift */, 5BC3784C271F1CFF00444D5E /* BaseInterstitialAdUnit.swift */, + 5BC37849271F1CFF00444D5E /* BaseInterstitialAdUnitProtocol.swift */, 5BC3784D271F1CFF00444D5E /* InterstitialAdUnitDelegate.swift */, + 5BC37854271F1CFF00444D5E /* InterstitialEventHandlerProtocol.swift */, + 5BC37844271F1CFF00444D5E /* InterstitialEventInteractionDelegate.swift */, 5BC3784E271F1CFF00444D5E /* InterstitialEventLoadingDelegate.swift */, - 5BC3784F271F1CFF00444D5E /* RewardedEventLoadingDelegate.swift */, + 5BC3784A271F1CFF00444D5E /* InterstitialRenderingAdUnit.swift */, 5BC37850271F1CFF00444D5E /* PBMInterstitialEventHandler.h */, - 5BC37851271F1CFF00444D5E /* BannerEventHandler.swift */, 5BC37852271F1CFF00444D5E /* PBMPrimaryAdRequesterProtocol.h */, + 53A447CC2CAE9F8E008DE6C0 /* PrebidReward.swift */, + 5BC3784B271F1CFF00444D5E /* RewardedAdUnit.swift */, + 5BC37845271F1CFF00444D5E /* RewardedAdUnitDelegate.swift */, 5BC37853271F1CFF00444D5E /* RewardedEventHandlerProtocol.swift */, - 5BC37854271F1CFF00444D5E /* InterstitialEventHandlerProtocol.swift */, - 5BC37855271F1CFF00444D5E /* AdLoading */, + 5BC37846271F1CFF00444D5E /* RewardedEventInteractionDelegate.swift */, + 5BC3784F271F1CFF00444D5E /* RewardedEventLoadingDelegate.swift */, ); path = GAM; sourceTree = ""; @@ -4253,6 +4256,7 @@ 5BC37A91271F1D0000444D5E /* InterstitialEventLoadingDelegate.swift in Sources */, 530382F2283197E100B2B111 /* PrebidServerResponse.swift in Sources */, 53D3C3882C2BEE1E0074D99B /* URL+Extensions.swift in Sources */, + 53A447CD2CAE9F8E008DE6C0 /* PrebidReward.swift in Sources */, 5BC3792F271F1D0000444D5E /* PBMDeviceAccessManager.m in Sources */, 5BC37A6E271F1D0000444D5E /* PBMORTBBidResponse.m in Sources */, 5BC37ACE271F1D0100444D5E /* PBMGeoLocationParameterBuilder.m in Sources */, diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift index 13ba3afb6..ef40ed066 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift @@ -75,7 +75,7 @@ public class AdConfiguration: AutoRefreshCountConfig { /** Sets an ad unit as an rewarded */ - public var isOptIn = false + public var isRewarded = false /** Indicates whether the ad is built-in video e.g. 300x250. diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialEventInteractionDelegate.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialEventInteractionDelegate.swift index 62b91fa16..4e9eb2373 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialEventInteractionDelegate.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialEventInteractionDelegate.swift @@ -17,23 +17,15 @@ import Foundation @objc public protocol InterstitialEventInteractionDelegate: NSObjectProtocol { - /*! - @abstract Call this when the ad server SDK is about to present a modal - */ + /// Call this when the ad server SDK is about to present a modal @objc func willPresentAd() - /*! - @abstract Call this when the ad server SDK dissmisses a modal - */ + /// Call this when the ad server SDK dissmisses a modal @objc func didDismissAd() - /*! - @abstract Call this when the ad server SDK informs about app leave event as a result of user interaction. - */ + /// Call this when the ad server SDK informs about app leave event as a result of user interaction. @objc func willLeaveApp() - /*! - @abstract Call this when the ad server SDK informs about click event as a result of user interaction. - */ + /// Call this when the ad server SDK informs about click event as a result of user interaction. @objc func didClickAd() } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift new file mode 100644 index 000000000..5fbf59cdf --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift @@ -0,0 +1,30 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import Foundation + +@objcMembers +public class PrebidReward: NSObject { + + public var type: String? + public var count: NSNumber? + public var ext: [String: Any]? + +// init(with ortbReward: TQBORTBBidExtRewardedReward? = nil) { +// self.type = ortbReward?.type +// self.count = ortbReward?.count +// self.ext = ortbReward?.ext +// } +} diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift index 6a2ab7afb..60f12e274 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift @@ -19,21 +19,17 @@ import UIKit @objc public class RewardedAdUnit: BaseInterstitialAdUnit, RewardedEventInteractionDelegate { - - /// The reward object for the ad unit. - @objc public private(set) var reward: NSObject? - // MARK: - Lifecycle - /// Initializes a `RewardedAdUnit` with the given configuration ID and event handler. - /// - /// - Parameter configID: The configuration ID for the ad unit. - /// - Parameter eventHandler: The event handler for the ad unit. - @objc public convenience init(configID: String, eventHandler: AnyObject) { + @objc public convenience init( + configID: String, + eventHandler: AnyObject + ) { self.init( configID: configID, minSizePerc: nil, - eventHandler: eventHandler) + eventHandler: eventHandler + ) } /// Initializes a `RewardedAdUnit` with the given configuration ID and a default event handler. @@ -43,46 +39,33 @@ public class RewardedAdUnit: BaseInterstitialAdUnit, self.init( configID: configID, minSizePerc: nil, - eventHandler: RewardedEventHandlerStandalone()) + eventHandler: RewardedEventHandlerStandalone() + ) } - /// Initializes a `RewardedAdUnit` with the given configuration ID, minimum size percentage, and event handler. - /// - /// - Parameter configID: The configuration ID for the ad unit. - /// - Parameter minSizePerc: The minimum size percentage for the ad unit. - /// - Parameter eventHandler: The event handler for the ad unit. - @objc required init(configID:String, minSizePerc: NSValue?, eventHandler: AnyObject?) { + @objc required init( + configID: String, + minSizePerc: NSValue?, + eventHandler: AnyObject? + ) { super.init( configID: configID, minSizePerc: minSizePerc, - eventHandler: eventHandler) + eventHandler: eventHandler + ) - adUnitConfig.adConfiguration.isOptIn = true - adFormats = [.video] + adUnitConfig.adConfiguration.isRewarded = true + adFormats = [.banner, .video] } - // MARK: - PBMRewardedEventDelegate + // MARK: - RewardedEventDelegate - /// Called when the user earns a reward. - /// - /// - Parameter reward: The reward object associated with the event. - @objc public func userDidEarnReward(_ reward: NSObject?) { - DispatchQueue.main.async(execute: { [weak self] in - self?.reward = reward - self?.callDelegate_rewardedAdUserDidEarnReward() - }) + @objc public func userDidEarnReward(_ reward: PrebidReward) { + DispatchQueue.main.async { + self.callDelegate_rewardedAdUserDidEarnReward(reward: reward) + } } - // MARK: - BaseInterstitialAdUnitProtocol protocol - - /// Called when the interstitial ad is closed. - /// - /// - Parameter interstitialController: The controller managing the interstitial ad. - @objc public override func interstitialControllerDidCloseAd(_ interstitialController: InterstitialController) { - callDelegate_rewardedAdUserDidEarnReward() - super.interstitialControllerDidCloseAd(interstitialController) - } - // MARK: - Protected overrides /// Called when the ad unit receives an ad. @@ -183,10 +166,9 @@ public class RewardedAdUnit: BaseInterstitialAdUnit, // MARK: - Private helpers - /// Calls the delegate method to notify that the user has earned a reward. - func callDelegate_rewardedAdUserDidEarnReward() { + func callDelegate_rewardedAdUserDidEarnReward(reward: PrebidReward) { if let delegate = self.delegate as? RewardedAdUnitDelegate { - delegate.rewardedAdUserDidEarnReward?(self) + delegate.rewardedAdUserDidEarnReward?(self, reward: reward) } } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnitDelegate.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnitDelegate.swift index 247ed78f2..2d2251227 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnitDelegate.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnitDelegate.swift @@ -23,7 +23,7 @@ import Foundation @objc optional func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) /// Called when user is able to receive a reward from the app - @objc optional func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit) + @objc optional func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) /// Called when the load process fails to produce a viable ad @objc optional func rewardedAd(_ rewardedAd: RewardedAdUnit, diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift index f2eaa6b58..9476706dd 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift @@ -17,9 +17,6 @@ import Foundation @objc public protocol RewardedEventInteractionDelegate: InterstitialEventInteractionDelegate { - /*! - @abstract Call this when the ad server SDK decides the use has earned reward - */ - func userDidEarnReward(_ reward: NSObject?) + /// Call this when the ad server SDK decides the use has earned reward + func userDidEarnReward(_ reward: PrebidReward) } - From c4662ca12ccf3be147820637510ff363ccf02e34 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Thu, 3 Oct 2024 13:12:44 +0300 Subject: [PATCH 03/18] fix: resolve warnings --- PrebidMobile/ConfigurationAndTargeting/Prebid.swift | 2 +- PrebidMobile/Dispatcher.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PrebidMobile/ConfigurationAndTargeting/Prebid.swift b/PrebidMobile/ConfigurationAndTargeting/Prebid.swift index db6438197..de2ec6461 100644 --- a/PrebidMobile/ConfigurationAndTargeting/Prebid.swift +++ b/PrebidMobile/ConfigurationAndTargeting/Prebid.swift @@ -267,6 +267,6 @@ public class Prebid: NSObject { } public static func containsPluginRenderer(_ prebidMobilePluginRenderer: PrebidMobilePluginRenderer) { - PrebidMobilePluginRegister.shared.containsPlugin(prebidMobilePluginRenderer); + _ = PrebidMobilePluginRegister.shared.containsPlugin(prebidMobilePluginRenderer); } } diff --git a/PrebidMobile/Dispatcher.swift b/PrebidMobile/Dispatcher.swift index f3d9711c4..80b17a1d2 100644 --- a/PrebidMobile/Dispatcher.swift +++ b/PrebidMobile/Dispatcher.swift @@ -27,7 +27,7 @@ class Dispatcher: NSObject { case stopped } - private (set) var state = State.notStarted + private(set) var state = State.notStarted var timer: Timer? From 9c88174558fde69260fe762b7462b65f365a9631 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Fri, 4 Oct 2024 13:57:43 +0300 Subject: [PATCH 04/18] refactor: introduce base interstitial and base rewarded internal classes --- .../InternalTestApp.xcodeproj/project.pbxproj | 18 +- .../Resources/Info.plist | 2 - .../OpenX/PrebidInterstitialController.swift | 7 +- PrebidMobile.xcodeproj/project.pbxproj | 28 +- .../AdTypes/AdView/AdConfiguration.swift | 1 - .../AdLoadFlowControllerDelegate.swift | 2 - .../GAM/AdLoading/PBMAdLoadFlowController.h | 1 + .../GAM/AdLoading/PBMAdLoadFlowController.m | 12 +- .../GAM/AdLoading/PBMInterstitialAdLoader.h | 4 +- .../GAM/AdLoading/PBMInterstitialAdLoader.m | 20 +- .../PBMInterstitialAdLoaderDelegate.h | 8 +- .../Prebid/Integrations/GAM/BannerView.swift | 1 + .../GAM/BaseInterstitialAdUnit.swift | 567 ++++-------------- .../GAM/BaseInterstitialAdUnitProtocol.swift | 4 +- .../Integrations/GAM/BaseRewardedAdUnit.swift | 41 ++ .../GAM/InterstitialRenderingAdUnit.swift | 394 ++++++++---- .../Integrations/GAM/RewardedAdUnit.swift | 349 +++++++---- .../RewardedEventInteractionDelegate.swift | 2 +- .../GAM/RewardedEventLoadingDelegate.swift | 5 +- .../Prebid/PBMCore/AdUnitConfig.swift | 33 +- .../Tests/PBMCreativeFactoryTest.swift | 2 +- .../RenderingTests/Tests/PBMWebViewObjCTest.m | 2 +- .../RenderingTests/Tests/PBMWebViewTest.swift | 8 +- .../BasicParameterBuilderTest.swift | 13 +- .../PrebidParameterBuilderTest.swift | 23 +- .../PBMAdLoadFlowControllerTest.swift | 35 +- .../Prebid/BaseInterstitialAdUnitTest.swift | 41 +- ...aseInterstitialAdUnit_DelegationTest.swift | 82 +-- 28 files changed, 888 insertions(+), 817 deletions(-) create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift diff --git a/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj b/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj index d2cf1fe9b..5d871d749 100644 --- a/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj +++ b/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj @@ -640,13 +640,13 @@ 349302192473F2EF004A6086 /* Prebid */ = { isa = PBXGroup; children = ( + 92E92500276B2986002B57F3 /* AdMob */, 3CC4A3E72C11F93A00B97128 /* CustomRenderer */, + 3493021A2473F2FB004A6086 /* GAM */, + 9289873D28003BFE0062BFAA /* MAX */, 3461835425A6020500783A2C /* NativeAdViewBox.swift */, AC4F253825DFF6300095C601 /* NativeAdViewBoxLinks.swift */, AC4F254A25E0112C0095C601 /* NativeAdViewBoxProtocol.swift */, - 92E92500276B2986002B57F3 /* AdMob */, - 3493021A2473F2FB004A6086 /* GAM */, - 9289873D28003BFE0062BFAA /* MAX */, 3493022024740BD8004A6086 /* OpenX */, 5397BD122936180600ABDA22 /* OriginalAPI */, ); @@ -801,20 +801,20 @@ 5B3EEDB12101D1AF00BAA0C4 /* ViewControllers */ = { isa = PBXGroup; children = ( - 5B8EB5EC226768D1003CC15C /* TableCells */, 5B3EEDBE2101D1AF00BAA0C4 /* AboutViewController.swift */, - 5B39E0CA211455B000BBB68F /* Adapters */, 5B6EB3CC211336D300317ED9 /* AdapterViewController.swift */, + ACBBDF842397E10E006D5FE6 /* CommandArgsViewController.swift */, 5BCCA3D52136D2E800DA3B5A /* ConfigurableViewController.swift */, - 5B3EEDB32101D1AF00BAA0C4 /* Configuration */, + 34BAD457239564740042DB33 /* IABConsentViewController.swift */, + ACC41AC92444E50B00B9A3A7 /* SettingsViewController.swift */, D551B9702149207500FFF51D /* TabNavigationController.swift */, 5B3EEDDB2101DB7900BAA0C4 /* TabViewController.swift */, 5B3EEDE12101EDA200BAA0C4 /* TestCasesSectionsViewController.swift */, 5B3EEDDD2101EA9200BAA0C4 /* TestCasesViewController.swift */, 34E56989237DB96900B47B01 /* UtilitiesViewController.swift */, - 34BAD457239564740042DB33 /* IABConsentViewController.swift */, - ACBBDF842397E10E006D5FE6 /* CommandArgsViewController.swift */, - ACC41AC92444E50B00B9A3A7 /* SettingsViewController.swift */, + 5B39E0CA211455B000BBB68F /* Adapters */, + 5B3EEDB32101D1AF00BAA0C4 /* Configuration */, + 5B8EB5EC226768D1003CC15C /* TableCells */, ); path = ViewControllers; sourceTree = ""; diff --git a/InternalTestApp/PrebidMobileDemoRendering/Resources/Info.plist b/InternalTestApp/PrebidMobileDemoRendering/Resources/Info.plist index 9da4dcdb2..7e4d40308 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/Resources/Info.plist +++ b/InternalTestApp/PrebidMobileDemoRendering/Resources/Info.plist @@ -2,8 +2,6 @@ - AppLovinSdkKey - 1tLUnP4cVQqpHuHH2yMtfdESvvUhTB05NdbCoDTceDDNVnhd_T8kwIzXDN9iwbdULTboByF-TtNaiTmsoVbxZw CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OpenX/PrebidInterstitialController.swift b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OpenX/PrebidInterstitialController.swift index f6d947a00..0669b1e79 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OpenX/PrebidInterstitialController.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OpenX/PrebidInterstitialController.swift @@ -70,8 +70,11 @@ class PrebidInterstitialController: NSObject, AdaptedController, PrebidConfigura Prebid.shared.storedAuctionResponse = storedAuctionResponse } - interstitialController = InterstitialRenderingAdUnit(configID: prebidConfigId, - minSizePercentage: CGSize(width: 30, height: 30)) + interstitialController = InterstitialRenderingAdUnit( + configID: prebidConfigId, + minSizePercentage: CGSize(width: 30, height: 30) + ) + interstitialController?.delegate = self // Custom video configuarion diff --git a/PrebidMobile.xcodeproj/project.pbxproj b/PrebidMobile.xcodeproj/project.pbxproj index 7df05f2f4..95ad601e2 100644 --- a/PrebidMobile.xcodeproj/project.pbxproj +++ b/PrebidMobile.xcodeproj/project.pbxproj @@ -101,6 +101,8 @@ 53A368EB2AB2E95E00A03B3E /* NativeParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A368EA2AB2E95E00A03B3E /* NativeParameters.swift */; }; 53A368F12AB83C9D00A03B3E /* PrebidRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A368F02AB83C9D00A03B3E /* PrebidRequestTests.swift */; }; 53A447CD2CAE9F8E008DE6C0 /* PrebidReward.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A447CC2CAE9F8E008DE6C0 /* PrebidReward.swift */; }; + 53A447CF2CAEA65A008DE6C0 /* BaseInterstitialAdUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A447CE2CAEA65A008DE6C0 /* BaseInterstitialAdUnit.swift */; }; + 53A447D12CAECA3C008DE6C0 /* BaseRewardedAdUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A447D02CAECA3C008DE6C0 /* BaseRewardedAdUnit.swift */; }; 53A6579E2A860F5800AE0B4F /* CacheExpiryDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A6579D2A860F5800AE0B4F /* CacheExpiryDelegate.swift */; }; 53A657A02A860F7200AE0B4F /* CacheExpiryDelegateWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A6579F2A860F7200AE0B4F /* CacheExpiryDelegateWrapper.swift */; }; 53A657B02A8B64C200AE0B4F /* PBMORTBSDKConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 53A657AF2A8B64C200AE0B4F /* PBMORTBSDKConfiguration.m */; }; @@ -480,7 +482,6 @@ 5BC37A8C271F1D0000444D5E /* BaseInterstitialAdUnitProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC37849271F1CFF00444D5E /* BaseInterstitialAdUnitProtocol.swift */; }; 5BC37A8D271F1D0000444D5E /* InterstitialRenderingAdUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784A271F1CFF00444D5E /* InterstitialRenderingAdUnit.swift */; }; 5BC37A8E271F1D0000444D5E /* RewardedAdUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784B271F1CFF00444D5E /* RewardedAdUnit.swift */; }; - 5BC37A8F271F1D0000444D5E /* BaseInterstitialAdUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784C271F1CFF00444D5E /* BaseInterstitialAdUnit.swift */; }; 5BC37A90271F1D0000444D5E /* InterstitialAdUnitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784D271F1CFF00444D5E /* InterstitialAdUnitDelegate.swift */; }; 5BC37A91271F1D0000444D5E /* InterstitialEventLoadingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784E271F1CFF00444D5E /* InterstitialEventLoadingDelegate.swift */; }; 5BC37A92271F1D0000444D5E /* RewardedEventLoadingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784F271F1CFF00444D5E /* RewardedEventLoadingDelegate.swift */; }; @@ -964,6 +965,8 @@ 53A368EA2AB2E95E00A03B3E /* NativeParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeParameters.swift; sourceTree = ""; }; 53A368F02AB83C9D00A03B3E /* PrebidRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidRequestTests.swift; sourceTree = ""; }; 53A447CC2CAE9F8E008DE6C0 /* PrebidReward.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidReward.swift; sourceTree = ""; }; + 53A447CE2CAEA65A008DE6C0 /* BaseInterstitialAdUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseInterstitialAdUnit.swift; sourceTree = ""; }; + 53A447D02CAECA3C008DE6C0 /* BaseRewardedAdUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseRewardedAdUnit.swift; sourceTree = ""; }; 53A6579D2A860F5800AE0B4F /* CacheExpiryDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheExpiryDelegate.swift; sourceTree = ""; }; 53A6579F2A860F7200AE0B4F /* CacheExpiryDelegateWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheExpiryDelegateWrapper.swift; sourceTree = ""; }; 53A657AE2A8B64B300AE0B4F /* PBMORTBSDKConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBSDKConfiguration.h; sourceTree = ""; }; @@ -1347,7 +1350,6 @@ 5BC37849271F1CFF00444D5E /* BaseInterstitialAdUnitProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseInterstitialAdUnitProtocol.swift; sourceTree = ""; }; 5BC3784A271F1CFF00444D5E /* InterstitialRenderingAdUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterstitialRenderingAdUnit.swift; sourceTree = ""; }; 5BC3784B271F1CFF00444D5E /* RewardedAdUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardedAdUnit.swift; sourceTree = ""; }; - 5BC3784C271F1CFF00444D5E /* BaseInterstitialAdUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseInterstitialAdUnit.swift; sourceTree = ""; }; 5BC3784D271F1CFF00444D5E /* InterstitialAdUnitDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterstitialAdUnitDelegate.swift; sourceTree = ""; }; 5BC3784E271F1CFF00444D5E /* InterstitialEventLoadingDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterstitialEventLoadingDelegate.swift; sourceTree = ""; }; 5BC3784F271F1CFF00444D5E /* RewardedEventLoadingDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardedEventLoadingDelegate.swift; sourceTree = ""; }; @@ -2542,8 +2544,9 @@ 5BC37842271F1CFF00444D5E /* BannerEventLoadingDelegate.swift */, 5BC37843271F1CFF00444D5E /* BannerView.swift */, 5BC37847271F1CFF00444D5E /* BannerViewDelegate.swift */, - 5BC3784C271F1CFF00444D5E /* BaseInterstitialAdUnit.swift */, + 53A447CE2CAEA65A008DE6C0 /* BaseInterstitialAdUnit.swift */, 5BC37849271F1CFF00444D5E /* BaseInterstitialAdUnitProtocol.swift */, + 53A447D02CAECA3C008DE6C0 /* BaseRewardedAdUnit.swift */, 5BC3784D271F1CFF00444D5E /* InterstitialAdUnitDelegate.swift */, 5BC37854271F1CFF00444D5E /* InterstitialEventHandlerProtocol.swift */, 5BC37844271F1CFF00444D5E /* InterstitialEventInteractionDelegate.swift */, @@ -2564,19 +2567,19 @@ 5BC37855271F1CFF00444D5E /* AdLoading */ = { isa = PBXGroup; children = ( - 5BC37856271F1CFF00444D5E /* PBMBannerAdLoader.m */, - 5BC37857271F1CFF00444D5E /* PBMInterstitialAdLoader.m */, + 5BC37861271F1CFF00444D5E /* AdLoadFlowControllerDelegate.swift */, 5BC37858271F1CFF00444D5E /* BannerAdLoaderDelegate.swift */, - 5BC37859271F1CFF00444D5E /* PBMAdLoadFlowController+PrivateState.h */, + 5BC3785E271F1CFF00444D5E /* PBMAdLoaderFlowDelegate.h */, 5BC3785A271F1CFF00444D5E /* PBMAdLoaderProtocol.h */, 5BC3785B271F1CFF00444D5E /* PBMAdLoadFlowController.h */, + 5BC37862271F1CFF00444D5E /* PBMAdLoadFlowController.m */, + 5BC37859271F1CFF00444D5E /* PBMAdLoadFlowController+PrivateState.h */, 5BC3785C271F1CFF00444D5E /* PBMAdLoadFlowState.h */, - 5BC3785D271F1CFF00444D5E /* PBMInterstitialAdLoaderDelegate.h */, - 5BC3785E271F1CFF00444D5E /* PBMAdLoaderFlowDelegate.h */, - 5BC3785F271F1CFF00444D5E /* PBMInterstitialAdLoader.h */, 5BC37860271F1CFF00444D5E /* PBMBannerAdLoader.h */, - 5BC37861271F1CFF00444D5E /* AdLoadFlowControllerDelegate.swift */, - 5BC37862271F1CFF00444D5E /* PBMAdLoadFlowController.m */, + 5BC37856271F1CFF00444D5E /* PBMBannerAdLoader.m */, + 5BC3785F271F1CFF00444D5E /* PBMInterstitialAdLoader.h */, + 5BC37857271F1CFF00444D5E /* PBMInterstitialAdLoader.m */, + 5BC3785D271F1CFF00444D5E /* PBMInterstitialAdLoaderDelegate.h */, ); path = AdLoading; sourceTree = ""; @@ -4107,6 +4110,7 @@ 5BC37A62271F1D0000444D5E /* PBMORTBBidExtPrebidCacheBids.m in Sources */, 929865392806CCC4007A2F34 /* UIView+Extensions.swift in Sources */, 5BC37997271F1D0000444D5E /* PBMAbstractCreative.m in Sources */, + 53A447D12CAECA3C008DE6C0 /* BaseRewardedAdUnit.swift in Sources */, 92EE5A0D27F9D292003D7691 /* Position.swift in Sources */, 92C3A83627F989E200DC05E9 /* AutoRefreshCountConfig.swift in Sources */, 5BC37A72271F1D0000444D5E /* BidResponse.swift in Sources */, @@ -4135,7 +4139,6 @@ 531CF21927E8FC1B005E5ABE /* LogLevel.swift in Sources */, FAEE4D1E262DC2B200AD9966 /* VideoInterstitialAdUnit.swift in Sources */, 5BC378FF271F1CFF00444D5E /* PBMORTBImpExtPrebid.m in Sources */, - 5BC37A8F271F1D0000444D5E /* BaseInterstitialAdUnit.swift in Sources */, 5BC37A14271F1D0000444D5E /* PBMError_Extension.swift in Sources */, 34C9CD602850CE6300FB5451 /* OMSDKVersionProvider.m in Sources */, 5BC378B3271F1CFF00444D5E /* NSException+PBMExtensions.m in Sources */, @@ -4144,6 +4147,7 @@ 92028EA627F0D89E00783470 /* NativeAdConfiguration.swift in Sources */, 5BC379C5271F1D0000444D5E /* PBMAdRequesterVAST.m in Sources */, 5BC378E0271F1CFF00444D5E /* PBMORTBFormat.m in Sources */, + 53A447CF2CAEA65A008DE6C0 /* BaseInterstitialAdUnit.swift in Sources */, 5BC37953271F1D0000444D5E /* PBMCreativeFactoryJob.m in Sources */, 5BC378B8271F1CFF00444D5E /* PBMViewExposureChecker.m in Sources */, 5BC37978271F1D0000444D5E /* PBMVastCreativeNonLinearAdsNonLinear.m in Sources */, diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift index ef40ed066..663641e3b 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift @@ -141,5 +141,4 @@ public class AdConfiguration: AutoRefreshCountConfig { } return [:] } - } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/AdLoadFlowControllerDelegate.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/AdLoadFlowControllerDelegate.swift index 3935fa9e8..227077c05 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/AdLoadFlowControllerDelegate.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/AdLoadFlowControllerDelegate.swift @@ -17,8 +17,6 @@ import Foundation @objc public protocol AdLoadFlowControllerDelegate: NSObjectProtocol { - var adUnitConfig:AdUnitConfig { get } - // Loading callbacks @objc func adLoadFlowController(_ adLoadFlowController: PBMAdLoadFlowController, failedWithError error: Error?) diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMAdLoadFlowController.h b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMAdLoadFlowController.h index b9bdea502..39c2ee040 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMAdLoadFlowController.h +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMAdLoadFlowController.h @@ -44,6 +44,7 @@ typedef BOOL(^PBMAdUnitConfigValidationBlock)(AdUnitConfig *adUnitConfig, BOOL r - (instancetype)initWithBidRequesterFactory:(id (^)(AdUnitConfig *))bidRequesterFactory adLoader:(id)adLoader + adUnitConfig:(AdUnitConfig *)adUnitConfig delegate:(id)delegate configValidationBlock:(PBMAdUnitConfigValidationBlock)configValidationBlock; diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMAdLoadFlowController.m b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMAdLoadFlowController.m index 786e66943..92bbcbb4e 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMAdLoadFlowController.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMAdLoadFlowController.m @@ -38,6 +38,7 @@ @implementation PBMAdLoadFlowController - (instancetype)initWithBidRequesterFactory:(id (^)(AdUnitConfig *))bidRequesterFactory adLoader:(id)adLoader + adUnitConfig:(AdUnitConfig *)adUnitConfig delegate:(id)delegate configValidationBlock:(PBMAdUnitConfigValidationBlock)configValidationBlock { @@ -49,6 +50,7 @@ - (instancetype)initWithBidRequesterFactory:(id (^)(AdU _adLoader = adLoader; _delegate = delegate; _configValidationBlock = [configValidationBlock copy]; + _savedAdUnitConfig = adUnitConfig; NSString * const uuid = [[NSUUID UUID] UUIDString]; const char * const queueName = [[NSString stringWithFormat:@"PBMAdLoadFlowController_%@", uuid] UTF8String]; @@ -195,14 +197,13 @@ - (void)moveToNextLoadingStep { } - (void)tryLaunchingAdRequestFlow { - AdUnitConfig * const configClone = [self.delegate.adUnitConfig copy]; - const BOOL configIsValid = self.configValidationBlock(configClone, NO); + const BOOL configIsValid = self.configValidationBlock(self.savedAdUnitConfig, NO); if (!configIsValid) { - [self reportLoadingFailedWithError:[PBMError errorWithMessage:@"AdUnitConfig is not valid." type:PBMErrorTypeInternalError]]; + [self reportLoadingFailedWithError:[PBMError errorWithMessage:@"AdUnitConfig is not valid." + type:PBMErrorTypeInternalError]]; return; } - self.savedAdUnitConfig = configClone; [self.delegate adLoadFlowControllerWillSendBidRequest:self]; [self sendBidRequest]; @@ -261,7 +262,8 @@ - (void)loadPrebidDisplayView { const BOOL configIsValid = self.configValidationBlock(self.savedAdUnitConfig, YES); if (!configIsValid) { - [self reportLoadingFailedWithError:[PBMError errorWithMessage:@"AdUnitConfig is not valid." type:PBMErrorTypeInternalError]]; + [self reportLoadingFailedWithError:[PBMError errorWithMessage:@"AdUnitConfig is not valid." + type:PBMErrorTypeInternalError]]; return; } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.h b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.h index cca15584b..761d76898 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.h +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.h @@ -23,9 +23,9 @@ NS_ASSUME_NONNULL_BEGIN @interface PBMInterstitialAdLoader : NSObject -- (instancetype)initWithDelegate:(id)delegate; +- (instancetype)initWithDelegate:(id)delegate + eventHandler:(id)eventHandler; -@property (nonatomic, strong) NSObject *reward; @end NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.m b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.m index 784755f68..b15985412 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.m @@ -29,10 +29,11 @@ #endif @interface PBMInterstitialAdLoader () -@property (nonatomic, weak, nullable, readonly) id delegate; -@end +@property (nonatomic, weak, nullable, readonly) id delegate; +@property (nonatomic, weak, nullable, readonly) id eventHandler; +@end @implementation PBMInterstitialAdLoader @@ -40,18 +41,23 @@ @implementation PBMInterstitialAdLoader // MARK: - Lifecycle -- (instancetype)initWithDelegate:(id)delegate { +- (instancetype)initWithDelegate:(id)delegate + eventHandler:(nonnull id)eventHandler { + if (!(self = [super init])) { return nil; } + _delegate = delegate; + _eventHandler = eventHandler; + return self; } // MARK: - PBMAdLoaderProtocol - (id)primaryAdRequester { - return self.delegate.eventHandler; + return self.eventHandler; } - (void)createPrebidAdWithBid:(Bid *)bid @@ -59,8 +65,8 @@ - (void)createPrebidAdWithBid:(Bid *)bid adObjectSaver:(void (^)(id))adObjectSaver loadMethodInvoker:(void (^)(dispatch_block_t))loadMethodInvoker { - InterstitialController * const controller = [[InterstitialController alloc] initWithBid:bid - adConfiguration:adUnitConfig]; + InterstitialController * const controller = [[InterstitialController alloc] initWithBid:bid + adConfiguration:adUnitConfig]; adObjectSaver(controller); @weakify(self); loadMethodInvoker(^{ @@ -119,7 +125,7 @@ - (void)prebidDidWin { } - (void)adServerDidWin { - [self.flowDelegate adLoader:self loadedPrimaryAd:self.delegate.eventHandler adSize:nil]; + [self.flowDelegate adLoader:self loadedPrimaryAd:self.eventHandler adSize:nil]; } - (void)failedWithError:(nullable NSError *)error { diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoaderDelegate.h b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoaderDelegate.h index ea96bcb33..84008eb65 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoaderDelegate.h +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoaderDelegate.h @@ -26,21 +26,15 @@ NS_ASSUME_NONNULL_BEGIN @required -@property (nonatomic, strong, nullable, readonly) id eventHandler; - // Loading callbacks - (void)interstitialAdLoader:(PBMInterstitialAdLoader *)interstitialAdLoader loadedAd:(void (^)(UIViewController * _Nullable))showBlock isReadyBlock:(BOOL (^)(void))isReadyBlock; // Hook to insert interaction delegate -- (void) interstitialAdLoader:(PBMInterstitialAdLoader *)interstitialAdLoader +- (void)interstitialAdLoader:(PBMInterstitialAdLoader *)interstitialAdLoader createdInterstitialController:(InterstitialController *)interstitialController; -@optional - -@property (nonatomic, strong, nullable) NSObject *reward; - @end NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BannerView.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BannerView.swift index d2db18d6d..de71986a5 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BannerView.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BannerView.swift @@ -156,6 +156,7 @@ public class BannerView: UIView, adUnitConfiguration: adUnitConfig) }, adLoader: bannerAdLoader, + adUnitConfig: adUnitConfig, delegate: self, configValidationBlock: { adUnitConfig, renderWithPrebid in true diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift index 3d4938b09..9a800cf11 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift @@ -1,66 +1,54 @@ /*   Copyright 2018-2021 Prebid.org, Inc. + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -import Foundation import UIKit -/// A base class for interstitial ad units. -public class BaseInterstitialAdUnit : +@objcMembers +class BaseInterstitialAdUnit: NSObject, PBMInterstitialAdLoaderDelegate, AdLoadFlowControllerDelegate, InterstitialControllerInteractionDelegate, - InterstitialEventInteractionDelegate, - BaseInterstitialAdUnitProtocol { + InterstitialEventInteractionDelegate { - // MARK: - Public Properties + // MARK: - Internal Properties - /// The banner parameters used for configuring ad unit. - @objc public var bannerParameters: BannerParameters { - get { adUnitConfig.adConfiguration.bannerParameters } - } + let adUnitConfig: AdUnitConfig + let eventHandler: PBMPrimaryAdRequesterProtocol - /// The video parameters used for configuring ad unit. - @objc public var videoParameters: VideoParameters { - get { adUnitConfig.adConfiguration.videoParameters } + weak var delegate: BaseInterstitialAdUnitProtocol? { + didSet { + if let adLoader { + delegate?.callEventHandler_setLoadingDelegate(adLoader) + } + } } - /// The last bid response received for the ad unit. - @objc public var lastBidResponse: BidResponse? { - return adLoadFlowController?.bidResponse + var bannerParameters: BannerParameters { + get { adUnitConfig.adConfiguration.bannerParameters } } - /// The configuration ID for the ad unit. - @objc public var configID: String { - adUnitConfig.configId + var videoParameters: VideoParameters { + get { adUnitConfig.adConfiguration.videoParameters } } - /// The set of ad formats supported by this ad unit. - @objc public var adFormats: Set { - get { adUnitConfig.adFormats } - set { adUnitConfig.adFormats = newValue } + var lastBidResponse: BidResponse? { + adLoadFlowController?.bidResponse } - /// The ORTB (OpenRTB) configuration string for the ad unit. - @objc public var ortbConfig: String? { - get { adUnitConfig.ortbConfig } - set { adUnitConfig.ortbConfig = newValue } - } - - /// A Boolean value indicating whether the ad unit is ready to be displayed. - @objc public var isReady: Bool { + var isReady: Bool { objc_sync_enter(blocksLockToken) if let block = isReadyBlock { let res = block() @@ -71,333 +59,97 @@ public class BaseInterstitialAdUnit : objc_sync_exit(blocksLockToken) return false } - - /// A Boolean value indicating whether the video controls are muted. - @objc public var isMuted: Bool { - get { adUnitConfig.adConfiguration.videoControlsConfig.isMuted } - set { adUnitConfig.adConfiguration.videoControlsConfig.isMuted = newValue } - } - - /// A Boolean value indicating whether the sound button is visible in the video controls. - @objc public var isSoundButtonVisible: Bool { - get { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible } - set { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible = newValue } - } - - /// The area of the close button in the video controls as a percentage. - @objc public var closeButtonArea: Double { - get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea } - set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea = newValue } - } - - /// The position of the close button in the video controls. - @objc public var closeButtonPosition: Position { - get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition } - set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition = newValue } - } - - /// A delegate for handling interactions with the ad unit. - @objc public weak var delegate: AnyObject? - - /// The configuration object for the ad unit. - public let adUnitConfig: AdUnitConfig // MARK: - Private Properties private var adLoadFlowController: PBMAdLoadFlowController! private let blocksLockToken: NSObject - private var showBlock: ((UIViewController?) -> Void)? private var currentAdBlock: ((UIViewController?) -> Void)? private var isReadyBlock: (() -> Bool)? - - private weak var targetController: UIViewController? + private var adLoader: PBMInterstitialAdLoader? - // MARK: - Public Methods + private weak var targetController: UIViewController? - /// Initializes a new `BaseInterstitialAdUnit` with the specified configuration ID, minimum size percentage, and event handler. - /// - Parameters: - /// - configID: The unique identifier for the ad unit configuration. - /// - minSizePerc: The minimum size percentage for the ad unit. - /// - eventHandler: An optional event handler object for handling ad events. - required public init(configID: String, - minSizePerc: NSValue?, - eventHandler: AnyObject?) { - + init( + configID: String, + minSizePerc: NSValue?, + eventHandler: PBMPrimaryAdRequesterProtocol + ) { adUnitConfig = AdUnitConfig(configId: configID) - adUnitConfig.adConfiguration.isInterstitialAd = true - adUnitConfig.minSizePerc = minSizePerc - adUnitConfig.adPosition = .fullScreen - adUnitConfig.adConfiguration.adFormats = [.banner, .video] - adUnitConfig.adConfiguration.bannerParameters.api = PrebidConstants.supportedRenderingBannerAPISignals blocksLockToken = NSObject() - + self.eventHandler = eventHandler - + super.init() - videoParameters.placement = .Interstitial + let adLoader = PBMInterstitialAdLoader( + delegate: self, + eventHandler: eventHandler + ) - let adLoader = PBMInterstitialAdLoader(delegate: self) - callEventHandler_setLoadingDelegate(adLoader) + self.adLoader = adLoader - adLoadFlowController = PBMAdLoadFlowController(bidRequesterFactory: { adUnitConfig in - return PBMBidRequester(connection: PrebidServerConnection.shared, - sdkConfiguration: Prebid.shared, - targeting: Targeting.shared, - adUnitConfiguration: adUnitConfig) - }, - adLoader: adLoader, - delegate: self, - configValidationBlock: { _,_ in true } ) - } - - /// Initializes a new `BaseInterstitialAdUnit` with the specified configuration ID, minimum size percentage, and event handler. - /// - Parameters: - /// - configID: The unique identifier for the ad unit configuration. - /// - minSizePercentage: The minimum size percentage for the ad unit. - /// - eventHandler: An optional event handler object for handling ad events. - public convenience init(configID: String, - minSizePercentage: CGSize, - eventHandler:AnyObject?) - { - self.init(configID: configID, - minSizePerc:NSValue(cgSize: minSizePercentage), - eventHandler: eventHandler) - } - - /// Initializes a new `BaseInterstitialAdUnit` with the specified configuration ID and event handler. - /// - Parameters: - /// - configID: The unique identifier for the ad unit configuration. - /// - eventHandler: An optional event handler object for handling ad events. - public convenience init(configID: String, - eventHandler:AnyObject?) { - self.init(configID: configID, - minSizePerc:nil, - eventHandler: eventHandler) + adLoadFlowController = PBMAdLoadFlowController( + bidRequesterFactory: { adUnitConfig in + return PBMBidRequester( + connection: PrebidServerConnection.shared, + sdkConfiguration: Prebid.shared, + targeting: Targeting.shared, + adUnitConfiguration: adUnitConfig + ) + }, + adLoader: adLoader, + adUnitConfig: adUnitConfig, + delegate: self, + configValidationBlock: { _, _ in true } + ) + // Set default values + adUnitConfig.adConfiguration.isInterstitialAd = true + adUnitConfig.minSizePerc = minSizePerc + adUnitConfig.adPosition = .fullScreen + adUnitConfig.adConfiguration.adFormats = [.banner, .video] + adUnitConfig.adConfiguration.bannerParameters.api = PrebidConstants.supportedRenderingBannerAPISignals + videoParameters.placement = .Interstitial } - - /// Initializes a new `BaseInterstitialAdUnit` with the specified configuration ID and minimum size percentage. - /// - Parameters: - /// - configID: The unique identifier for the ad unit configuration. - /// - minSizePercentage: The minimum size percentage for the ad unit. - public convenience init(configID: String, - minSizePercentage:CGSize) { - - self.init(configID: configID, - minSizePerc:NSValue(cgSize: minSizePercentage), - eventHandler: nil) - } - - /// Initializes a new `BaseInterstitialAdUnit` with the specified configuration ID. - /// - Parameter configID: The unique identifier for the ad unit configuration. - public convenience init(configID: String) { - self.init(configID: configID, - minSizePerc:nil, - eventHandler: nil) } // MARK: - Public Methods - /// Loads a new ad. - @objc public func loadAd() { + func loadAd() { adLoadFlowController.refresh() } - /// Shows the ad from a specified view controller. - /// - Parameter controller: The view controller from which the ad will be presented. - /// - Note: This method must be called on the main thread. - @objc public func show(from controller: UIViewController) { + func show(from controller: UIViewController) { // It is expected from the user to call this method on main thread assert(Thread.isMainThread, "Expected to only be called on the main thread"); - + objc_sync_enter(blocksLockToken) - - guard self.showBlock != nil, - self.currentAdBlock == nil else { - objc_sync_exit(blocksLockToken) - return; - } - isReadyBlock = nil; - currentAdBlock = showBlock; - showBlock = nil; - callDelegate_willPresentAd() - targetController = controller; - currentAdBlock?(controller); + guard self.showBlock != nil, + self.currentAdBlock == nil else { objc_sync_exit(blocksLockToken) - - } - - // MARK: - Ext Data (imp[].ext.data) - - /// Adds context data for a specified key. - /// - Parameters: - /// - data: The data to add. - /// - key: The key associated with the data. - @available(*, deprecated, message: "This method is deprecated. Please, use addExtData method instead.") - @objc public func addContextData(_ data: String, forKey key: String) { - addExtData(key: key, value: data) - } - - /// Updates context data for a specified key. - /// - Parameters: - /// - data: A set of data to update. - /// - key: The key associated with the data. - @available(*, deprecated, message: "This method is deprecated. Please, use updateExtData method instead.") - @objc public func updateContextData(_ data: Set, forKey key: String) { - updateExtData(key: key, value: data) - } - - /// Removes context data for a specified key. - /// - Parameter key: The key associated with the data to remove. - @available(*, deprecated, message: "This method is deprecated. Please, use removeExtData method instead.") - @objc public func removeContextDate(forKey key: String) { - removeExtData(forKey: key) - } - - /// Clears all context data. - @available(*, deprecated, message: "This method is deprecated. Please, use clearExtData method instead.") - @objc public func clearContextData() { - clearExtData() - } - - /// Adds ext data. - /// - Parameters: - /// - key: The key for the data. - /// - value: The value for the data. - @objc public func addExtData(key: String, value: String) { - adUnitConfig.addExtData(key: key, value: value) - } - - /// Updates ext data. - /// - Parameters: - /// - key: The key for the data. - /// - value: The value for the data. - @objc public func updateExtData(key: String, value: Set) { - adUnitConfig.updateExtData(key: key, value: value) - } - - /// Removes ext data. - /// - Parameters: - /// - key: The key for the data. - @objc public func removeExtData(forKey: String) { - adUnitConfig.removeExtData(for: forKey) - } - - /// Clears ext data. - @objc public func clearExtData() { - adUnitConfig.clearExtData() - } - - // MARK: - Ext keywords (imp[].ext.keywords) - - /// Adds a context keyword. - /// - Parameter newElement: The keyword to add. - @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeyword method instead.") - @objc public func addContextKeyword(_ newElement: String) { - addExtKeyword(newElement) - } - - /// Adds a set of context keywords. - /// - Parameter newElements: A set of keywords to add. - @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeywords method instead.") - @objc public func addContextKeywords(_ newElements: Set) { - addExtKeywords(newElements) - } - - /// Removes a context keyword. - /// - Parameter element: The keyword to remove. - @available(*, deprecated, message: "This method is deprecated. Please, use removeExtKeyword method instead.") - @objc public func removeContextKeyword(_ element: String) { - removeExtKeyword(element) - } - - /// Clears all context keywords. - @available(*, deprecated, message: "This method is deprecated. Please, use clearExtKeywords method instead.") - @objc public func clearContextKeywords() { - clearExtKeywords() - } - - /// Adds an extended keyword. - /// - Parameter newElement: The keyword to be added. - @objc public func addExtKeyword(_ newElement: String) { - adUnitConfig.addExtKeyword(newElement) - } - - /// Adds multiple extended keywords. - /// - Parameter newElements: A set of keywords to be added. - @objc public func addExtKeywords(_ newElements: Set) { - adUnitConfig.addExtKeywords(newElements) - } - - /// Removes an extended keyword. - /// - Parameter element: The keyword to be removed. - @objc public func removeExtKeyword(_ element: String) { - adUnitConfig.removeExtKeyword(element) - } - - /// Clears all extended keywords. - @objc public func clearExtKeywords() { - adUnitConfig.clearExtKeywords() - } - - // MARK: - App Content (app.content.data) - - /// Sets the app content data. - /// - Parameter appContent: The app content data. - @objc public func setAppContent(_ appContent: PBMORTBAppContent) { - adUnitConfig.setAppContent(appContent) - } - - /// Clears the app content data. - @objc public func clearAppContent() { - adUnitConfig.clearAppContent() - } - - /// Adds app content data objects. - /// - Parameter dataObjects: The data objects to be added. - @objc public func addAppContentData(_ dataObjects: [PBMORTBContentData]) { - adUnitConfig.addAppContentData(dataObjects) - } - - /// Removes an app content data object. - /// - Parameter dataObject: The data object to be removed. - @objc public func removeAppContentDataObject(_ dataObject: PBMORTBContentData) { - adUnitConfig.removeAppContentData(dataObject) - } - - /// Clears all app content data objects. - @objc public func clearAppContentDataObjects() { - adUnitConfig.clearAppContentData() - } - - // MARK: - User Data (user.data) - - /// Adds user data objects. - /// - Parameter userDataObjects: The user data objects to be added. - @objc public func addUserData(_ userDataObjects: [PBMORTBContentData]) { - adUnitConfig.addUserData(userDataObjects) - } - - /// Removes a user data object. - /// - Parameter userDataObject: The user data object to be removed. - @objc public func removeUserData(_ userDataObject: PBMORTBContentData) { - adUnitConfig.removeUserData(userDataObject) - } - - /// Clears all user data objects. - @objc public func clearUserData() { - adUnitConfig.clearUserData() + return; + } + + isReadyBlock = nil + currentAdBlock = showBlock + showBlock = nil + + delegate?.callDelegate_willPresentAd() + targetController = controller + currentAdBlock?(controller) + objc_sync_exit(blocksLockToken) } // MARK: - PBMInterstitialAdLoaderDelegate - /// Internal delegate method. - public func interstitialAdLoader(_ interstitialAdLoader: PBMInterstitialAdLoader, - loadedAd showBlock: @escaping (UIViewController?) -> Void, - isReadyBlock: @escaping () -> Bool) { + public func interstitialAdLoader( + _ interstitialAdLoader: PBMInterstitialAdLoader, + loadedAd showBlock: @escaping (UIViewController?) -> Void, + isReadyBlock: @escaping () -> Bool + ) { objc_sync_enter(blocksLockToken) self.showBlock = showBlock self.isReadyBlock = isReadyBlock @@ -406,26 +158,20 @@ public class BaseInterstitialAdUnit : reportLoadingSuccess() } - /// Internal delegate method. - public func interstitialAdLoader(_ interstitialAdLoader: PBMInterstitialAdLoader, - createdInterstitialController interstitialController: InterstitialController) { + public func interstitialAdLoader( + _ interstitialAdLoader: PBMInterstitialAdLoader, + createdInterstitialController interstitialController: InterstitialController + ) { interstitialController.interactionDelegate = self } - - /// The event handler for the interstitial events. - public var eventHandler: Any? - // MARK: - AdLoadFlowControllerDelegate - /// Called when the ad load flow controller is about to send a bid request. - public func adLoadFlowControllerWillSendBidRequest(_ adLoadFlowController: PBMAdLoadFlowController) { - // nop - } + public func adLoadFlowControllerWillSendBidRequest(_ adLoadFlowController: PBMAdLoadFlowController) {} /// Called when the ad load flow controller is about to request the primary ad. public func adLoadFlowControllerWillRequestPrimaryAd(_ adLoadFlowController: PBMAdLoadFlowController) { - callEventHandler_setInteractionDelegate() + delegate?.callEventHandler_setInteractionDelegate() } /// Called to determine if the ad load flow controller should continue with the current flow. @@ -433,8 +179,10 @@ public class BaseInterstitialAdUnit : true } - /// Called when the ad load flow controller fails with an error. - public func adLoadFlowController(_ adLoadFlowController: PBMAdLoadFlowController, failedWithError error: Error?) { + public func adLoadFlowController( + _ adLoadFlowController: PBMAdLoadFlowController, + failedWithError error: Error? + ) { reportLoadingFailed(with: error) } @@ -443,63 +191,43 @@ public class BaseInterstitialAdUnit : /// Tracks an impression for the given interstitial controller. public func trackImpression(forInterstitialController: InterstitialController) { DispatchQueue.main.async { - self.callEventHandler_trackImpression() + self.delegate?.callEventHandler_trackImpression() } } /// Called when the ad in the interstitial controller is clicked. public func interstitialControllerDidClickAd(_ interstitialController: InterstitialController) { assert(Thread.isMainThread, "Expected to only be called on the main thread") - callDelegate_didClickAd() + delegate?.callDelegate_didClickAd() } /// Called when the ad in the interstitial controller is closed. public func interstitialControllerDidCloseAd(_ interstitialController: InterstitialController) { assert(Thread.isMainThread, "Expected to only be called on the main thread") - callDelegate_didDismissAd() + delegate?.callDelegate_didDismissAd() } /// Called when the ad in the interstitial controller causes the app to leave. public func interstitialControllerDidLeaveApp(_ interstitialController: InterstitialController) { assert(Thread.isMainThread, "Expected to only be called on the main thread") - callDelegate_willLeaveApplication() + delegate?.callDelegate_willLeaveApplication() } - /// Called when the interstitial controller displays an ad. - public func interstitialControllerDidDisplay(_ interstitialController: InterstitialController) { - - } - - /// Called when the interstitial controller completes the ad display. - public func interstitialControllerDidComplete(_ interstitialController: InterstitialController) { - - } + public func interstitialControllerDidDisplay(_ interstitialController: InterstitialController) {} + public func interstitialControllerDidComplete(_ interstitialController: InterstitialController) {} - /// Provides the view controller to use for modal presentation. - public func viewControllerForModalPresentation(fromInterstitialController: InterstitialController) -> UIViewController? { + public func viewControllerForModalPresentation( + fromInterstitialController: InterstitialController + ) -> UIViewController? { return targetController } - // MARK: - Private methods - - private func reportLoadingSuccess() { - DispatchQueue.main.async { - self.callDelegate_didReceiveAd() - } - } - - private func reportLoadingFailed(with error: Error?) { - DispatchQueue.main.async { - self.callDelegate_didFailToReceiveAd(with: error) - } - } - // MARK: - InterstitialEventInteractionDelegate /// Called when an ad is about to be presented. public func willPresentAd() { DispatchQueue.main.async { - self.callDelegate_willPresentAd() + self.delegate?.callDelegate_willPresentAd() } } @@ -510,90 +238,35 @@ public class BaseInterstitialAdUnit : objc_sync_exit(blocksLockToken) DispatchQueue.main.async { - self.callDelegate_didDismissAd() + self.delegate?.callDelegate_didDismissAd() } } /// Called when the ad causes the app to leave. public func willLeaveApp() { DispatchQueue.main.async { - self.callDelegate_willLeaveApplication() + self.delegate?.callDelegate_willLeaveApplication() } } /// Called when an ad is clicked. public func didClickAd() { DispatchQueue.main.async { - self.callDelegate_didClickAd() + self.delegate?.callDelegate_didClickAd() } } - - // MARK: - BaseInterstitialAdUnitProtocol - /// Requests an ad using the provided bid response. - public func callEventHandler_requestAd(with bidResponse: BidResponse?) { - - } + // MARK: - Private methods - /// Displays the ad using the provided view controller. - public func callEventHandler_show(from controller: UIViewController?) { - + private func reportLoadingSuccess() { + DispatchQueue.main.async { + self.delegate?.callDelegate_didReceiveAd() + } } - - // MARK: - Abstract Methods - /// Checks if the ad unit is ready to show an ad. - public func callEventHandler_isReady() -> Bool { - return false // to be overridden in subclass - } - - /// Notifies the delegate that an ad has been successfully received. - public func callDelegate_didReceiveAd() { - // to be overridden in subclass - } - - /// Notifies the delegate that the ad failed to load. - public func callDelegate_didFailToReceiveAd(with: Error?) { - // to be overridden in subclass - } - - /// Notifies the delegate that an ad is about to be presented. - public func callDelegate_willPresentAd() { - // to be overridden in subclass - } - - /// Notifies the delegate that an ad has been dismissed. - public func callDelegate_didDismissAd() { - // to be overridden in subclass - } - - /// Notifies the delegate that the app is about to leave due to an ad. - public func callDelegate_willLeaveApplication() { - // to be overridden in subclass - } - - /// Notifies the delegate that an ad has been clicked. - public func callDelegate_didClickAd() { - // to be overridden in subclass - } - - /// Sets the loading delegate for the event handler. - public func callEventHandler_setLoadingDelegate(_ loadingDelegate: NSObject?) { - // to be overridden in subclass - } - - /// Sets the interaction delegate for the event handler. - public func callEventHandler_setInteractionDelegate() { - // to be overridden in subclass - } - - /// Shows the ad from the provided view controller. - public func callEventHandler_showFromViewController(controller: UIViewController?) { - // to be overridden in subclass - } - - /// Tracks an impression for the ad. - public func callEventHandler_trackImpression() { - // to be overridden in subclass + private func reportLoadingFailed(with error: Error?) { + DispatchQueue.main.async { + self.delegate?.callDelegate_didFailToReceiveAd(with: error) + } } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnitProtocol.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnitProtocol.swift index 9b6877df8..308bdc29f 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnitProtocol.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnitProtocol.swift @@ -16,7 +16,7 @@ import Foundation import UIKit -@objc public protocol BaseInterstitialAdUnitProtocol: NSObjectProtocol { +@objc protocol BaseInterstitialAdUnitProtocol: NSObjectProtocol { @objc func interstitialControllerDidCloseAd(_ interstitialController: InterstitialController) @@ -33,4 +33,6 @@ import UIKit @objc func callEventHandler_requestAd(with bidResponse: BidResponse?) @objc func callEventHandler_show(from controller: UIViewController?) @objc func callEventHandler_trackImpression() + + @objc optional func callDelegate_rewardedAdUserDidEarnReward(reward: PrebidReward) } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift new file mode 100644 index 000000000..2abe40c8c --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift @@ -0,0 +1,41 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ + +import Foundation + +@objcMembers +class BaseRewardedAdUnit: BaseInterstitialAdUnit, RewardedEventInteractionDelegate { + + override init( + configID: String, + minSizePerc: NSValue?, + eventHandler: PBMPrimaryAdRequesterProtocol + ) { + super.init( + configID: configID, + minSizePerc: minSizePerc, + eventHandler: eventHandler + ) + + // Setup default values + adUnitConfig.adConfiguration.isRewarded = true + } + + func userDidEarnReward(_ interstitialController: InterstitialController, _ reward: PrebidReward) { + DispatchQueue.main.async { + self.delegate?.callDelegate_rewardedAdUserDidEarnReward?(reward: reward) + } + } +} diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialRenderingAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialRenderingAdUnit.swift index e0d9c5488..73d01f733 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialRenderingAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialRenderingAdUnit.swift @@ -1,157 +1,333 @@ /*   Copyright 2018-2021 Prebid.org, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ import UIKit /// Represents an interstitial ad unit. Built for rendering type of integration. @objcMembers -public class InterstitialRenderingAdUnit: BaseInterstitialAdUnit { +public class InterstitialRenderingAdUnit: NSObject, BaseInterstitialAdUnitProtocol { + + public weak var delegate: InterstitialAdUnitDelegate? + + public var isReady: Bool { + baseAdUnit.isReady + } + + public var adFormats: Set { + get { adUnitConfig.adFormats } + set { adUnitConfig.adFormats = newValue } + } + + public var ortbConfig: String? { + get { adUnitConfig.ortbConfig } + set { adUnitConfig.ortbConfig = newValue } + } + + public var bannerParameters: BannerParameters { + get { adUnitConfig.adConfiguration.bannerParameters } + } + + public var videoParameters: VideoParameters { + get { adUnitConfig.adConfiguration.videoParameters } + } + + // MARK: - Video controls configuration + + public var closeButtonArea: Double { + get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea } + set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea = newValue } + } + + public var closeButtonPosition: Position { + get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition } + set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition = newValue } + } - /// The area of the skip button in the video controls, specified as a percentage of the screen width. - @objc public var skipButtonArea: Double { + public var skipButtonArea: Double { get { adUnitConfig.adConfiguration.videoControlsConfig.skipButtonArea } set { adUnitConfig.adConfiguration.videoControlsConfig.skipButtonArea = newValue } } - /// The position of the skip button in the video controls. - @objc public var skipButtonPosition: Position { + public var skipButtonPosition: Position { get { adUnitConfig.adConfiguration.videoControlsConfig.skipButtonPosition } set { adUnitConfig.adConfiguration.videoControlsConfig.skipButtonPosition = newValue } } - /// The delay before the skip button appears, in seconds. - @objc public var skipDelay: Double { + public var skipDelay: Double { get { adUnitConfig.adConfiguration.videoControlsConfig.skipDelay } set { adUnitConfig.adConfiguration.videoControlsConfig.skipDelay = newValue } } - - /// Initializes a new interstitial rendering ad unit with the specified configuration ID. - /// - Parameter configID: The unique identifier for the ad unit configuration. - @objc public init(configID: String) { - super.init(configID: configID, - minSizePerc: nil, - eventHandler: InterstitialEventHandlerStandalone()) + + public var isMuted: Bool { + get { adUnitConfig.adConfiguration.videoControlsConfig.isMuted } + set { adUnitConfig.adConfiguration.videoControlsConfig.isMuted = newValue } } - - /// Initializes a new interstitial rendering ad unit with the specified configuration ID and minimum size percentage. - /// - Parameter configID: The unique identifier for the ad unit configuration. - /// - Parameter minSizePercentage: The minimum size percentage of the ad. - @objc public init(configID: String, minSizePercentage: CGSize) { - super.init( + + public var isSoundButtonVisible: Bool { + get { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible } + set { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible = newValue } + } + + // MARK: Private properties + + private let baseAdUnit: BaseInterstitialAdUnit + + // NOTE: exposed for tests + var adUnitConfig: AdUnitConfig { + baseAdUnit.adUnitConfig + } + + private var eventHandler: PBMPrimaryAdRequesterProtocol { + baseAdUnit.eventHandler + } + + public convenience init(configID: String) { + self.init( + configID: configID, + minSizePerc: nil, + primaryAdRequester: InterstitialEventHandlerStandalone() + ) + } + + public convenience init(configID: String, minSizePercentage: CGSize) { + self.init( configID: configID, minSizePerc: NSValue(cgSize: minSizePercentage), - eventHandler: InterstitialEventHandlerStandalone()) + primaryAdRequester: InterstitialEventHandlerStandalone() + ) } - - /// Initializes a new interstitial rendering ad unit with the specified configuration ID, minimum size percentage, and event handler. - /// - Parameter configID: The unique identifier for the ad unit configuration. - /// - Parameter minSizePercentage: The minimum size percentage of the ad. - /// - Parameter eventHandler: The event handler to manage ad events. - @objc public init(configID: String, minSizePercentage: CGSize, eventHandler: AnyObject) { - super.init( + + public convenience init(configID: String, eventHandler: AnyObject?) { + self.init( + configID: configID, + minSizePerc: nil, + primaryAdRequester: (eventHandler as? PBMPrimaryAdRequesterProtocol) ?? InterstitialEventHandlerStandalone() + ) + } + + public convenience init( + configID: String, + minSizePercentage: CGSize, + eventHandler: AnyObject + ) { + self.init( configID: configID, minSizePerc: NSValue(cgSize: minSizePercentage), - eventHandler: eventHandler) + primaryAdRequester: (eventHandler as? PBMPrimaryAdRequesterProtocol) ?? InterstitialEventHandlerStandalone() + ) } - /// Initializes a new interstitial rendering ad unit with the specified configuration ID, minimum size percentage, and event handler. - /// - Parameter configID: The unique identifier for the ad unit configuration. - /// - Parameter minSizePerc: The minimum size percentage of the ad. - /// - Parameter eventHandler: The event handler to manage ad events. - @objc required init(configID: String, minSizePerc: NSValue?, eventHandler: AnyObject?) { - super.init( + required init( + configID: String, + minSizePerc: NSValue?, + primaryAdRequester: PBMPrimaryAdRequesterProtocol + ) { + baseAdUnit = BaseInterstitialAdUnit( configID: configID, minSizePerc: minSizePerc, - eventHandler: eventHandler) + eventHandler: primaryAdRequester + ) + + super.init() + + baseAdUnit.delegate = self } - // MARK: - Protected overrides - - /// Called when an ad is successfully received. - @objc public override func callDelegate_didReceiveAd() { - if let delegate = self.delegate as? InterstitialAdUnitDelegate { - delegate.interstitialDidReceiveAd?(self) - } + // MARK: - Public methods + + public func loadAd() { + baseAdUnit.loadAd() } - /// Called when the ad fails to be received. - @objc public override func callDelegate_didFailToReceiveAd(with error: Error?) { - if let delegate = self.delegate as? InterstitialAdUnitDelegate { - delegate.interstitial?(self, didFailToReceiveAdWithError: error) - } + public func show(from controller: UIViewController) { + baseAdUnit.show(from: controller) } - - /// Called when the ad will be presented. - @objc public override func callDelegate_willPresentAd() { - if let delegate = self.delegate as? InterstitialAdUnitDelegate { - delegate.interstitialWillPresentAd?(self) - } + + // MARK: - Ext Data (imp[].ext.data) + + @available(*, deprecated, message: "This method is deprecated. Please, use addExtData method instead.") + public func addContextData(_ data: String, forKey key: String) { + addExtData(key: key, value: data) } - - /// Called when the ad is dismissed. - @objc public override func callDelegate_didDismissAd() { - if let delegate = self.delegate as? InterstitialAdUnitDelegate { - delegate.interstitialDidDismissAd?(self) - } + + @available(*, deprecated, message: "This method is deprecated. Please, use updateExtData method instead.") + public func updateContextData(_ data: Set, forKey key: String) { + updateExtData(key: key, value: data) } - - /// Called when the user will leave the application. - @objc public override func callDelegate_willLeaveApplication() { - if let delegate = self.delegate as? InterstitialAdUnitDelegate { - delegate.interstitialWillLeaveApplication?(self) - } + + @available(*, deprecated, message: "This method is deprecated. Please, use removeExtData method instead.") + public func removeContextDate(forKey key: String) { + removeExtData(forKey: key) } - - /// Called when the ad is clicked. - @objc public override func callDelegate_didClickAd() { - if let delegate = self.delegate as? InterstitialAdUnitDelegate { - delegate.interstitialDidClickAd?(self) - } + + @available(*, deprecated, message: "This method is deprecated. Please, use clearExtData method instead.") + public func clearContextData() { + clearExtData() } - /// Checks if the ad is ready to be displayed. - @objc public override func callEventHandler_isReady() -> Bool { - interstitialEventHandler?.isReady ?? false + public func addExtData(key: String, value: String) { + adUnitConfig.addExtData(key: key, value: value) } - /// Sets the loading delegate for the event handler. - @objc public override func callEventHandler_setLoadingDelegate(_ loadingDelegate: NSObject?) { - interstitialEventHandler?.loadingDelegate = loadingDelegate as? RewardedEventLoadingDelegate + public func updateExtData(key: String, value: Set) { + adUnitConfig.updateExtData(key: key, value: value) } - - /// Sets the interaction delegate for the event handler. - @objc public override func callEventHandler_setInteractionDelegate() { - interstitialEventHandler?.interactionDelegate = self + + public func removeExtData(forKey: String) { + adUnitConfig.removeExtData(for: forKey) } - - /// Requests an ad with the specified bid response - @objc public override func callEventHandler_requestAd(with bidResponse: BidResponse?) { - interstitialEventHandler?.requestAd(with: bidResponse) + + public func clearExtData() { + adUnitConfig.clearExtData() } - - /// Shows the ad from the specified view controller. - @objc public override func callEventHandler_show(from controller: UIViewController?) { - interstitialEventHandler?.show(from: controller) + + // MARK: - Ext keywords (imp[].ext.keywords) + + @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeyword method instead.") + public func addContextKeyword(_ newElement: String) { + addExtKeyword(newElement) } - - /// Tracks an impression for the ad. - @objc public override func callEventHandler_trackImpression() { - interstitialEventHandler?.trackImpression?() + + @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeywords method instead.") + public func addContextKeywords(_ newElements: Set) { + addExtKeywords(newElements) + } + + @available(*, deprecated, message: "This method is deprecated. Please, use removeExtKeyword method instead.") + public func removeContextKeyword(_ element: String) { + removeExtKeyword(element) + } + + @available(*, deprecated, message: "This method is deprecated. Please, use clearExtKeywords method instead.") + public func clearContextKeywords() { + clearExtKeywords() + } + + public func addExtKeyword(_ newElement: String) { + adUnitConfig.addExtKeyword(newElement) + } + + public func addExtKeywords(_ newElements: Set) { + adUnitConfig.addExtKeywords(newElements) + } + + public func removeExtKeyword(_ element: String) { + adUnitConfig.removeExtKeyword(element) + } + + public func clearExtKeywords() { + adUnitConfig.clearExtKeywords() + } + + // MARK: - App Content (app.content.data) + + public func setAppContent(_ appContent: PBMORTBAppContent) { + adUnitConfig.setAppContent(appContent) + } + + public func clearAppContent() { + adUnitConfig.clearAppContent() + } + + public func addAppContentData(_ dataObjects: [PBMORTBContentData]) { + adUnitConfig.addAppContentData(dataObjects) + } + + public func removeAppContentDataObject(_ dataObject: PBMORTBContentData) { + adUnitConfig.removeAppContentData(dataObject) + } + + public func clearAppContentDataObjects() { + adUnitConfig.clearAppContentData() + } + + // MARK: - User Data (user.data) + + public func addUserData(_ userDataObjects: [PBMORTBContentData]) { + adUnitConfig.addUserData(userDataObjects) + } + + public func removeUserData(_ userDataObject: PBMORTBContentData) { + adUnitConfig.removeUserData(userDataObject) + } + + public func clearUserData() { + adUnitConfig.clearUserData() + } + + // MARK: - Internal methods + + func interstitialControllerDidCloseAd(_ interstitialController: InterstitialController) { + baseAdUnit.interstitialControllerDidCloseAd(interstitialController) + } + + func callDelegate_didReceiveAd() { + delegate?.interstitialDidReceiveAd?(self) + } + + func callDelegate_didFailToReceiveAd(with error: Error?) { + delegate?.interstitial?(self, didFailToReceiveAdWithError: error) + } + + func callDelegate_willPresentAd() { + delegate?.interstitialWillPresentAd?(self) + } + + func callDelegate_didDismissAd() { + delegate?.interstitialDidDismissAd?(self) + } + + func callDelegate_willLeaveApplication() { + delegate?.interstitialWillLeaveApplication?(self) + } + + func callDelegate_didClickAd() { + delegate?.interstitialDidClickAd?(self) } - private var interstitialEventHandler: InterstitialEventHandlerProtocol? { - eventHandler as? InterstitialEventHandlerProtocol + func callEventHandler_isReady() -> Bool { + (eventHandler as? InterstitialEventHandlerProtocol)?.isReady ?? false + } + + func callEventHandler_setLoadingDelegate(_ loadingDelegate: NSObject?) { + if let eventHandler = eventHandler as? InterstitialEventHandlerProtocol { + eventHandler.loadingDelegate = loadingDelegate as? InterstitialEventLoadingDelegate + } + } + + func callEventHandler_setInteractionDelegate() { + if let eventHandler = eventHandler as? InterstitialEventHandlerProtocol { + eventHandler.interactionDelegate = baseAdUnit + } + } + + func callEventHandler_requestAd(with bidResponse: BidResponse?) { + if let eventHandler = eventHandler as? InterstitialEventHandlerProtocol { + eventHandler.requestAd(with: bidResponse) + } + } + + func callEventHandler_show(from controller: UIViewController?) { + if let eventHandler = eventHandler as? InterstitialEventHandlerProtocol { + eventHandler.show(from: controller) + } + } + + func callEventHandler_trackImpression() { + if let eventHandler = eventHandler as? InterstitialEventHandlerProtocol { + eventHandler.trackImpression?() + } } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift index 60f12e274..92403fa35 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift @@ -17,158 +17,305 @@ import UIKit /// Represents an rewarded ad unit. Built for rendering type of integration. @objc -public class RewardedAdUnit: BaseInterstitialAdUnit, - RewardedEventInteractionDelegate { - // MARK: - Lifecycle +public class RewardedAdUnit: NSObject, BaseInterstitialAdUnitProtocol { - @objc public convenience init( - configID: String, - eventHandler: AnyObject - ) { + public weak var delegate: RewardedAdUnitDelegate? + + public var isReady: Bool { + baseAdUnit.isReady + } + + public var adFormats: Set { + get { adUnitConfig.adFormats } + set { adUnitConfig.adFormats = newValue } + } + + public var ortbConfig: String? { + get { adUnitConfig.ortbConfig } + set { adUnitConfig.ortbConfig = newValue } + } + + public var bannerParameters: BannerParameters { + get { adUnitConfig.adConfiguration.bannerParameters } + } + + public var videoParameters: VideoParameters { + get { adUnitConfig.adConfiguration.videoParameters } + } + + // MARK: - Video controls configuration + + public var closeButtonArea: Double { + get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea } + set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea = newValue } + } + + public var closeButtonPosition: Position { + get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition } + set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition = newValue } + } + + public var isMuted: Bool { + get { adUnitConfig.adConfiguration.videoControlsConfig.isMuted } + set { adUnitConfig.adConfiguration.videoControlsConfig.isMuted = newValue } + } + + public var isSoundButtonVisible: Bool { + get { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible } + set { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible = newValue } + } + + // MARK: Private properties + + private let baseAdUnit: BaseRewardedAdUnit + + private var adUnitConfig: AdUnitConfig { + baseAdUnit.adUnitConfig + } + + private var eventHandler: PBMPrimaryAdRequesterProtocol { + baseAdUnit.eventHandler + } + + public convenience init(configID: String) { self.init( configID: configID, minSizePerc: nil, - eventHandler: eventHandler + primaryAdRequester: RewardedEventHandlerStandalone() ) } - - /// Initializes a `RewardedAdUnit` with the given configuration ID and a default event handler. - /// - /// - Parameter configID: The configuration ID for the ad unit. - @objc public convenience init(configID: String) { + + public convenience init(configID: String, minSizePercentage: CGSize) { + self.init( + configID: configID, + minSizePerc: NSValue(cgSize: minSizePercentage), + primaryAdRequester: RewardedEventHandlerStandalone() + ) + } + + public convenience init(configID: String, eventHandler: AnyObject?) { self.init( configID: configID, minSizePerc: nil, - eventHandler: RewardedEventHandlerStandalone() + primaryAdRequester: (eventHandler as? PBMPrimaryAdRequesterProtocol) ?? RewardedEventHandlerStandalone() + ) + } + + public convenience init( + configID: String, + minSizePercentage: CGSize, + eventHandler: AnyObject + ) { + self.init( + configID: configID, + minSizePerc: NSValue(cgSize: minSizePercentage), + primaryAdRequester: (eventHandler as? PBMPrimaryAdRequesterProtocol) ?? RewardedEventHandlerStandalone() ) } - @objc required init( + required init( configID: String, minSizePerc: NSValue?, - eventHandler: AnyObject? + primaryAdRequester: PBMPrimaryAdRequesterProtocol ) { - super.init( + baseAdUnit = BaseRewardedAdUnit( configID: configID, minSizePerc: minSizePerc, - eventHandler: eventHandler + eventHandler: primaryAdRequester ) - adUnitConfig.adConfiguration.isRewarded = true - adFormats = [.banner, .video] + super.init() + + baseAdUnit.delegate = self } - // MARK: - RewardedEventDelegate + // MARK: - Public methods - @objc public func userDidEarnReward(_ reward: PrebidReward) { - DispatchQueue.main.async { - self.callDelegate_rewardedAdUserDidEarnReward(reward: reward) - } + public func loadAd() { + baseAdUnit.loadAd() } - // MARK: - Protected overrides + public func show(from controller: UIViewController) { + baseAdUnit.show(from: controller) + } - /// Called when the ad unit receives an ad. - @objc public override func callDelegate_didReceiveAd() { - if let delegate = self.delegate as? RewardedAdUnitDelegate { - delegate.rewardedAdDidReceiveAd?(self) - } + // MARK: - Ext Data (imp[].ext.data) + + @available(*, deprecated, message: "This method is deprecated. Please, use addExtData method instead.") + public func addContextData(_ data: String, forKey key: String) { + addExtData(key: key, value: data) } - - /// Called when the ad unit fails to receive an ad. - /// - /// - Parameter error: The error describing the failure. - @objc public override func callDelegate_didFailToReceiveAd(with error: Error?) { - if let delegate = self.delegate as? RewardedAdUnitDelegate { - delegate.rewardedAd?(self, didFailToReceiveAdWithError: error) - } + + @available(*, deprecated, message: "This method is deprecated. Please, use updateExtData method instead.") + public func updateContextData(_ data: Set, forKey key: String) { + updateExtData(key: key, value: data) } - /// Called when the ad unit will present an ad. - @objc public override func callDelegate_willPresentAd() { - if let delegate = self.delegate as? RewardedAdUnitDelegate { - delegate.rewardedAdWillPresentAd?(self) - } + @available(*, deprecated, message: "This method is deprecated. Please, use removeExtData method instead.") + public func removeContextDate(forKey key: String) { + removeExtData(forKey: key) } - - /// Called when the ad unit dismisses an ad. - @objc public override func callDelegate_didDismissAd() { - if let delegate = self.delegate as? RewardedAdUnitDelegate { - delegate.rewardedAdDidDismissAd?(self) - } + + @available(*, deprecated, message: "This method is deprecated. Please, use clearExtData method instead.") + public func clearContextData() { + clearExtData() } - - /// Called when the ad unit will leave the application. - @objc public override func callDelegate_willLeaveApplication() { - if let delegate = self.delegate as? RewardedAdUnitDelegate { - delegate.rewardedAdWillLeaveApplication?(self) - } + + public func addExtData(key: String, value: String) { + adUnitConfig.addExtData(key: key, value: value) + } + + public func updateExtData(key: String, value: Set) { + adUnitConfig.updateExtData(key: key, value: value) + } + + public func removeExtData(forKey: String) { + adUnitConfig.removeExtData(for: forKey) + } + + public func clearExtData() { + adUnitConfig.clearExtData() + } + + // MARK: - Ext keywords (imp[].ext.keywords) + + @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeyword method instead.") + public func addContextKeyword(_ newElement: String) { + addExtKeyword(newElement) + } + + @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeywords method instead.") + public func addContextKeywords(_ newElements: Set) { + addExtKeywords(newElements) + } + + @available(*, deprecated, message: "This method is deprecated. Please, use removeExtKeyword method instead.") + public func removeContextKeyword(_ element: String) { + removeExtKeyword(element) } - /// Called when the ad unit is clicked. - @objc public override func callDelegate_didClickAd() { - if let delegate = self.delegate as? RewardedAdUnitDelegate { - delegate.rewardedAdDidClickAd?(self) - } + @available(*, deprecated, message: "This method is deprecated. Please, use clearExtKeywords method instead.") + public func clearContextKeywords() { + clearExtKeywords() } - /// Returns whether the event handler is ready. - /// - /// - Returns: A boolean indicating if the event handler is ready. - @objc public override func callEventHandler_isReady() -> Bool { - if let eventHandler = self.eventHandler as? RewardedEventHandlerProtocol { - return eventHandler.isReady - } else { - return false - } + public func addExtKeyword(_ newElement: String) { + adUnitConfig.addExtKeyword(newElement) + } + + public func addExtKeywords(_ newElements: Set) { + adUnitConfig.addExtKeywords(newElements) + } + + public func removeExtKeyword(_ element: String) { + adUnitConfig.removeExtKeyword(element) + } + + public func clearExtKeywords() { + adUnitConfig.clearExtKeywords() + } + + // MARK: - App Content (app.content.data) + + public func setAppContent(_ appContent: PBMORTBAppContent) { + adUnitConfig.setAppContent(appContent) + } + + public func clearAppContent() { + adUnitConfig.clearAppContent() + } + + public func addAppContentData(_ dataObjects: [PBMORTBContentData]) { + adUnitConfig.addAppContentData(dataObjects) } - /// Sets the loading delegate for the event handler. - /// - /// - Parameter loadingDelegate: The loading delegate to set. - @objc public override func callEventHandler_setLoadingDelegate(_ loadingDelegate: NSObject?) { - if let eventHandler = self.eventHandler as? RewardedEventHandlerProtocol { + public func removeAppContentDataObject(_ dataObject: PBMORTBContentData) { + adUnitConfig.removeAppContentData(dataObject) + } + + public func clearAppContentDataObjects() { + adUnitConfig.clearAppContentData() + } + + // MARK: - User Data (user.data) + + public func addUserData(_ userDataObjects: [PBMORTBContentData]) { + adUnitConfig.addUserData(userDataObjects) + } + + public func removeUserData(_ userDataObject: PBMORTBContentData) { + adUnitConfig.removeUserData(userDataObject) + } + + public func clearUserData() { + adUnitConfig.clearUserData() + } + + // MARK: - Internal methods + + func interstitialControllerDidCloseAd(_ interstitialController: InterstitialController) { + baseAdUnit.interstitialControllerDidCloseAd(interstitialController) + } + + func callDelegate_didReceiveAd() { + delegate?.rewardedAdDidReceiveAd?(self) + } + + func callDelegate_didFailToReceiveAd(with error: Error?) { + delegate?.rewardedAd?(self, didFailToReceiveAdWithError: error) + } + + func callDelegate_willPresentAd() { + delegate?.rewardedAdWillPresentAd?(self) + } + + func callDelegate_didDismissAd() { + delegate?.rewardedAdDidDismissAd?(self) + } + + func callDelegate_willLeaveApplication() { + delegate?.rewardedAdWillLeaveApplication?(self) + } + + func callDelegate_didClickAd() { + delegate?.rewardedAdDidClickAd?(self) + } + + func callEventHandler_isReady() -> Bool { + (eventHandler as? RewardedEventHandlerProtocol)?.isReady ?? false + } + + func callEventHandler_setLoadingDelegate(_ loadingDelegate: NSObject?) { + if let eventHandler = eventHandler as? RewardedEventHandlerProtocol { eventHandler.loadingDelegate = loadingDelegate as? RewardedEventLoadingDelegate } } - - /// Sets the interaction delegate for the event handler. - @objc public override func callEventHandler_setInteractionDelegate() { - if let eventHandler = self.eventHandler as? RewardedEventHandlerProtocol { - eventHandler.interactionDelegate = self + + func callEventHandler_setInteractionDelegate() { + if let eventHandler = eventHandler as? RewardedEventHandlerProtocol { + eventHandler.interactionDelegate = baseAdUnit } } - - /// Requests an ad with the given bid response. - /// - /// - Parameter bidResponse: The bid response to use for the ad request. - @objc public override func callEventHandler_requestAd(with bidResponse: BidResponse?) { - if let eventHandler = self.eventHandler as? RewardedEventHandlerProtocol { + + func callEventHandler_requestAd(with bidResponse: BidResponse?) { + if let eventHandler = eventHandler as? RewardedEventHandlerProtocol { eventHandler.requestAd(with: bidResponse) } } - - /// Shows the ad from the specified view controller. - /// - /// - Parameter controller: The view controller from which to present the ad. - @objc public override func callEventHandler_show(from controller: UIViewController?) { - if let eventHandler = self.eventHandler as? RewardedEventHandlerProtocol { + + func callEventHandler_show(from controller: UIViewController?) { + if let eventHandler = eventHandler as? RewardedEventHandlerProtocol { eventHandler.show(from: controller) } } - - /// Tracks the impression for the ad. - @objc public override func callEventHandler_trackImpression() { - if let eventHandler = self.eventHandler as? RewardedEventHandlerProtocol { + + func callEventHandler_trackImpression() { + if let eventHandler = eventHandler as? RewardedEventHandlerProtocol { eventHandler.trackImpression?() } } - // MARK: - Private helpers - func callDelegate_rewardedAdUserDidEarnReward(reward: PrebidReward) { - if let delegate = self.delegate as? RewardedAdUnitDelegate { - delegate.rewardedAdUserDidEarnReward?(self, reward: reward) - } + delegate?.rewardedAdUserDidEarnReward?(self, reward: reward) } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift index 9476706dd..556d8f6e2 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift @@ -18,5 +18,5 @@ import Foundation @objc public protocol RewardedEventInteractionDelegate: InterstitialEventInteractionDelegate { /// Call this when the ad server SDK decides the use has earned reward - func userDidEarnReward(_ reward: PrebidReward) + func userDidEarnReward(_ interstitialController: InterstitialController, _ reward: PrebidReward) } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventLoadingDelegate.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventLoadingDelegate.swift index 85441cb4c..25f49de06 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventLoadingDelegate.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventLoadingDelegate.swift @@ -12,12 +12,11 @@  See the License for the specific language governing permissions and  limitations under the License.  */ + import Foundation @objc public protocol RewardedEventLoadingDelegate : InterstitialEventLoadingDelegate { - /*! - @abstract The reward to be given to the user. May be assigned on successful loading. - */ + // The reward to be given to the user. May be assigned on successful loading. weak var reward: NSObject? { get set } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift index 8012fe616..2e0aa773a 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift @@ -302,16 +302,15 @@ public class AdUnitConfig: NSObject, NSCopying { let clone = AdUnitConfig(configId: self.configId, size: self.adSize) clone.adFormats = self.adFormats - clone.adConfiguration.adFormats = self.adConfiguration.adFormats - clone.adConfiguration.isInterstitialAd = self.adConfiguration.isInterstitialAd - clone.adConfiguration.isRewarded = self.adConfiguration.isRewarded clone.nativeAdConfiguration = self.nativeAdConfiguration - clone.adConfiguration.bannerParameters = self.adConfiguration.bannerParameters - clone.adConfiguration.videoParameters = self.adConfiguration.videoParameters - clone.adConfiguration.videoControlsConfig = self.adConfiguration.videoControlsConfig clone.sizes = sizes - clone.refreshInterval = self.refreshInterval + clone.adSize = adSize clone.minSizePerc = self.minSizePerc + clone.adPosition = self.adPosition + clone.additionalSizes = self.additionalSizes + clone.refreshInterval = self.refreshInterval + clone.gpid = self.gpid + clone.ortbConfig = self.ortbConfig clone.extensionData = self.extensionData.merging(clone.extensionData) { $1 } clone.appContent = self.appContent clone.extKeywords = self.extKeywords @@ -319,6 +318,26 @@ public class AdUnitConfig: NSObject, NSCopying { clone.adPosition = self.adPosition clone.pbAdSlot = self.pbAdSlot + clone.adConfiguration.winningBidAdFormat = self.adConfiguration.winningBidAdFormat + clone.adConfiguration.adFormats = self.adConfiguration.adFormats + clone.adConfiguration.isOriginalAPI = self.adConfiguration.isOriginalAPI + clone.adConfiguration.size = self.adConfiguration.size + clone.adConfiguration.isBuiltInVideo = self.adConfiguration.isBuiltInVideo + clone.adConfiguration.isInterstitialAd = self.adConfiguration.isInterstitialAd + clone.adConfiguration.isRewarded = self.adConfiguration.isRewarded + clone.adConfiguration.forceInterstitialPresentation = self.adConfiguration.forceInterstitialPresentation + clone.adConfiguration.interstitialLayout = self.adConfiguration.interstitialLayout + clone.nativeAdConfiguration = self.nativeAdConfiguration + clone.adConfiguration.bannerParameters = self.adConfiguration.bannerParameters + clone.adConfiguration.videoParameters = self.adConfiguration.videoParameters + clone.adConfiguration.videoControlsConfig = self.adConfiguration.videoControlsConfig + clone.adConfiguration.clickHandlerOverride = self.adConfiguration.clickHandlerOverride + clone.adConfiguration.autoRefreshDelay = self.adConfiguration.autoRefreshDelay + clone.adConfiguration.pollFrequency = self.adConfiguration.pollFrequency + clone.adConfiguration.viewableArea = self.adConfiguration.viewableArea + clone.adConfiguration.viewableDuration = self.adConfiguration.viewableDuration + clone.adConfiguration.ortbConfig = self.adConfiguration.ortbConfig + return clone } diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMCreativeFactoryTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMCreativeFactoryTest.swift index 86b7b367e..bc67a6fec 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMCreativeFactoryTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMCreativeFactoryTest.swift @@ -66,6 +66,6 @@ class PBMCreativeFactoryTest: XCTestCase { creativeFactory.start() - waitForExpectations(timeout: 5) + waitForExpectations(timeout: 10) } } diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMWebViewObjCTest.m b/PrebidMobileTests/RenderingTests/Tests/PBMWebViewObjCTest.m index 304d321da..378e98c9b 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMWebViewObjCTest.m +++ b/PrebidMobileTests/RenderingTests/Tests/PBMWebViewObjCTest.m @@ -92,7 +92,7 @@ - (void)testEvaluateJSNil { NSString *str = nil; [webView evaluateJavaScript:str]; - [self waitForExpectationsWithTimeout:3.0 handler:nil]; + [self waitForExpectationsWithTimeout:5.0 handler:nil]; } #pragma mark - WKNavigationDelegate diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMWebViewTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMWebViewTest.swift index 9ca695a91..7ee160fd1 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMWebViewTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMWebViewTest.swift @@ -685,7 +685,7 @@ class PBMWebViewTest : XCTestCase, PBMWebViewDelegate { XCTAssertEqual(webView.mraidState, .notEnabled) XCTAssertEqual(webView.state, .loading) - waitForExpectations(timeout: 3, handler: { _ in + waitForExpectations(timeout: 5, handler: { _ in XCTAssertEqual(webView.state, .loaded) XCTAssertEqual(webView.mraidState, PBMMRAIDState.default) }) @@ -898,7 +898,7 @@ class PBMWebViewTest : XCTestCase, PBMWebViewDelegate { } checkJSEvaluating(webView: webView, commandBlock: commandBlock, evaluatingBlock: jsEvaluationBlock) - waitForExpectations(timeout: 3) + waitForExpectations(timeout: 5) } func testMRAID_onExposureChangeTrue() { @@ -914,7 +914,7 @@ class PBMWebViewTest : XCTestCase, PBMWebViewDelegate { } checkJSEvaluating(webView: webView, commandBlock: commandBlock, evaluatingBlock: jsEvaluationBlock) - waitForExpectations(timeout: 3) + waitForExpectations(timeout: 5) } func testMRAID_updatePlacementType() { @@ -930,7 +930,7 @@ class PBMWebViewTest : XCTestCase, PBMWebViewDelegate { } checkJSEvaluating(webView: webView, commandBlock: commandBlock, evaluatingBlock: jsEvaluationBlock) - waitForExpectations(timeout: 3) + waitForExpectations(timeout: 5) } func testAudioVolumeChange() { diff --git a/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/BasicParameterBuilderTest.swift b/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/BasicParameterBuilderTest.swift index 461632d3f..94ab42ca7 100644 --- a/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/BasicParameterBuilderTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/BasicParameterBuilderTest.swift @@ -148,23 +148,22 @@ class PBMBasicParameterBuilderTest: XCTestCase { } func testParameterBuilderDefaultInterstitialConfig() { - var adUnit = BaseInterstitialAdUnit.init(configID: "configId") + var adUnit = InterstitialRenderingAdUnit(configID: "configId") checkDefaultParametersForAdUnit(adConfiguration: adUnit.adUnitConfig.adConfiguration) - adUnit = BaseInterstitialAdUnit.init(configID: "configId", minSizePerc: 0.2 as NSValue, eventHandler: InterstitialEventHandlerStandalone()) + adUnit = InterstitialRenderingAdUnit(configID: "configId", minSizePerc: 0.2 as NSValue, primaryAdRequester: InterstitialEventHandlerStandalone()) checkDefaultParametersForAdUnit(adConfiguration: adUnit.adUnitConfig.adConfiguration) - adUnit = BaseInterstitialAdUnit.init(configID: "configId", minSizePercentage: CGSize.zero) + adUnit = InterstitialRenderingAdUnit(configID: "configId", minSizePercentage: CGSize.zero) checkDefaultParametersForAdUnit(adConfiguration: adUnit.adUnitConfig.adConfiguration) - adUnit = BaseInterstitialAdUnit.init(configID: "configId", minSizePercentage: CGSize.zero, eventHandler: InterstitialEventHandlerStandalone()) + adUnit = InterstitialRenderingAdUnit(configID: "configId", minSizePercentage: CGSize.zero, eventHandler: InterstitialEventHandlerStandalone()) checkDefaultParametersForAdUnit(adConfiguration: adUnit.adUnitConfig.adConfiguration) - adUnit = BaseInterstitialAdUnit.init(configID: "configId", eventHandler: InterstitialEventHandlerStandalone()) + adUnit = InterstitialRenderingAdUnit(configID: "configId", eventHandler: InterstitialEventHandlerStandalone()) checkDefaultParametersForAdUnit(adConfiguration: adUnit.adUnitConfig.adConfiguration) - let mediationAdUnit = MediationBaseInterstitialAdUnit.init(configId: "configId", mediationDelegate: MockMediationUtils(adObject: MockAdObject())) - + let mediationAdUnit = MediationBaseInterstitialAdUnit(configId: "configId", mediationDelegate: MockMediationUtils(adObject: MockAdObject())) checkDefaultParametersForAdUnit(adConfiguration: mediationAdUnit.adUnitConfig.adConfiguration) } diff --git a/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/PrebidParameterBuilderTest.swift b/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/PrebidParameterBuilderTest.swift index d1e1700a9..9de2d84be 100644 --- a/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/PrebidParameterBuilderTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/ParameterBuilderTests/PrebidParameterBuilderTest.swift @@ -63,7 +63,11 @@ class PrebidParameterBuilderTest: XCTestCase { func testAdPositionFullScreen() { let configId = "b6260e2b-bc4c-4d10-bdb5-f7bdd62f5ed4" - let interstitialAdUnit = InterstitialRenderingAdUnit(configID: configId) + let interstitialAdUnit = BaseInterstitialAdUnit( + configID: configId, + minSizePerc: nil, + eventHandler: InterstitialEventHandlerStandalone() + ) let bidRequest = buildBidRequest(with: interstitialAdUnit.adUnitConfig) @@ -396,7 +400,12 @@ class PrebidParameterBuilderTest: XCTestCase { XCTAssertEqual(imp.banner?.api, apiSignalsAsNumbers) } - let redenderingInterstitialAdUnit = BaseInterstitialAdUnit(configID: "configID") + let redenderingInterstitialAdUnit = BaseInterstitialAdUnit( + configID: "configID", + minSizePerc: nil, + eventHandler: InterstitialEventHandlerStandalone() + ) + bidRequest = buildBidRequest(with: redenderingInterstitialAdUnit.adUnitConfig) bidRequest.imp.forEach { @@ -583,8 +592,14 @@ class PrebidParameterBuilderTest: XCTestCase { } func testParameterBuilderInterstitialVAST() { - let adUnit = InterstitialRenderingAdUnit.init(configID: "configId") - adUnit.adFormats = [.video] + let adUnit = BaseInterstitialAdUnit( + configID: "configID", + minSizePerc: nil, + eventHandler: InterstitialEventHandlerStandalone() + ) + + adUnit.adUnitConfig.adFormats = [.video] + let adConfiguration = adUnit.adUnitConfig.adConfiguration let parameters = VideoParameters(mimes: []) parameters.placement = .Interstitial diff --git a/PrebidMobileTests/RenderingTests/Tests/Prebid/AdLoadFlow/PBMAdLoadFlowControllerTest.swift b/PrebidMobileTests/RenderingTests/Tests/Prebid/AdLoadFlow/PBMAdLoadFlowControllerTest.swift index f4b4d36c3..74bf3ac00 100644 --- a/PrebidMobileTests/RenderingTests/Tests/Prebid/AdLoadFlow/PBMAdLoadFlowControllerTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/Prebid/AdLoadFlow/PBMAdLoadFlowControllerTest.swift @@ -28,9 +28,11 @@ class PBMAdLoadFlowControllerTest: XCTestCase { } func testNoImmediateCalls() { + let adUnitConfig = AdUnitConfig(configId: "configId") let compositeMock = CompositeMock(expectedCalls: []) let flowController = PBMAdLoadFlowController(bidRequesterFactory: compositeMock.mockRequesterFactory, adLoader: compositeMock.mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock.mockFlowControllerDelegate, configValidationBlock: compositeMock.mockConfigValidator) let timeExp = expectation(description: "no event") @@ -66,7 +68,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let successReported = expectation(description: "success reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return true @@ -110,6 +111,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -150,7 +152,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let successReported = expectation(description: "success reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return true @@ -202,6 +203,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -234,7 +236,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let successReported = expectation(description: "success reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return true @@ -285,6 +286,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -311,7 +313,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let failureReported = expectation(description: "failure reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return true @@ -355,6 +356,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -381,7 +383,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let failureReported = expectation(description: "failure reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return true @@ -429,6 +430,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -457,7 +459,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let successReported = expectation(description: "success reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return true @@ -511,6 +512,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -539,7 +541,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let failureReported = expectation(description: "failure reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return true @@ -586,6 +587,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -609,7 +611,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let failureReported = expectation(description: "failure reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return false @@ -623,6 +624,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -646,7 +648,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let failureReported = expectation(description: "failure reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return true @@ -686,6 +687,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -709,7 +711,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let failureReported = expectation(description: "failure reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in XCTAssertFalse(renderWithPrebid) return true @@ -750,6 +751,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -778,10 +780,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { let successReported = expectation(description: "success reported") compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { - flowController().refresh() - return adUnitConfig - })), .configValidation(call: { (adConfig, renderWithPrebid) in flowController().refresh() return true @@ -837,6 +835,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -873,7 +872,6 @@ class PBMAdLoadFlowControllerTest: XCTestCase { } compositeMockBox[0] = CompositeMock(expectedCalls: [ - .flowControllerDelegate(call: .adUnitConfig(provider: { adUnitConfig })), .configValidation(call: { (adConfig, renderWithPrebid) in true }), .flowControllerDelegate(call: .willSendBidRequest(handler: { loader in })), .makeBidRequester(handler: { config, mockRequester in mockRequester }), @@ -915,6 +913,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { flowControllerBox[0] = PBMAdLoadFlowController(bidRequesterFactory: compositeMock().mockRequesterFactory, adLoader: compositeMock().mockAdLoader, + adUnitConfig: adUnitConfig, delegate: compositeMock().mockFlowControllerDelegate, configValidationBlock: compositeMock().mockConfigValidator) @@ -926,7 +925,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { waitForExpectations(timeout: 1) XCTAssertEqual(flowController().flowState, .demandReceived) - XCTAssertEqual(compositeMock().getProgress().done, 6) + XCTAssertEqual(compositeMock().getProgress().done, 5) nextShouldContinueExpectationBox[0] = expectation(description: "Second 'shouldContinue' reached") let secondTimeout = expectation(description: "first timeout") @@ -936,7 +935,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { waitForExpectations(timeout: 1) XCTAssertEqual(flowController().flowState, .readyToDeploy) - XCTAssertEqual(compositeMock().getProgress().done, 13) + XCTAssertEqual(compositeMock().getProgress().done, 12) successReportedExpectationBox[0] = expectation(description: "success reported") @@ -945,7 +944,7 @@ class PBMAdLoadFlowControllerTest: XCTestCase { XCTAssertFalse(flowController().hasFailedLoading) XCTAssertEqual(flowController().flowState, .idle) - XCTAssertEqual(compositeMock().getProgress().done, 14) + XCTAssertEqual(compositeMock().getProgress().done, 13) compositeMock().checkIsFinished() } } diff --git a/PrebidMobileTests/RenderingTests/Tests/Prebid/BaseInterstitialAdUnitTest.swift b/PrebidMobileTests/RenderingTests/Tests/Prebid/BaseInterstitialAdUnitTest.swift index febebecc2..88fa3cea7 100644 --- a/PrebidMobileTests/RenderingTests/Tests/Prebid/BaseInterstitialAdUnitTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/Prebid/BaseInterstitialAdUnitTest.swift @@ -13,31 +13,44 @@  limitations under the License.  */ - import XCTest -import PrebidMobile +@testable import PrebidMobile class BaseInterstitialAdUnitTest: XCTestCase { func testCloseButtonArea() { - let adUnit = BaseInterstitialAdUnit(configID: "test") - XCTAssertTrue(adUnit.closeButtonArea == 0.1) + let adUnit = BaseInterstitialAdUnit( + configID: "test", + minSizePerc: nil, + eventHandler: InterstitialEventHandlerStandalone() + ) + + let videoConfig = adUnit.adUnitConfig.adConfiguration.videoControlsConfig + + XCTAssertTrue(videoConfig.closeButtonArea == 0.1) - adUnit.closeButtonArea = 1.1 - XCTAssertTrue(adUnit.closeButtonArea == 0.1) + videoConfig.closeButtonArea = 1.1 + XCTAssertTrue(videoConfig.closeButtonArea == 0.1) - adUnit.closeButtonArea = -0.1 - XCTAssertTrue(adUnit.closeButtonArea == 0.1) + videoConfig.closeButtonArea = -0.1 + XCTAssertTrue(videoConfig.closeButtonArea == 0.1) - adUnit.closeButtonArea = 0.25 - XCTAssertTrue(adUnit.closeButtonArea == 0.25) + videoConfig.closeButtonArea = 0.25 + XCTAssertTrue(videoConfig.closeButtonArea == 0.25) } func testCloseButtonPosition() { - let adUnit = BaseInterstitialAdUnit(configID: "test") - XCTAssertEqual(adUnit.closeButtonPosition, .topRight) + let adUnit = BaseInterstitialAdUnit( + configID: "test", + minSizePerc: nil, + eventHandler: InterstitialEventHandlerStandalone() + ) + + let videoConfig = adUnit.adUnitConfig.adConfiguration.videoControlsConfig + + XCTAssertEqual(videoConfig.closeButtonPosition, .topRight) - adUnit.closeButtonPosition = .topLeft - XCTAssertEqual(adUnit.adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition, .topLeft) + videoConfig.closeButtonPosition = .topLeft + XCTAssertEqual(videoConfig.closeButtonPosition, .topLeft) } } diff --git a/PrebidMobileTests/RenderingTests/Tests/Prebid/PBMBaseInterstitialAdUnit_DelegationTest.swift b/PrebidMobileTests/RenderingTests/Tests/Prebid/PBMBaseInterstitialAdUnit_DelegationTest.swift index b21f2fceb..9cdd91286 100644 --- a/PrebidMobileTests/RenderingTests/Tests/Prebid/PBMBaseInterstitialAdUnit_DelegationTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/Prebid/PBMBaseInterstitialAdUnit_DelegationTest.swift @@ -13,23 +13,10 @@  limitations under the License.  */ -import Foundation import XCTest @testable import PrebidMobile -class MockInterstitialAdUnit: InterstitialRenderingAdUnit { - override var lastBidResponse: BidResponse? { - return WinningBidResponseFabricator.makeWinningBidResponse(bidPrice: 0.85) - } -} - -class MockRewardedAdUnit: RewardedAdUnit { - override var lastBidResponse: BidResponse? { - return WinningBidResponseFabricator.makeWinningBidResponse(bidPrice: 0.85) - } -} - class PBMBaseInterstitialAdUnit_DelegationTest: XCTestCase { override func tearDown() { Prebid.reset() @@ -40,28 +27,28 @@ class PBMBaseInterstitialAdUnit_DelegationTest: XCTestCase { private let configId = "someConfigId" func testInterstitialDelegateCalls_noOptionalMethods() { - let adUnit = MockInterstitialAdUnit(configID: configId) + let adUnit = InterstitialRenderingAdUnit(configID: configId) let delegate = DummyInterstitialDelegate() adUnit.delegate = delegate callInterstitialDelegateMethods(adUnit: adUnit) } func testInterstitialDelegateCalls_receiveAllMethods() { - let adUnit = MockInterstitialAdUnit(configID: configId) + let adUnit = InterstitialRenderingAdUnit(configID: configId) let delegate = InterstitialProxyDelegate() adUnit.delegate = delegate callInterstitialDelegateMethods(adUnit: adUnit, proxyDelegate: delegate) } func testRewardedAdDelegateCalls_noOptionalMethods() { - let adUnit = MockRewardedAdUnit(configID: configId, minSizePerc: nil, eventHandler: RewardedEventHandlerStandalone()) + let adUnit = RewardedAdUnit(configID: configId, minSizePerc: nil, primaryAdRequester: RewardedEventHandlerStandalone()) let delegate = DummyRewardedAdDelegate() adUnit.delegate = delegate callRewardedAdDelegateMethods(adUnit: adUnit) } func testRewardedAdDelegateCalls_receiveAllMethods() { - let adUnit = MockRewardedAdUnit(configID: configId, minSizePerc: nil, eventHandler: RewardedEventHandlerStandalone()) + let adUnit = RewardedAdUnit(configID: configId, minSizePerc: nil, primaryAdRequester: RewardedEventHandlerStandalone()) let delegate = RewardedAdProxyDelegate() adUnit.delegate = delegate callRewardedAdDelegateMethods(adUnit: adUnit, proxyDelegate: delegate) @@ -72,14 +59,14 @@ class PBMBaseInterstitialAdUnit_DelegationTest: XCTestCase { Prebid.shared.prebidServerAccountId = "" - let interstitial = MockInterstitialAdUnit(configID: testID) + let interstitial = InterstitialRenderingAdUnit(configID: testID) let exp = expectation(description: "loading callback called") let delegate = InterstitialProxyDelegate() interstitial.delegate = delegate delegate.onCall = { selector, args in XCTAssertEqual(selector, "interstitial:didFailToReceiveAdWithError:") XCTAssertEqual(args.count, 2) - XCTAssertEqual(args[0] as? MockInterstitialAdUnit, interstitial) + XCTAssertEqual(args[0] as? InterstitialRenderingAdUnit, interstitial) XCTAssertEqual(args[1] as? NSError, PBMError.prebidInvalidAccountId as NSError?) exp.fulfill() } @@ -94,14 +81,14 @@ class PBMBaseInterstitialAdUnit_DelegationTest: XCTestCase { Prebid.shared.prebidServerAccountId = "" - let rewarded = MockRewardedAdUnit(configID: testID, minSizePerc: nil, eventHandler: RewardedEventHandlerStandalone()) + let rewarded = RewardedAdUnit(configID: testID, minSizePerc: nil, primaryAdRequester: RewardedEventHandlerStandalone()) let exp = expectation(description: "loading callback called") let delegate = RewardedAdProxyDelegate() rewarded.delegate = delegate delegate.onCall = { selector, args in XCTAssertEqual(selector, "rewardedAd:didFailToReceiveAdWithError:") XCTAssertEqual(args.count, 2) - XCTAssertEqual(args[0] as? MockRewardedAdUnit, rewarded) + XCTAssertEqual(args[0] as? RewardedAdUnit, rewarded) XCTAssertEqual(args[1] as? NSError, PBMError.prebidInvalidAccountId as NSError?) exp.fulfill() } @@ -139,58 +126,45 @@ class PBMBaseInterstitialAdUnit_DelegationTest: XCTestCase { private class InterstitialProxyDelegate: BaseProxyDelegate, InterstitialAdUnitDelegate { func interstitialDidReceiveAd(_ interstitial: InterstitialRenderingAdUnit) { report(selectorName: "interstitialDidReceiveAd:", args: [interstitial]) - XCTAssertNotNil(interstitial.lastBidResponse) } func interstitial(_ interstitial: InterstitialRenderingAdUnit, didFailToReceiveAdWithError error: Error?) { report(selectorName: "interstitial:didFailToReceiveAdWithError:", args: [interstitial, error as Any]) - XCTAssertNotNil(interstitial.lastBidResponse) } func interstitialWillPresentAd(_ interstitial: InterstitialRenderingAdUnit) { report(selectorName: "interstitialWillPresentAd:", args: [interstitial]) - XCTAssertNotNil(interstitial.lastBidResponse) } func interstitialDidDismissAd(_ interstitial: InterstitialRenderingAdUnit) { report(selectorName: "interstitialDidDismissAd:", args: [interstitial]) - XCTAssertNotNil(interstitial.lastBidResponse) } func interstitialWillLeaveApplication(_ interstitial: InterstitialRenderingAdUnit) { report(selectorName: "interstitialWillLeaveApplication:", args: [interstitial]) - XCTAssertNotNil(interstitial.lastBidResponse) } func interstitialDidClickAd(_ interstitial: InterstitialRenderingAdUnit) { report(selectorName: "interstitialDidClickAd:", args: [interstitial]) - XCTAssertNotNil(interstitial.lastBidResponse) } } private class RewardedAdProxyDelegate: BaseProxyDelegate, RewardedAdUnitDelegate { func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { report(selectorName: "rewardedAdDidReceiveAd:", args: [rewardedAd]) - XCTAssertNotNil(rewardedAd.lastBidResponse) } func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { report(selectorName: "rewardedAd:didFailToReceiveAdWithError:", args: [rewardedAd, error as Any]) - XCTAssertNotNil(rewardedAd.lastBidResponse) } func rewardedAdWillPresentAd(_ rewardedAd: RewardedAdUnit) { report(selectorName: "rewardedAdWillPresentAd:", args: [rewardedAd]) - XCTAssertNotNil(rewardedAd.lastBidResponse) } func rewardedAdDidDismissAd(_ rewardedAd: RewardedAdUnit) { report(selectorName: "rewardedAdDidDismissAd:", args: [rewardedAd]) - XCTAssertNotNil(rewardedAd.lastBidResponse) } func rewardedAdWillLeaveApplication(_ rewardedAd: RewardedAdUnit) { report(selectorName: "rewardedAdWillLeaveApplication:", args: [rewardedAd]) - XCTAssertNotNil(rewardedAd.lastBidResponse) } func rewardedAdDidClickAd(_ rewardedAd: RewardedAdUnit) { report(selectorName: "rewardedAdDidClickAd:", args: [rewardedAd]) - XCTAssertNotNil(rewardedAd.lastBidResponse) } - func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit) { - report(selectorName: "rewardedAdUserDidEarnReward:", args: [rewardedAd]) - XCTAssertNotNil(rewardedAd.lastBidResponse) + func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) { + report(selectorName: "rewardedAdUserDidEarnReward:", args: [rewardedAd, reward]) } } @@ -290,24 +264,32 @@ class PBMBaseInterstitialAdUnit_DelegationTest: XCTestCase { private func callRewardedAdDelegateMethods(adUnit: RewardedAdUnit, proxyDelegate: RewardedAdProxyDelegate? = nil, - file: StaticString = #file, line: UInt = #line) - { + file: StaticString = #file, line: UInt = #line) { + func testCall(_ expectedSelector: String, args expectedArgs: [Any], block: () throws -> ()) { - PBMBaseInterstitialAdUnit_DelegationTest.callDelegateMethod(proxyDelegate: proxyDelegate, - expectedSelector: expectedSelector, - expectedArgs: expectedArgs, - file: file, line: line, - block: block) + PBMBaseInterstitialAdUnit_DelegationTest + .callDelegateMethod( + proxyDelegate: proxyDelegate, + expectedSelector: expectedSelector, + expectedArgs: expectedArgs, + file: file, + line: line, + block: block + ) } - callProtectedSelectors(baseAdUnit: adUnit, - proxyDelegate: proxyDelegate, - selectorPrefix: "rewardedAd", - file: file, line: line) + callProtectedSelectors( + baseAdUnit: adUnit, + proxyDelegate: proxyDelegate, + selectorPrefix: "rewardedAd", + file: file, + line: line + ) - testCall("rewardedAdUserDidEarnReward:", args: [adUnit]) { - adUnit.callDelegate_rewardedAdUserDidEarnReward() + let reward = PrebidReward() + + testCall("rewardedAdUserDidEarnReward:", args: [adUnit, reward]) { + adUnit.callDelegate_rewardedAdUserDidEarnReward(reward: reward) } } - } From 42c8afdfd9d9d21bfe0b3d4c6ee0f93782e89e88 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Fri, 4 Oct 2024 14:52:26 +0300 Subject: [PATCH 05/18] feat: add comments to the new functionality --- .build/workspace-state.json | 11 +++ .../GAM/InterstitialRenderingAdUnit.swift | 82 ++++++++++++++++++ .../Integrations/GAM/RewardedAdUnit.swift | 83 ++++++++++++++++++- 3 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 .build/workspace-state.json diff --git a/.build/workspace-state.json b/.build/workspace-state.json new file mode 100644 index 000000000..71deae90f --- /dev/null +++ b/.build/workspace-state.json @@ -0,0 +1,11 @@ +{ + "object" : { + "artifacts" : [ + + ], + "dependencies" : [ + + ] + }, + "version" : 6 +} \ No newline at end of file diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialRenderingAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialRenderingAdUnit.swift index 73d01f733..f4e69cbb7 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialRenderingAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/InterstitialRenderingAdUnit.swift @@ -19,62 +19,75 @@ import UIKit @objcMembers public class InterstitialRenderingAdUnit: NSObject, BaseInterstitialAdUnitProtocol { + /// A delegate for handling interactions with the ad unit. public weak var delegate: InterstitialAdUnitDelegate? + /// A Boolean value indicating whether the ad unit is ready to be displayed. public var isReady: Bool { baseAdUnit.isReady } + /// The set of ad formats supported by this ad unit. public var adFormats: Set { get { adUnitConfig.adFormats } set { adUnitConfig.adFormats = newValue } } + /// The ORTB (OpenRTB) configuration string for the ad unit. public var ortbConfig: String? { get { adUnitConfig.ortbConfig } set { adUnitConfig.ortbConfig = newValue } } + /// The banner parameters used for configuring ad unit. public var bannerParameters: BannerParameters { get { adUnitConfig.adConfiguration.bannerParameters } } + /// The video parameters used for configuring ad unit. public var videoParameters: VideoParameters { get { adUnitConfig.adConfiguration.videoParameters } } // MARK: - Video controls configuration + /// The area of the close button in the video controls as a percentage. public var closeButtonArea: Double { get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea } set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea = newValue } } + /// The position of the close button in the video controls. public var closeButtonPosition: Position { get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition } set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition = newValue } } + /// The area of the skip button in the video controls, specified as a percentage of the screen width. public var skipButtonArea: Double { get { adUnitConfig.adConfiguration.videoControlsConfig.skipButtonArea } set { adUnitConfig.adConfiguration.videoControlsConfig.skipButtonArea = newValue } } + /// The position of the skip button in the video controls. public var skipButtonPosition: Position { get { adUnitConfig.adConfiguration.videoControlsConfig.skipButtonPosition } set { adUnitConfig.adConfiguration.videoControlsConfig.skipButtonPosition = newValue } } + /// The delay before the skip button appears, in seconds. public var skipDelay: Double { get { adUnitConfig.adConfiguration.videoControlsConfig.skipDelay } set { adUnitConfig.adConfiguration.videoControlsConfig.skipDelay = newValue } } + /// A Boolean value indicating whether the video controls are muted. public var isMuted: Bool { get { adUnitConfig.adConfiguration.videoControlsConfig.isMuted } set { adUnitConfig.adConfiguration.videoControlsConfig.isMuted = newValue } } + /// A Boolean value indicating whether the sound button is visible in the video controls. public var isSoundButtonVisible: Bool { get { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible } set { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible = newValue } @@ -93,6 +106,8 @@ public class InterstitialRenderingAdUnit: NSObject, BaseInterstitialAdUnitProtoc baseAdUnit.eventHandler } + /// Initializes a new `BaseInterstitialAdUnit` with the specified configuration ID. + /// - Parameter configID: The unique identifier for the ad unit configuration. public convenience init(configID: String) { self.init( configID: configID, @@ -101,6 +116,10 @@ public class InterstitialRenderingAdUnit: NSObject, BaseInterstitialAdUnitProtoc ) } + /// Initializes a new `InterstitialRenderingAdUnit` with the specified configuration ID and minimum size percentage. + /// - Parameters: + /// - configID: The unique identifier for the ad unit configuration. + /// - minSizePercentage: The minimum size percentage for the ad unit. public convenience init(configID: String, minSizePercentage: CGSize) { self.init( configID: configID, @@ -109,6 +128,10 @@ public class InterstitialRenderingAdUnit: NSObject, BaseInterstitialAdUnitProtoc ) } + /// Initializes a new `InterstitialRenderingAdUnit` with the specified configuration ID and event handler. + /// - Parameters: + /// - configID: The unique identifier for the ad unit configuration. + /// - eventHandler: An object for handling ad events. public convenience init(configID: String, eventHandler: AnyObject?) { self.init( configID: configID, @@ -117,6 +140,11 @@ public class InterstitialRenderingAdUnit: NSObject, BaseInterstitialAdUnitProtoc ) } + /// Initializes a new `InterstitialRenderingAdUnit` with the specified configuration ID, minimum size percentage, and event handler. + /// - Parameters: + /// - configID: The unique identifier for the ad unit configuration. + /// - minSizePercentage: The minimum size percentage for the ad unit. + /// - eventHandler: An object for handling ad events. public convenience init( configID: String, minSizePercentage: CGSize, @@ -147,122 +175,176 @@ public class InterstitialRenderingAdUnit: NSObject, BaseInterstitialAdUnitProtoc // MARK: - Public methods + /// Loads a new ad. public func loadAd() { baseAdUnit.loadAd() } + /// Shows the ad from a specified view controller. + /// - Parameter controller: The view controller from which the ad will be presented. + /// - Note: This method must be called on the main thread. public func show(from controller: UIViewController) { baseAdUnit.show(from: controller) } // MARK: - Ext Data (imp[].ext.data) + /// Adds context data for a specified key. + /// - Parameters: + /// - data: The data to add. + /// - key: The key associated with the data. @available(*, deprecated, message: "This method is deprecated. Please, use addExtData method instead.") public func addContextData(_ data: String, forKey key: String) { addExtData(key: key, value: data) } + /// Updates context data for a specified key. + /// - Parameters: + /// - data: A set of data to update. + /// - key: The key associated with the data. @available(*, deprecated, message: "This method is deprecated. Please, use updateExtData method instead.") public func updateContextData(_ data: Set, forKey key: String) { updateExtData(key: key, value: data) } + /// Removes context data for a specified key. + /// - Parameter key: The key associated with the data to remove. @available(*, deprecated, message: "This method is deprecated. Please, use removeExtData method instead.") public func removeContextDate(forKey key: String) { removeExtData(forKey: key) } + /// Clears all context data. @available(*, deprecated, message: "This method is deprecated. Please, use clearExtData method instead.") public func clearContextData() { clearExtData() } + /// Adds ext data. + /// - Parameters: + /// - key: The key for the data. + /// - value: The value for the data. public func addExtData(key: String, value: String) { adUnitConfig.addExtData(key: key, value: value) } + /// Updates ext data. + /// - Parameters: + /// - key: The key for the data. + /// - value: The value for the data. public func updateExtData(key: String, value: Set) { adUnitConfig.updateExtData(key: key, value: value) } + /// Removes ext data. + /// - Parameters: + /// - key: The key for the data. public func removeExtData(forKey: String) { adUnitConfig.removeExtData(for: forKey) } + /// Clears ext data. public func clearExtData() { adUnitConfig.clearExtData() } // MARK: - Ext keywords (imp[].ext.keywords) + /// Adds a context keyword. + /// - Parameter newElement: The keyword to add. @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeyword method instead.") public func addContextKeyword(_ newElement: String) { addExtKeyword(newElement) } + /// Adds a set of context keywords. + /// - Parameter newElements: A set of keywords to add. @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeywords method instead.") public func addContextKeywords(_ newElements: Set) { addExtKeywords(newElements) } + /// Removes a context keyword. + /// - Parameter element: The keyword to remove. @available(*, deprecated, message: "This method is deprecated. Please, use removeExtKeyword method instead.") public func removeContextKeyword(_ element: String) { removeExtKeyword(element) } + /// Clears all context keywords. @available(*, deprecated, message: "This method is deprecated. Please, use clearExtKeywords method instead.") public func clearContextKeywords() { clearExtKeywords() } + /// Adds an extended keyword. + /// - Parameter newElement: The keyword to be added. public func addExtKeyword(_ newElement: String) { adUnitConfig.addExtKeyword(newElement) } + /// Adds multiple extended keywords. + /// - Parameter newElements: A set of keywords to be added. public func addExtKeywords(_ newElements: Set) { adUnitConfig.addExtKeywords(newElements) } + /// Removes an extended keyword. + /// - Parameter element: The keyword to be removed. public func removeExtKeyword(_ element: String) { adUnitConfig.removeExtKeyword(element) } + /// Clears all extended keywords. public func clearExtKeywords() { adUnitConfig.clearExtKeywords() } // MARK: - App Content (app.content.data) + /// Sets the app content data. + /// - Parameter appContent: The app content data. public func setAppContent(_ appContent: PBMORTBAppContent) { adUnitConfig.setAppContent(appContent) } + /// Clears the app content data. public func clearAppContent() { adUnitConfig.clearAppContent() } + /// Adds app content data objects. + /// - Parameter dataObjects: The data objects to be added. public func addAppContentData(_ dataObjects: [PBMORTBContentData]) { adUnitConfig.addAppContentData(dataObjects) } + /// Removes an app content data object. + /// - Parameter dataObject: The data object to be removed. public func removeAppContentDataObject(_ dataObject: PBMORTBContentData) { adUnitConfig.removeAppContentData(dataObject) } + /// Clears all app content data objects. public func clearAppContentDataObjects() { adUnitConfig.clearAppContentData() } // MARK: - User Data (user.data) + /// Adds user data objects. + /// - Parameter userDataObjects: The user data objects to be added. public func addUserData(_ userDataObjects: [PBMORTBContentData]) { adUnitConfig.addUserData(userDataObjects) } + /// Removes a user data object. + /// - Parameter userDataObject: The user data object to be removed. public func removeUserData(_ userDataObject: PBMORTBContentData) { adUnitConfig.removeUserData(userDataObject) } + /// Clears all user data objects. public func clearUserData() { adUnitConfig.clearUserData() } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift index 92403fa35..e5567a199 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift @@ -19,47 +19,57 @@ import UIKit @objc public class RewardedAdUnit: NSObject, BaseInterstitialAdUnitProtocol { + /// A delegate for handling interactions with the ad unit. public weak var delegate: RewardedAdUnitDelegate? + /// A Boolean value indicating whether the ad unit is ready to be displayed. public var isReady: Bool { baseAdUnit.isReady } + /// The set of ad formats supported by this ad unit. public var adFormats: Set { get { adUnitConfig.adFormats } set { adUnitConfig.adFormats = newValue } } + /// The ORTB (OpenRTB) configuration string for the ad unit. public var ortbConfig: String? { get { adUnitConfig.ortbConfig } set { adUnitConfig.ortbConfig = newValue } } + /// The banner parameters used for configuring ad unit. public var bannerParameters: BannerParameters { get { adUnitConfig.adConfiguration.bannerParameters } } + /// The video parameters used for configuring ad unit. public var videoParameters: VideoParameters { get { adUnitConfig.adConfiguration.videoParameters } } // MARK: - Video controls configuration + /// The area of the close button in the video controls as a percentage. public var closeButtonArea: Double { get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea } set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonArea = newValue } } + /// The position of the close button in the video controls. public var closeButtonPosition: Position { get { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition } set { adUnitConfig.adConfiguration.videoControlsConfig.closeButtonPosition = newValue } } + /// A Boolean value indicating whether the video controls are muted. public var isMuted: Bool { get { adUnitConfig.adConfiguration.videoControlsConfig.isMuted } set { adUnitConfig.adConfiguration.videoControlsConfig.isMuted = newValue } } + /// A Boolean value indicating whether the sound button is visible in the video controls. public var isSoundButtonVisible: Bool { get { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible } set { adUnitConfig.adConfiguration.videoControlsConfig.isSoundButtonVisible = newValue } @@ -77,6 +87,8 @@ public class RewardedAdUnit: NSObject, BaseInterstitialAdUnitProtocol { baseAdUnit.eventHandler } + /// Initializes a new `BaseInterstitialAdUnit` with the specified configuration ID. + /// - Parameter configID: The unique identifier for the ad unit configuration. public convenience init(configID: String) { self.init( configID: configID, @@ -85,6 +97,10 @@ public class RewardedAdUnit: NSObject, BaseInterstitialAdUnitProtocol { ) } + /// Initializes a new `InterstitialRenderingAdUnit` with the specified configuration ID and minimum size percentage. + /// - Parameters: + /// - configID: The unique identifier for the ad unit configuration. + /// - minSizePercentage: The minimum size percentage for the ad unit. public convenience init(configID: String, minSizePercentage: CGSize) { self.init( configID: configID, @@ -93,6 +109,10 @@ public class RewardedAdUnit: NSObject, BaseInterstitialAdUnitProtocol { ) } + /// Initializes a new `InterstitialRenderingAdUnit` with the specified configuration ID and event handler. + /// - Parameters: + /// - configID: The unique identifier for the ad unit configuration. + /// - eventHandler: An object for handling ad events. public convenience init(configID: String, eventHandler: AnyObject?) { self.init( configID: configID, @@ -101,6 +121,11 @@ public class RewardedAdUnit: NSObject, BaseInterstitialAdUnitProtocol { ) } + /// Initializes a new `InterstitialRenderingAdUnit` with the specified configuration ID, minimum size percentage, and event handler. + /// - Parameters: + /// - configID: The unique identifier for the ad unit configuration. + /// - minSizePercentage: The minimum size percentage for the ad unit. + /// - eventHandler: An object for handling ad events. public convenience init( configID: String, minSizePercentage: CGSize, @@ -131,122 +156,176 @@ public class RewardedAdUnit: NSObject, BaseInterstitialAdUnitProtocol { // MARK: - Public methods + /// Loads a new ad. public func loadAd() { baseAdUnit.loadAd() } + /// Shows the ad from a specified view controller. + /// - Parameter controller: The view controller from which the ad will be presented. + /// - Note: This method must be called on the main thread. public func show(from controller: UIViewController) { baseAdUnit.show(from: controller) } // MARK: - Ext Data (imp[].ext.data) + /// Adds context data for a specified key. + /// - Parameters: + /// - data: The data to add. + /// - key: The key associated with the data. @available(*, deprecated, message: "This method is deprecated. Please, use addExtData method instead.") public func addContextData(_ data: String, forKey key: String) { addExtData(key: key, value: data) } + /// Updates context data for a specified key. + /// - Parameters: + /// - data: A set of data to update. + /// - key: The key associated with the data. @available(*, deprecated, message: "This method is deprecated. Please, use updateExtData method instead.") public func updateContextData(_ data: Set, forKey key: String) { updateExtData(key: key, value: data) } + /// Removes context data for a specified key. + /// - Parameter key: The key associated with the data to remove. @available(*, deprecated, message: "This method is deprecated. Please, use removeExtData method instead.") public func removeContextDate(forKey key: String) { removeExtData(forKey: key) } + /// Clears all context data. @available(*, deprecated, message: "This method is deprecated. Please, use clearExtData method instead.") public func clearContextData() { clearExtData() } + /// Adds ext data. + /// - Parameters: + /// - key: The key for the data. + /// - value: The value for the data. public func addExtData(key: String, value: String) { adUnitConfig.addExtData(key: key, value: value) } + /// Updates ext data. + /// - Parameters: + /// - key: The key for the data. + /// - value: The value for the data. public func updateExtData(key: String, value: Set) { adUnitConfig.updateExtData(key: key, value: value) } + /// Removes ext data. + /// - Parameters: + /// - key: The key for the data. public func removeExtData(forKey: String) { adUnitConfig.removeExtData(for: forKey) } + /// Clears ext data. public func clearExtData() { adUnitConfig.clearExtData() } // MARK: - Ext keywords (imp[].ext.keywords) + /// Adds a context keyword. + /// - Parameter newElement: The keyword to add. @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeyword method instead.") public func addContextKeyword(_ newElement: String) { addExtKeyword(newElement) } + /// Adds a set of context keywords. + /// - Parameter newElements: A set of keywords to add. @available(*, deprecated, message: "This method is deprecated. Please, use addExtKeywords method instead.") public func addContextKeywords(_ newElements: Set) { addExtKeywords(newElements) } + /// Removes a context keyword. + /// - Parameter element: The keyword to remove. @available(*, deprecated, message: "This method is deprecated. Please, use removeExtKeyword method instead.") public func removeContextKeyword(_ element: String) { removeExtKeyword(element) } - + + /// Clears all context keywords. @available(*, deprecated, message: "This method is deprecated. Please, use clearExtKeywords method instead.") public func clearContextKeywords() { clearExtKeywords() } + /// Adds an extended keyword. + /// - Parameter newElement: The keyword to be added. public func addExtKeyword(_ newElement: String) { adUnitConfig.addExtKeyword(newElement) } + /// Adds multiple extended keywords. + /// - Parameter newElements: A set of keywords to be added. public func addExtKeywords(_ newElements: Set) { adUnitConfig.addExtKeywords(newElements) } + /// Removes an extended keyword. + /// - Parameter element: The keyword to be removed. public func removeExtKeyword(_ element: String) { adUnitConfig.removeExtKeyword(element) } + /// Clears all extended keywords. public func clearExtKeywords() { adUnitConfig.clearExtKeywords() } // MARK: - App Content (app.content.data) + /// Sets the app content data. + /// - Parameter appContent: The app content data. public func setAppContent(_ appContent: PBMORTBAppContent) { adUnitConfig.setAppContent(appContent) } + /// Clears the app content data. public func clearAppContent() { adUnitConfig.clearAppContent() } + /// Adds app content data objects. + /// - Parameter dataObjects: The data objects to be added. public func addAppContentData(_ dataObjects: [PBMORTBContentData]) { adUnitConfig.addAppContentData(dataObjects) } - + + /// Removes an app content data object. + /// - Parameter dataObject: The data object to be removed. public func removeAppContentDataObject(_ dataObject: PBMORTBContentData) { adUnitConfig.removeAppContentData(dataObject) } + /// Clears all app content data objects. public func clearAppContentDataObjects() { adUnitConfig.clearAppContentData() } // MARK: - User Data (user.data) + /// Adds user data objects. + /// - Parameter userDataObjects: The user data objects to be added. public func addUserData(_ userDataObjects: [PBMORTBContentData]) { adUnitConfig.addUserData(userDataObjects) } + /// Removes a user data object. + /// - Parameter userDataObject: The user data object to be removed. public func removeUserData(_ userDataObject: PBMORTBContentData) { adUnitConfig.removeUserData(userDataObject) } + /// Clears all user data objects. public func clearUserData() { adUnitConfig.clearUserData() } From 96bde09aa20df60bd4328d92c86a2c5d851388f3 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Tue, 8 Oct 2024 14:32:32 +0300 Subject: [PATCH 06/18] feat: introduce rewarded configuration --- PrebidMobile.xcodeproj/project.pbxproj | 60 ++++++++++++++ .../BuildFiles/PrebidMobile.modulemap | 9 +++ .../BuildFiles/PrebidMobileSwiftHeaders.h | 9 +++ .../AdTypes/AdView/AdConfiguration.swift | 3 + .../Integrations/GAM/PrebidReward.swift | 10 +-- .../Integrations/GAM/RewardedConfig.swift | 81 +++++++++++++++++++ .../Prebid/PBMCore/AdUnitConfig.swift | 1 + .../Prebid/PBMCore/Bid.swift | 4 + .../ORTB/Prebid/PBMORTBExtPrebidPassthrough.h | 3 + .../ORTB/Prebid/PBMORTBExtPrebidPassthrough.m | 9 +++ .../ORTB/Prebid/PBMORTBRewardedClose.h | 35 ++++++++ .../ORTB/Prebid/PBMORTBRewardedClose.m | 42 ++++++++++ .../ORTB/Prebid/PBMORTBRewardedCompletion.h | 33 ++++++++ .../ORTB/Prebid/PBMORTBRewardedCompletion.m | 20 +++++ .../Prebid/PBMORTBRewardedCompletionBanner.h | 31 +++++++ .../Prebid/PBMORTBRewardedCompletionBanner.m | 42 ++++++++++ .../Prebid/PBMORTBRewardedCompletionVideo.h | 37 +++++++++ .../Prebid/PBMORTBRewardedCompletionVideo.m | 44 ++++++++++ .../PBMORTBRewardedCompletionVideoEndcard.h | 31 +++++++ .../PBMORTBRewardedCompletionVideoEndcard.m | 42 ++++++++++ .../Prebid/PBMORTBRewardedConfiguration.h | 38 +++++++++ .../Prebid/PBMORTBRewardedConfiguration.m | 48 +++++++++++ .../ORTB/Prebid/PBMORTBRewardedReward.h | 35 ++++++++ .../ORTB/Prebid/PBMORTBRewardedReward.m | 44 ++++++++++ 24 files changed, 706 insertions(+), 5 deletions(-) create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedConfig.swift create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.h create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.m create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.h create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.h create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.m create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.h create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.m create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.h create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.m create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.h create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.m create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.h create mode 100644 PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.m diff --git a/PrebidMobile.xcodeproj/project.pbxproj b/PrebidMobile.xcodeproj/project.pbxproj index 95ad601e2..84347c3a0 100644 --- a/PrebidMobile.xcodeproj/project.pbxproj +++ b/PrebidMobile.xcodeproj/project.pbxproj @@ -78,6 +78,21 @@ 533E0FB929100076000CC24F /* MockGADMobileAds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 533E0FB829100076000CC24F /* MockGADMobileAds.swift */; }; 533FDF852A12030C0066ED5A /* MockPrebidJSLibraryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 533FDF842A12030C0066ED5A /* MockPrebidJSLibraryManager.swift */; }; 5347473B2BFB4D3D00966658 /* UserAgentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5347473A2BFB4D3D00966658 /* UserAgentService.swift */; }; + 534C611F2CB5252C0026119A /* PBMORTBRewardedConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C611D2CB5252C0026119A /* PBMORTBRewardedConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 534C61202CB5252C0026119A /* PBMORTBRewardedConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C611E2CB5252C0026119A /* PBMORTBRewardedConfiguration.m */; }; + 534C61232CB526CE0026119A /* PBMORTBRewardedReward.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C61212CB526CE0026119A /* PBMORTBRewardedReward.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 534C61242CB526CE0026119A /* PBMORTBRewardedReward.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61222CB526CE0026119A /* PBMORTBRewardedReward.m */; }; + 534C61272CB5279C0026119A /* PBMORTBRewardedCompletionBanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C61252CB5279C0026119A /* PBMORTBRewardedCompletionBanner.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 534C61282CB5279C0026119A /* PBMORTBRewardedCompletionBanner.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61262CB5279C0026119A /* PBMORTBRewardedCompletionBanner.m */; }; + 534C612D2CB527F80026119A /* PBMORTBRewardedCompletionVideo.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C612B2CB527F80026119A /* PBMORTBRewardedCompletionVideo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 534C612E2CB527F80026119A /* PBMORTBRewardedCompletionVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C612C2CB527F80026119A /* PBMORTBRewardedCompletionVideo.m */; }; + 534C61312CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C612F2CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 534C61322CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61302CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.m */; }; + 534C61352CB529240026119A /* PBMORTBRewardedClose.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C61332CB529240026119A /* PBMORTBRewardedClose.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 534C61362CB529240026119A /* PBMORTBRewardedClose.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61342CB529240026119A /* PBMORTBRewardedClose.m */; }; + 534C61392CB52A4E0026119A /* PBMORTBRewardedCompletion.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C61372CB52A4E0026119A /* PBMORTBRewardedCompletion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 534C613A2CB52A4E0026119A /* PBMORTBRewardedCompletion.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61382CB52A4E0026119A /* PBMORTBRewardedCompletion.m */; }; + 534C613C2CB536F00026119A /* RewardedConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C613B2CB536F00026119A /* RewardedConfig.swift */; }; 5355ACA929C454070014F16E /* VAST_with_empty_companion.xml in Resources */ = {isa = PBXBuildFile; fileRef = 5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */; }; 5355ACAB29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */; }; 536A39262A84C50F00B1CCEA /* StringExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */; }; @@ -942,6 +957,21 @@ 533E0FB829100076000CC24F /* MockGADMobileAds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGADMobileAds.swift; sourceTree = ""; }; 533FDF842A12030C0066ED5A /* MockPrebidJSLibraryManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPrebidJSLibraryManager.swift; sourceTree = ""; }; 5347473A2BFB4D3D00966658 /* UserAgentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentService.swift; sourceTree = ""; }; + 534C611D2CB5252C0026119A /* PBMORTBRewardedConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBRewardedConfiguration.h; sourceTree = ""; }; + 534C611E2CB5252C0026119A /* PBMORTBRewardedConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PBMORTBRewardedConfiguration.m; sourceTree = ""; }; + 534C61212CB526CE0026119A /* PBMORTBRewardedReward.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBRewardedReward.h; sourceTree = ""; }; + 534C61222CB526CE0026119A /* PBMORTBRewardedReward.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PBMORTBRewardedReward.m; sourceTree = ""; }; + 534C61252CB5279C0026119A /* PBMORTBRewardedCompletionBanner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBRewardedCompletionBanner.h; sourceTree = ""; }; + 534C61262CB5279C0026119A /* PBMORTBRewardedCompletionBanner.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PBMORTBRewardedCompletionBanner.m; sourceTree = ""; }; + 534C612B2CB527F80026119A /* PBMORTBRewardedCompletionVideo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBRewardedCompletionVideo.h; sourceTree = ""; }; + 534C612C2CB527F80026119A /* PBMORTBRewardedCompletionVideo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PBMORTBRewardedCompletionVideo.m; sourceTree = ""; }; + 534C612F2CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBRewardedCompletionVideoEndcard.h; sourceTree = ""; }; + 534C61302CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PBMORTBRewardedCompletionVideoEndcard.m; sourceTree = ""; }; + 534C61332CB529240026119A /* PBMORTBRewardedClose.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBRewardedClose.h; sourceTree = ""; }; + 534C61342CB529240026119A /* PBMORTBRewardedClose.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PBMORTBRewardedClose.m; sourceTree = ""; }; + 534C61372CB52A4E0026119A /* PBMORTBRewardedCompletion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBRewardedCompletion.h; sourceTree = ""; }; + 534C61382CB52A4E0026119A /* PBMORTBRewardedCompletion.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PBMORTBRewardedCompletion.m; sourceTree = ""; }; + 534C613B2CB536F00026119A /* RewardedConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardedConfig.swift; sourceTree = ""; }; 5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = VAST_with_empty_companion.xml; sourceTree = ""; }; 5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreativeModelCollectionMakerVASTTests.swift; sourceTree = ""; }; 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensionsTest.swift; sourceTree = ""; }; @@ -2503,6 +2533,20 @@ 924F661727FDB79C00C8DAF7 /* PBMORTBExtPrebidPassthrough.h */, 924F661D27FDBC3100C8DAF7 /* PBMORTBExtPrebidPassthrough.m */, 5BC3781C271F1CFF00444D5E /* PBMORTBPrebid.h */, + 534C61332CB529240026119A /* PBMORTBRewardedClose.h */, + 534C61342CB529240026119A /* PBMORTBRewardedClose.m */, + 534C61372CB52A4E0026119A /* PBMORTBRewardedCompletion.h */, + 534C61382CB52A4E0026119A /* PBMORTBRewardedCompletion.m */, + 534C61252CB5279C0026119A /* PBMORTBRewardedCompletionBanner.h */, + 534C61262CB5279C0026119A /* PBMORTBRewardedCompletionBanner.m */, + 534C612B2CB527F80026119A /* PBMORTBRewardedCompletionVideo.h */, + 534C612C2CB527F80026119A /* PBMORTBRewardedCompletionVideo.m */, + 534C612F2CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.h */, + 534C61302CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.m */, + 534C611D2CB5252C0026119A /* PBMORTBRewardedConfiguration.h */, + 534C611E2CB5252C0026119A /* PBMORTBRewardedConfiguration.m */, + 534C61212CB526CE0026119A /* PBMORTBRewardedReward.h */, + 534C61222CB526CE0026119A /* PBMORTBRewardedReward.m */, 53A657AE2A8B64B300AE0B4F /* PBMORTBSDKConfiguration.h */, 53A657AF2A8B64C200AE0B4F /* PBMORTBSDKConfiguration.m */, 92664564272AB5BB0064F7BD /* PBMORTBSkadnFidelity.h */, @@ -2560,6 +2604,7 @@ 5BC37853271F1CFF00444D5E /* RewardedEventHandlerProtocol.swift */, 5BC37846271F1CFF00444D5E /* RewardedEventInteractionDelegate.swift */, 5BC3784F271F1CFF00444D5E /* RewardedEventLoadingDelegate.swift */, + 534C613B2CB536F00026119A /* RewardedConfig.swift */, ); path = GAM; sourceTree = ""; @@ -3404,6 +3449,7 @@ 5BC37ACC271F1D0100444D5E /* PBMORTBParameterBuilder.h in Headers */, 5BC37A70271F1D0000444D5E /* PBMORTBAbstractResponse+Protected.h in Headers */, 5BC379AA271F1D0000444D5E /* PBMModalViewControllerDelegate.h in Headers */, + 534C61272CB5279C0026119A /* PBMORTBRewardedCompletionBanner.h in Headers */, 5BC3791F271F1CFF00444D5E /* PBMDeviceAccessManagerKeys.h in Headers */, 5BC378D2271F1CFF00444D5E /* PBMORTBBanner.h in Headers */, 5BC37987271F1D0000444D5E /* PBMCreativeModelMakerResult.h in Headers */, @@ -3462,6 +3508,7 @@ 5BC379B8271F1D0000444D5E /* PBMAdViewManager.h in Headers */, 5BC379B3271F1D0000444D5E /* PBMVideoViewDelegate.h in Headers */, 5BC378F2271F1CFF00444D5E /* PBMORTBAbstract.h in Headers */, + 534C611F2CB5252C0026119A /* PBMORTBRewardedConfiguration.h in Headers */, 5BC37AA0271F1D0000444D5E /* PBMAdLoaderFlowDelegate.h in Headers */, 5BC3794F271F1D0000444D5E /* PBMErrorType.h in Headers */, 5BC37928271F1CFF00444D5E /* PBMDownloadDataHelper.h in Headers */, @@ -3472,6 +3519,7 @@ 5BC379D8271F1D0000444D5E /* PBMDisplayView+InternalState.h in Headers */, 53BDBF8A293F605B004B6DE8 /* InternalUserConsentDataManager.h in Headers */, 5BC37A6B271F1D0000444D5E /* PBMORTBNoBidReason.h in Headers */, + 534C61392CB52A4E0026119A /* PBMORTBRewardedCompletion.h in Headers */, 5BC3799A271F1D0000444D5E /* PBMModalViewController.h in Headers */, 5BC37A9C271F1D0000444D5E /* PBMAdLoaderProtocol.h in Headers */, 5BC37AA1271F1D0000444D5E /* PBMInterstitialAdLoader.h in Headers */, @@ -3488,6 +3536,7 @@ 5BC37A9E271F1D0000444D5E /* PBMAdLoadFlowState.h in Headers */, 5BC379BD271F1D0000444D5E /* PBMAdRefreshOptions.h in Headers */, 5BC378F8271F1CFF00444D5E /* PBMORTBPmp.h in Headers */, + 534C612D2CB527F80026119A /* PBMORTBRewardedCompletionVideo.h in Headers */, 92664565272AB5BB0064F7BD /* PBMORTBSkadnFidelity.h in Headers */, 53F096CA27E917D40058C94C /* Log+Extensions.h in Headers */, 5BC3797F271F1D0000444D5E /* PBMMRAIDCommand.h in Headers */, @@ -3499,6 +3548,7 @@ 5BC37A5B271F1D0000444D5E /* PBMORTBAbstractResponse.h in Headers */, 5BC37909271F1CFF00444D5E /* PBMDeepLinkPlusHelper+Testing.h in Headers */, 5BC3799B271F1D0000444D5E /* PBMDeferredModalState.h in Headers */, + 534C61352CB529240026119A /* PBMORTBRewardedClose.h in Headers */, 5BC37912271F1CFF00444D5E /* PBMConstants.h in Headers */, 5BC37A64271F1D0000444D5E /* PBMORTBBidResponseExt.h in Headers */, 5BC3794D271F1D0000444D5E /* Prebid+TestExtension.h in Headers */, @@ -3513,6 +3563,7 @@ 5BC3795A271F1D0000444D5E /* PBMVastResourceContainerProtocol.h in Headers */, 5BC37925271F1CFF00444D5E /* PBMNSThreadProtocol.h in Headers */, 5BC37ABC271F1D0000444D5E /* PBMOpenMeasurementSession.h in Headers */, + 534C61312CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.h in Headers */, 5BC379A1271F1D0000444D5E /* PBMModalPresentationController.h in Headers */, 5BC378B5271F1CFF00444D5E /* PBMViewExposureChecker.h in Headers */, 5BC37A52271F1D0000444D5E /* PBMAdMarkupStringHandler.h in Headers */, @@ -3577,6 +3628,7 @@ 5BC3799D271F1D0000444D5E /* PBMTouchForwardingView.h in Headers */, 5BC37AD4271F1D0100444D5E /* PBMParameterBuilderProtocol.h in Headers */, 5BC37A19271F1D0000444D5E /* PBMBidRequesterFactoryBlock.h in Headers */, + 534C61232CB526CE0026119A /* PBMORTBRewardedReward.h in Headers */, 5BC379B0271F1D0000444D5E /* PBMAutoRefreshManager.h in Headers */, 5BC37AD3271F1D0100444D5E /* PBMBasicParameterBuilder.h in Headers */, 5BC3798A271F1D0000444D5E /* PBMInterstitialDisplayProperties.h in Headers */, @@ -4064,6 +4116,7 @@ 9236A64E272FEAFE00ABBEF4 /* ImpressionTasksExecutor.swift in Sources */, FAEE4D26262DC2B200AD9966 /* ExternalUserId.swift in Sources */, 5BC379A0271F1D0000444D5E /* PBMTouchForwardingView.m in Sources */, + 534C61202CB5252C0026119A /* PBMORTBRewardedConfiguration.m in Sources */, 5BC378D4271F1CFF00444D5E /* PBMORTBDeviceExtAtts.m in Sources */, 92C85D6E27A983150080BAC5 /* NativeAdMarkup.swift in Sources */, 53138B2C2A7132CD00B18B5C /* PrebidGAMVersionChecker.swift in Sources */, @@ -4079,6 +4132,8 @@ 537B651E2833A3DA008AE9D1 /* Reachability.swift in Sources */, 5BC37A5D271F1D0000444D5E /* PBMORTBBidExtPrebidCache.m in Sources */, 5BC379DB271F1D0000444D5E /* InterstitialControllerLoadingDelegate.swift in Sources */, + 534C61242CB526CE0026119A /* PBMORTBRewardedReward.m in Sources */, + 534C61322CB5282F0026119A /* PBMORTBRewardedCompletionVideoEndcard.m in Sources */, 5BC3794A271F1D0000444D5E /* PBMAdDetails.m in Sources */, 92C85D7027A987260080BAC5 /* NativeEventTrackerResponse.swift in Sources */, 5BC379C7271F1D0000444D5E /* PBMVideoView.m in Sources */, @@ -4104,6 +4159,7 @@ 5BC3796D271F1D0000444D5E /* PBMVastCreativeNonLinearAds.m in Sources */, 5BC379C9271F1D0000444D5E /* PBMAdRequestResponseVAST.m in Sources */, 5BC378F9271F1CFF00444D5E /* PBMORTBPublisher.m in Sources */, + 534C61362CB529240026119A /* PBMORTBRewardedClose.m in Sources */, 5BC379D6271F1D0000444D5E /* PBMWebView.m in Sources */, 92AFE57F274FCD9900B0430C /* PBMORTBAppContent.m in Sources */, 92664569272AB9120064F7BD /* SkadnEventTracker.swift in Sources */, @@ -4134,11 +4190,13 @@ 5BC378AC271F1CFF00444D5E /* Gender.swift in Sources */, 5BC37966271F1D0000444D5E /* PBMVastCreativeCompanionAds.m in Sources */, 5BC379D3271F1D0000444D5E /* PBMMRAIDJavascriptCommands.m in Sources */, + 534C613C2CB536F00026119A /* RewardedConfig.swift in Sources */, 5BC378B7271F1CFF00444D5E /* UIView+PBMViewExposure.m in Sources */, 53322AA8282E29910049229D /* EventManager.swift in Sources */, 531CF21927E8FC1B005E5ABE /* LogLevel.swift in Sources */, FAEE4D1E262DC2B200AD9966 /* VideoInterstitialAdUnit.swift in Sources */, 5BC378FF271F1CFF00444D5E /* PBMORTBImpExtPrebid.m in Sources */, + 534C612E2CB527F80026119A /* PBMORTBRewardedCompletionVideo.m in Sources */, 5BC37A14271F1D0000444D5E /* PBMError_Extension.swift in Sources */, 34C9CD602850CE6300FB5451 /* OMSDKVersionProvider.m in Sources */, 5BC378B3271F1CFF00444D5E /* NSException+PBMExtensions.m in Sources */, @@ -4187,8 +4245,10 @@ 53C925052990FBFB009E6F94 /* PrebidServerStatusRequester.swift in Sources */, 5BC378DE271F1CFF00444D5E /* PBMORTBDeviceExtPrebidInterstitial.m in Sources */, 5BC37A5F271F1D0000444D5E /* PBMORTBBidExtSkadn.m in Sources */, + 534C61282CB5279C0026119A /* PBMORTBRewardedCompletionBanner.m in Sources */, 5BC3793A271F1D0000444D5E /* PBMLocationManager.m in Sources */, 5BC37AB5271F1D0000444D5E /* PBMOpenMeasurementSession.m in Sources */, + 534C613A2CB52A4E0026119A /* PBMORTBRewardedCompletion.m in Sources */, 9298964B275FD3C300D3C174 /* JSONConvertible.swift in Sources */, 53A368E42AB2E0AA00A03B3E /* PrebidAdUnit.swift in Sources */, 5BC37A58271F1D0000444D5E /* PBMORTBNoBidReason.m in Sources */, diff --git a/PrebidMobile/BuildFiles/PrebidMobile.modulemap b/PrebidMobile/BuildFiles/PrebidMobile.modulemap index f6849bb33..464cb6231 100644 --- a/PrebidMobile/BuildFiles/PrebidMobile.modulemap +++ b/PrebidMobile/BuildFiles/PrebidMobile.modulemap @@ -157,6 +157,15 @@ framework module PrebidMobile { header "PBMORTBContentSegment.h" header "PBMORTBNative.h" + // Rewarded + header "PBMORTBRewardedClose.h" + header "PBMORTBRewardedCompletion.h" + header "PBMORTBRewardedCompletionBanner.h" + header "PBMORTBRewardedCompletionVideo.h" + header "PBMORTBRewardedCompletionVideoEndcard.h" + header "PBMORTBRewardedConfiguration.h" + header "PBMORTBRewardedReward.h" + header "NSDictionary+PBMExtensions.h" header "NSMutableDictionary+PBMExtensions.h" header "PBMLocationManager.h" diff --git a/PrebidMobile/BuildFiles/PrebidMobileSwiftHeaders.h b/PrebidMobile/BuildFiles/PrebidMobileSwiftHeaders.h index 2c2b9c7a3..be5a45fcb 100644 --- a/PrebidMobile/BuildFiles/PrebidMobileSwiftHeaders.h +++ b/PrebidMobile/BuildFiles/PrebidMobileSwiftHeaders.h @@ -34,6 +34,15 @@ #import "PBMORTBExtPrebidEvents.h" #import "PBMORTBAdConfiguration.h" #import "PBMRawBidResponse.h" + +#import "PBMORTBRewardedClose.h" +#import "PBMORTBRewardedCompletion.h" +#import "PBMORTBRewardedCompletionBanner.h" +#import "PBMORTBRewardedCompletionVideo.h" +#import "PBMORTBRewardedCompletionVideoEndcard.h" +#import "PBMORTBRewardedConfiguration.h" +#import "PBMORTBRewardedReward.h" + #import "PBMLocationManager.h" #import "Log+Extensions.h" diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift index 663641e3b..ef3b688e2 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/AdConfiguration.swift @@ -94,6 +94,9 @@ public class AdConfiguration: AutoRefreshCountConfig { */ public lazy var videoControlsConfig = VideoControlsConfiguration() + /// Server-side configuration for rewarded ads (bid.ext.rwdd) + public var rewardedConfig: RewardedConfig? + // MARK: - Impression Tracking public var pollFrequency: TimeInterval = 0.2 diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift index 5fbf59cdf..284fca86b 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift @@ -22,9 +22,9 @@ public class PrebidReward: NSObject { public var count: NSNumber? public var ext: [String: Any]? -// init(with ortbReward: TQBORTBBidExtRewardedReward? = nil) { -// self.type = ortbReward?.type -// self.count = ortbReward?.count -// self.ext = ortbReward?.ext -// } + init(with ortbReward: PBMORTBRewardedReward? = nil) { + self.type = ortbReward?.type + self.count = ortbReward?.count + self.ext = ortbReward?.ext + } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedConfig.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedConfig.swift new file mode 100644 index 000000000..636d324a5 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedConfig.swift @@ -0,0 +1,81 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ + +import Foundation + +@objc(PBMRewardedConfig) @objcMembers +public class RewardedConfig: NSObject { + + // MARK: - Reward + + public var reward: PrebidReward? { + PrebidReward(with: ortbRewarded.reward) + } + + // MARK: - Banner + + public var bannerTime: NSNumber? { + ortbRewarded.completion?.banner?.time + } + + public var bannerEvent: String? { + ortbRewarded.completion?.banner?.event + } + + // MARK: - Video + + public var videoTime: NSNumber? { + ortbRewarded.completion?.video?.time + } + + public var videoPlaybackevent: String? { + ortbRewarded.completion?.video?.playbackevent + } + + + // MARK: - Endcard + + public var endcardTime: NSNumber? { + ortbRewarded.completion?.video?.endcard?.time + } + + public var endcardEvent: String? { + ortbRewarded.completion?.video?.endcard?.event + } + + // MARK: - Close + + public var closeAction: String? { + ortbRewarded.close?.action + } + + public var postRewardTime: NSNumber? { + ortbRewarded.close?.postrewardtime + } + + // MARK: - Default Values + + /// The timeout duration for rewarded completion, measured in seconds. + public let defaultCompletionTime: NSNumber = 120 + + /// The playback event when the SDK should send a signal to the application that the user has earned the reward + public let defaultVideoPlaybackEvent = "complete" + + private let ortbRewarded: PBMORTBRewardedConfiguration + + init(ortbRewarded: PBMORTBRewardedConfiguration) { + self.ortbRewarded = ortbRewarded + } +} diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift index 2e0aa773a..7ded2a488 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/AdUnitConfig.swift @@ -318,6 +318,7 @@ public class AdUnitConfig: NSObject, NSCopying { clone.adPosition = self.adPosition clone.pbAdSlot = self.pbAdSlot + clone.adConfiguration.rewardedConfig = self.adConfiguration.rewardedConfig clone.adConfiguration.winningBidAdFormat = self.adConfiguration.winningBidAdFormat clone.adConfiguration.adFormats = self.adConfiguration.adFormats clone.adConfiguration.isOriginalAPI = self.adConfiguration.isOriginalAPI diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/Bid.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/Bid.swift index da3b7e409..98f75cfe3 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/Bid.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/Bid.swift @@ -87,6 +87,10 @@ public class Bid: NSObject { } #endif + public var rewardedConfig: PBMORTBRewardedConfiguration? { + bid.ext.prebid?.passthrough?.filter { $0.type == "prebidmobilesdk" }.first?.rewardedConfiguration + } + /// Returns YES if this bid is intented for display. @objc public var isWinning: Bool { guard let targetingInfo = self.targetingInfo else { diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBExtPrebidPassthrough.h b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBExtPrebidPassthrough.h index 9ac25c880..67781fdc4 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBExtPrebidPassthrough.h +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBExtPrebidPassthrough.h @@ -18,6 +18,7 @@ @class PBMORTBAdConfiguration; @class PBMORTBSDKConfiguration; +@class PBMORTBRewardedConfiguration; NS_ASSUME_NONNULL_BEGIN @@ -29,6 +30,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, nullable) PBMORTBSDKConfiguration *sdkConfiguration; +@property (nonatomic, strong, nullable) PBMORTBRewardedConfiguration *rewardedConfiguration; + @end NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBExtPrebidPassthrough.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBExtPrebidPassthrough.m index 871f50d50..8655c37a2 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBExtPrebidPassthrough.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBExtPrebidPassthrough.m @@ -16,6 +16,7 @@ #import "PBMORTBExtPrebidPassthrough.h" #import "PBMORTBAdConfiguration.h" #import "PBMORTBSDKConfiguration.h" +#import "PBMORTBRewardedConfiguration.h" @implementation PBMORTBExtPrebidPassthrough @@ -38,6 +39,12 @@ - (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { _sdkConfiguration = [[PBMORTBSDKConfiguration alloc] initWithJsonDictionary:sdkConfigDic]; } + PBMJsonDictionary * const rewardedConfigDic = jsonDictionary[@"rwdd"]; + + if (rewardedConfigDic) { + _rewardedConfiguration = [[PBMORTBRewardedConfiguration alloc] initWithJsonDictionary:rewardedConfigDic]; + } + return self; } @@ -50,6 +57,8 @@ - (PBMJsonDictionary *)toJsonDictionary { ret[@"sdkconfiguration"] = [self.sdkConfiguration toJsonDictionary]; + ret[@"rwdd"] = [self.rewardedConfiguration toJsonDictionary]; + [ret pbmRemoveEmptyVals]; return ret; diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.h b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.h new file mode 100644 index 000000000..63ca40ca4 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.h @@ -0,0 +1,35 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBAbstract.h" +#import "PBMORTBAbstract+Protected.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Describes the close behavior. How should the SDK manage the ad when it is encountered as viewed +@interface PBMORTBRewardedClose : PBMORTBAbstract + +/// The time interval in seconds passed after the reward event when SDK should close the interstitial +@property (nonatomic, strong, nullable) NSNumber *postrewardtime; + +/// The action that SDK should do. +/// Available options: +/// - autoclose - close the interstitial; +/// - closebutton - show the close button. +@property (nonatomic, strong, nullable) NSString *action; + +@end + +NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.m new file mode 100644 index 000000000..232728ee2 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.m @@ -0,0 +1,42 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBRewardedClose.h" + +@implementation PBMORTBRewardedClose + +- (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { + if (!(self = [self init])) { + return nil; + } + + _postrewardtime = jsonDictionary[@"postrewardtime"]; + _action = jsonDictionary[@"action"]; + + return self; +} + +- (PBMJsonDictionary *)toJsonDictionary { + PBMMutableJsonDictionary * const ret = [[PBMMutableJsonDictionary alloc] init]; + + ret[@"postrewardtime"] = self.postrewardtime; + ret[@"action"] = self.action; + + [ret pbmRemoveEmptyVals]; + + return ret; +} + +@end diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.h b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.h new file mode 100644 index 000000000..3d385ee09 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.h @@ -0,0 +1,33 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBAbstract.h" +#import "PBMORTBAbstract+Protected.h" + +@class PBMORTBRewardedCompletionBanner; +@class PBMORTBRewardedCompletionVideo; + +NS_ASSUME_NONNULL_BEGIN + +/// Describes the condition when the SDK should send a signal to the application that the user has earned the reward. +@interface PBMORTBRewardedCompletion : PBMORTBAbstract + +@property (nonatomic, strong, nullable) PBMORTBRewardedCompletionBanner * banner; + +@property (nonatomic, strong, nullable) PBMORTBRewardedCompletionVideo * video; + +@end + +NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m new file mode 100644 index 000000000..fe7e0d279 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m @@ -0,0 +1,20 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBRewardedCompletion.h" + +@implementation PBMORTBRewardedCompletion + +@end diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.h b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.h new file mode 100644 index 000000000..18f48bd7f --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.h @@ -0,0 +1,31 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBAbstract.h" +#import "PBMORTBAbstract+Protected.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PBMORTBRewardedCompletionBanner : PBMORTBAbstract + +/// The period of time that the ad is on the screen and the user earns a reward +@property (nonatomic, strong, nullable) NSNumber *time; + +/// The URL with a custom schema that will be sent by the creative and should be caught by the SDK +@property (nonatomic, strong, nullable) NSString *event; + +@end + +NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.m new file mode 100644 index 000000000..1b5d8469c --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.m @@ -0,0 +1,42 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBRewardedCompletionBanner.h" + +@implementation PBMORTBRewardedCompletionBanner + +- (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { + if (!(self = [self init])) { + return nil; + } + + _time = jsonDictionary[@"time"]; + _event = jsonDictionary[@"event"]; + + return self; +} + +- (PBMJsonDictionary *)toJsonDictionary { + PBMMutableJsonDictionary * const ret = [[PBMMutableJsonDictionary alloc] init]; + + ret[@"time"] = self.time; + ret[@"event"] = self.event; + + [ret pbmRemoveEmptyVals]; + + return ret; +} + +@end diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.h b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.h new file mode 100644 index 000000000..b499da9d6 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.h @@ -0,0 +1,37 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBAbstract.h" +#import "PBMORTBAbstract+Protected.h" + +#import "PBMORTBRewardedCompletionVideoEndcard.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PBMORTBRewardedCompletionVideo : PBMORTBAbstract + +/// The period of time that the ad is on the screen and the user earns a reward +@property (nonatomic, strong, nullable) NSNumber *time; + +/// The playback part when the user earns a reward +@property (nonatomic, strong, nullable) NSString *playbackevent; + +/// Endcard completion criteria +@property (nonatomic, strong, nullable) PBMORTBRewardedCompletionVideoEndcard *endcard; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.m new file mode 100644 index 000000000..f82272304 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.m @@ -0,0 +1,44 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBRewardedCompletionVideo.h" + +@implementation PBMORTBRewardedCompletionVideo + +- (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { + if (!(self = [self init])) { + return nil; + } + + _time = jsonDictionary[@"time"]; + _playbackevent = jsonDictionary[@"playbackevent"]; + _endcard = [[PBMORTBRewardedCompletionVideoEndcard alloc] initWithJsonDictionary:jsonDictionary[@"endcard"]]; + + return self; +} + +- (PBMJsonDictionary *)toJsonDictionary { + PBMMutableJsonDictionary * const ret = [[PBMMutableJsonDictionary alloc] init]; + + ret[@"time"] = self.time; + ret[@"playbackevent"] = self.playbackevent; + ret[@"endcard"] = [self.endcard toJsonDictionary]; + + [ret pbmRemoveEmptyVals]; + + return ret; +} + +@end diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.h b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.h new file mode 100644 index 000000000..12eb0bb78 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.h @@ -0,0 +1,31 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBAbstract.h" +#import "PBMORTBAbstract+Protected.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface PBMORTBRewardedCompletionVideoEndcard : PBMORTBAbstract + +/// The period of time that the ad is on the screen and the user earns a reward +@property (nonatomic, strong, nullable) NSNumber *time; + +/// The URL with a custom schema that will be sent by the creative and should be caught by the SDK +@property (nonatomic, strong, nullable) NSString *event; + +@end + +NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.m new file mode 100644 index 000000000..9ed18305f --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.m @@ -0,0 +1,42 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBRewardedCompletionVideoEndcard.h" + +@implementation PBMORTBRewardedCompletionVideoEndcard + +- (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { + if (!(self = [self init])) { + return nil; + } + + _time = jsonDictionary[@"time"]; + _event = jsonDictionary[@"event"]; + + return self; +} + +- (PBMJsonDictionary *)toJsonDictionary { + PBMMutableJsonDictionary * const ret = [[PBMMutableJsonDictionary alloc] init]; + + ret[@"time"] = self.time; + ret[@"event"] = self.event; + + [ret pbmRemoveEmptyVals]; + + return ret; +} + +@end diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.h b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.h new file mode 100644 index 000000000..ec6ec7116 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.h @@ -0,0 +1,38 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBAbstract.h" +#import "PBMORTBAbstract+Protected.h" + +@class PBMORTBRewardedReward; +@class PBMORTBRewardedCompletion; +@class PBMORTBRewardedClose; + +NS_ASSUME_NONNULL_BEGIN + +@interface PBMORTBRewardedConfiguration : PBMORTBAbstract + +/// Metadata provided by the publisher to describe the reward. +@property (nonatomic, strong, nullable) PBMORTBRewardedReward * reward; + +/// Describes the condition when the SDK should send a signal to the application that the user has earned the reward. +@property (nonatomic, strong, nullable) PBMORTBRewardedCompletion * completion; + +/// Describes the close behavior. How should the SDK manage the ad when it is encountered as viewed. +@property (nonatomic, strong, nullable) PBMORTBRewardedClose * close; + +@end + +NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.m new file mode 100644 index 000000000..359d306ca --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.m @@ -0,0 +1,48 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBRewardedConfiguration.h" + +#import "PBMORTBRewardedReward.h" +#import "PBMORTBRewardedCompletion.h" +#import "PBMORTBRewardedClose.h" + +@implementation PBMORTBRewardedConfiguration + +- (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { + if (!(self = [self init])) { + return nil; + } + + _reward = [[PBMORTBRewardedReward alloc] initWithJsonDictionary:jsonDictionary[@"reward"]]; + _completion = [[PBMORTBRewardedCompletion alloc] initWithJsonDictionary:jsonDictionary[@"completion"]]; + _close = [[PBMORTBRewardedClose alloc] initWithJsonDictionary:jsonDictionary[@"close"]]; + + return self; +} + +- (PBMJsonDictionary *)toJsonDictionary { + PBMMutableJsonDictionary * const ret = [[PBMMutableJsonDictionary alloc] init]; + + ret[@"reward"] = [self.reward toJsonDictionary]; + ret[@"completion"] = [self.completion toJsonDictionary]; + ret[@"close"] = [self.close toJsonDictionary]; + + [ret pbmRemoveEmptyVals]; + + return ret; +} + +@end diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.h b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.h new file mode 100644 index 000000000..2ef66f05d --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.h @@ -0,0 +1,35 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBAbstract.h" +#import "PBMORTBAbstract+Protected.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Metadata provided by the publisher to describe the reward +@interface PBMORTBRewardedReward : PBMORTBAbstract + +/// Type of the reward +@property (nonatomic, strong, nullable) NSString *type; + +/// Amount of reward +@property (nonatomic, strong, nullable) NSNumber *count; + +/// For the future extensions +@property (nonatomic, strong, nullable) PBMJsonDictionary *ext; + +@end + +NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.m new file mode 100644 index 000000000..29176a679 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.m @@ -0,0 +1,44 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMORTBRewardedReward.h" + +@implementation PBMORTBRewardedReward + +- (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { + if (!(self = [self init])) { + return nil; + } + + _type = jsonDictionary[@"type"]; + _count = jsonDictionary[@"count"]; + _ext = jsonDictionary[@"ext"]; + + return self; +} + +- (PBMJsonDictionary *)toJsonDictionary { + PBMMutableJsonDictionary * const ret = [[PBMMutableJsonDictionary alloc] init]; + + ret[@"type"] = self.type; + ret[@"count"] = self.count; + ret[@"ext"] = self.ext; + + [ret pbmRemoveEmptyVals]; + + return ret; +} + +@end From 41ebbe195927db69f1808e0e09f52a0d645c6669 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Tue, 8 Oct 2024 14:33:28 +0300 Subject: [PATCH 07/18] feat: add rewarded endcard time test case --- .../Model/TestCasesManager.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift index 72106a742..d0a3c3c5f 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift @@ -2050,6 +2050,22 @@ struct TestCaseManager { setupCustomParams(for: rewardedAdController.prebidConfigId) }), + TestCase(title: "Video Rewarded Endcard Time 320x480 (In-App)", + tags: [.video, .inapp, .server], + exampleVCStoryboardID: "AdapterViewController", + configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { + return + } + + let rewardedAdController = PrebidRewardedController(rootController: adapterVC) + + rewardedAdController.prebidConfigId = "prebid-video-rewarded-endcard-time" + adapterVC.setup(adapter: rewardedAdController) + + setupCustomParams(for: rewardedAdController.prebidConfigId) + }), + // MARK: ---- Video Rewarded (GAM) ---- TestCase(title: "Video Rewarded 320x480 (GAM) [OK, Metadata]", From 8029d819497260fe8ba16745ba7672e5436d951d Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Tue, 8 Oct 2024 16:17:03 +0300 Subject: [PATCH 08/18] feat: implement reward behavior & add unit tests --- PrebidMobile.xcodeproj/project.pbxproj | 60 ++-- .../AdView/Modals/PBMModalViewController.h | 1 + .../AdView/Modals/PBMModalViewController.m | 21 +- .../AdTypes/AdView/PBMAdViewManager.m | 19 +- .../AdTypes/AdView/PBMAdViewManagerDelegate.h | 3 + .../AdTypes/AdView/PBMCloseActionManager.h | 32 +++ .../AdTypes/AdView/PBMCloseActionManager.m | 30 ++ .../AdTypes/AdView/PBMCreativeModel.h | 7 + .../AdTypes/AdView/PBMCreativeModel.m | 3 + .../AdTypes/AdView/PBMCreativeViewDelegate.h | 3 + .../AdTypes/AdView/PBMTrackingEvent.h | 5 +- .../AdTypes/AdView/PBMTrackingEvent.m | 69 +++++ .../AdTypes/AdView/PBMVideoCreative.h | 2 + .../AdTypes/AdView/PBMVideoCreative.m | 102 ++++++- .../AdTypes/AdView/PBMVideoView.h | 3 + .../AdTypes/AdView/PBMVideoView.m | 110 +++++++- .../AdTypes/AdView/PBMVideoViewDelegate.h | 2 + .../AdTypes/AdView/PBMWebView.h | 2 + .../AdTypes/AdView/PBMWebView.m | 18 +- .../AdTypes/AdView/PBMWebViewDelegate.h | 1 + .../AdTypes/PBMHTMLCreative.h | 1 + .../AdTypes/PBMHTMLCreative.m | 116 +++++++- .../InterstitialController.swift | 18 +- .../PBMCacheRenderers/PrebidRenderer.swift | 7 +- .../ORTB/Prebid/PBMORTBRewardedCompletion.m | 25 ++ .../Prebid/PBMCore/PBMSafariVCOpener.m | 44 +-- .../Utilities/BackgroundAwareTimer.swift | 103 +++++++ .../PrebidMobileTest-Bridging-Header.h | 2 + .../RenderingTests/Mocks/MockVideoView.swift | 26 ++ .../PBMVideoView+pbmTestExtension.h | 2 + .../Tests/CloseActionManagerTests.swift | 40 +++ .../Tests/PBMHTMLCreativeTest.swift | 230 +++++++++++++--- .../Tests/PBMHTMLCreativeTest_Base.swift | 2 + .../PBMHTMLCreativeTest_MRAIDClose.swift | 1 + .../Tests/PBMMRAIDControllerTest_Base.swift | 1 + .../Tests/PBMModalViewControllerTest.swift | 15 +- .../Tests/PBMVideoViewTest.swift | 260 ++++++++++++++++-- .../RenderingTests/Tests/PBMWebViewTest.swift | 2 + .../Tests/Prebid/PBMORTBTest.swift | 29 ++ .../PBMRewardedVideoViewTest.swift | 2 + .../PBMRewardedVideoCreativeTest.swift | 1 + .../VASTTests/PBMVideoCreativeTest.swift | 78 +++++- .../VASTTests/RewardedVideoEventsTest.swift | 1 + .../VASTTests/VastEventTrackingTest.swift | 4 +- .../Tests/VASTTests/VideoEventsTest.swift | 2 + .../Tests/VASTTests/VideoFileTypeTest.swift | 3 + 46 files changed, 1363 insertions(+), 145 deletions(-) create mode 100644 PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCloseActionManager.h create mode 100644 PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCloseActionManager.m create mode 100644 PrebidMobile/PrebidMobileRendering/Utilities/BackgroundAwareTimer.swift create mode 100644 PrebidMobileTests/RenderingTests/Mocks/MockVideoView.swift create mode 100644 PrebidMobileTests/RenderingTests/Tests/CloseActionManagerTests.swift diff --git a/PrebidMobile.xcodeproj/project.pbxproj b/PrebidMobile.xcodeproj/project.pbxproj index 84347c3a0..b1906de9d 100644 --- a/PrebidMobile.xcodeproj/project.pbxproj +++ b/PrebidMobile.xcodeproj/project.pbxproj @@ -93,6 +93,11 @@ 534C61392CB52A4E0026119A /* PBMORTBRewardedCompletion.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C61372CB52A4E0026119A /* PBMORTBRewardedCompletion.h */; settings = {ATTRIBUTES = (Public, ); }; }; 534C613A2CB52A4E0026119A /* PBMORTBRewardedCompletion.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61382CB52A4E0026119A /* PBMORTBRewardedCompletion.m */; }; 534C613C2CB536F00026119A /* RewardedConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C613B2CB536F00026119A /* RewardedConfig.swift */; }; + 534C613F2CB5504D0026119A /* PBMCloseActionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 534C613D2CB5504D0026119A /* PBMCloseActionManager.h */; }; + 534C61402CB5504D0026119A /* PBMCloseActionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C613E2CB5504D0026119A /* PBMCloseActionManager.m */; }; + 534C61422CB55D980026119A /* BackgroundAwareTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61412CB55D980026119A /* BackgroundAwareTimer.swift */; }; + 534C61442CB5619B0026119A /* MockVideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61432CB5619B0026119A /* MockVideoView.swift */; }; + 534C61462CB562E40026119A /* CloseActionManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61452CB562E40026119A /* CloseActionManagerTests.swift */; }; 5355ACA929C454070014F16E /* VAST_with_empty_companion.xml in Resources */ = {isa = PBXBuildFile; fileRef = 5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */; }; 5355ACAB29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */; }; 536A39262A84C50F00B1CCEA /* StringExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */; }; @@ -972,6 +977,11 @@ 534C61372CB52A4E0026119A /* PBMORTBRewardedCompletion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMORTBRewardedCompletion.h; sourceTree = ""; }; 534C61382CB52A4E0026119A /* PBMORTBRewardedCompletion.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PBMORTBRewardedCompletion.m; sourceTree = ""; }; 534C613B2CB536F00026119A /* RewardedConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardedConfig.swift; sourceTree = ""; }; + 534C613D2CB5504D0026119A /* PBMCloseActionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PBMCloseActionManager.h; sourceTree = ""; }; + 534C613E2CB5504D0026119A /* PBMCloseActionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PBMCloseActionManager.m; sourceTree = ""; }; + 534C61412CB55D980026119A /* BackgroundAwareTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundAwareTimer.swift; sourceTree = ""; }; + 534C61432CB5619B0026119A /* MockVideoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockVideoView.swift; sourceTree = ""; }; + 534C61452CB562E40026119A /* CloseActionManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseActionManagerTests.swift; sourceTree = ""; }; 5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = VAST_with_empty_companion.xml; sourceTree = ""; }; 5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreativeModelCollectionMakerVASTTests.swift; sourceTree = ""; }; 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensionsTest.swift; sourceTree = ""; }; @@ -1808,6 +1818,7 @@ 539D4C7129B5E23600B6B30E /* MockPBMAbstractCreative.swift */, 533FDF842A12030C0066ED5A /* MockPrebidJSLibraryManager.swift */, 53CE09022AD67ECE0018CB75 /* MockPBMBidRequester.swift */, + 534C61432CB5619B0026119A /* MockVideoView.swift */, ); path = Mocks; sourceTree = ""; @@ -2055,10 +2066,8 @@ 5BC37672271F1CFD00444D5E /* ORTB */ = { isa = PBXGroup; children = ( - 3CADBD222BFDDE01007B6913 /* PBMORTBRendererConfig.h */, - 3CADBD232BFDDE01007B6913 /* PBMORTBRendererConfig.m */, - 5BC3768C271F1CFD00444D5E /* PBMORTB_NotImplemented.h */, 5BC37682271F1CFD00444D5E /* PBMORTB.h */, + 5BC3768C271F1CFD00444D5E /* PBMORTB_NotImplemented.h */, 5BC37693271F1CFD00444D5E /* PBMORTBAbstract.h */, 5BC37674271F1CFD00444D5E /* PBMORTBAbstract.m */, 5BC37691271F1CFD00444D5E /* PBMORTBAbstract+Protected.h */, @@ -2066,6 +2075,8 @@ 5BC37680271F1CFD00444D5E /* PBMORTBApp.m */, 92AFE57C274FCD8200B0430C /* PBMORTBAppContent.h */, 92AFE57E274FCD9900B0430C /* PBMORTBAppContent.m */, + 799109FC28F99C7D004837B4 /* PBMORTBAppExt.h */, + 799109FA28F99C2B004837B4 /* PBMORTBAppExt.m */, 5BC37679271F1CFD00444D5E /* PBMORTBAppExtPrebid.h */, 5BC3768E271F1CFD00444D5E /* PBMORTBAppExtPrebid.m */, 5BC37673271F1CFD00444D5E /* PBMORTBBanner.h */, @@ -2108,6 +2119,8 @@ 5BC3769A271F1CFD00444D5E /* PBMORTBPublisher.m */, 5BC376A5271F1CFD00444D5E /* PBMORTBRegs.h */, 5BC3768A271F1CFD00444D5E /* PBMORTBRegs.m */, + 3CADBD222BFDDE01007B6913 /* PBMORTBRendererConfig.h */, + 3CADBD232BFDDE01007B6913 /* PBMORTBRendererConfig.m */, 5BC3767B271F1CFD00444D5E /* PBMORTBSource.h */, 5BC3769C271F1CFD00444D5E /* PBMORTBSource.m */, 5BC3768D271F1CFD00444D5E /* PBMORTBSourceExtOMID.h */, @@ -2116,8 +2129,6 @@ 5BC37678271F1CFD00444D5E /* PBMORTBUser.m */, 5BC3768B271F1CFD00444D5E /* PBMORTBVideo.h */, 5BC376A4271F1CFD00444D5E /* PBMORTBVideo.m */, - 799109FA28F99C2B004837B4 /* PBMORTBAppExt.m */, - 799109FC28F99C7D004837B4 /* PBMORTBAppExt.h */, ); path = ORTB; sourceTree = ""; @@ -2168,6 +2179,7 @@ 537B651D2833A3DA008AE9D1 /* Reachability.swift */, 537B653F2833C091008AE9D1 /* NetworkType.swift */, 5347473A2BFB4D3D00966658 /* UserAgentService.swift */, + 534C61412CB55D980026119A /* BackgroundAwareTimer.swift */, ); path = Utilities; sourceTree = ""; @@ -2225,14 +2237,14 @@ 5BC37701271F1CFE00444D5E /* AdTypes */ = { isa = PBXGroup; children = ( - 5BC37702271F1CFE00444D5E /* Video */, - 5BC37727271F1CFE00444D5E /* PBMHTMLFormatter.m */, - 5BC37728271F1CFE00444D5E /* PBMHTMLCreative.m */, - 5BC37729271F1CFE00444D5E /* PBMMRAIDCommand.h */, + 5BC3772D271F1CFE00444D5E /* AdView */, 5BC3772A271F1CFE00444D5E /* PBMHTMLCreative.h */, + 5BC37728271F1CFE00444D5E /* PBMHTMLCreative.m */, 5BC3772B271F1CFE00444D5E /* PBMHTMLFormatter.h */, + 5BC37727271F1CFE00444D5E /* PBMHTMLFormatter.m */, + 5BC37729271F1CFE00444D5E /* PBMMRAIDCommand.h */, 5BC3772C271F1CFE00444D5E /* PBMMRAIDCommand.m */, - 5BC3772D271F1CFE00444D5E /* AdView */, + 5BC37702271F1CFE00444D5E /* Video */, ); path = AdTypes; sourceTree = ""; @@ -2309,6 +2321,8 @@ 5BC3773F271F1CFE00444D5E /* PBMAdViewManagerDelegate.h */, 5BC3775D271F1CFE00444D5E /* PBMAutoRefreshManager.h */, 5BC37775271F1CFE00444D5E /* PBMAutoRefreshManager.m */, + 534C613D2CB5504D0026119A /* PBMCloseActionManager.h */, + 534C613E2CB5504D0026119A /* PBMCloseActionManager.m */, 5BC37767271F1CFE00444D5E /* PBMCreativeModel.h */, 5BC3773A271F1CFE00444D5E /* PBMCreativeModel.m */, 5BC37733271F1CFE00444D5E /* PBMCreativeModelCollectionMakerVAST.h */, @@ -2340,8 +2354,8 @@ 5BC37782271F1CFE00444D5E /* PBMWKNavigationActionCompatible.h */, 5BC3776F271F1CFE00444D5E /* PBMWKWebViewCompatible.h */, 92EE5A0C27F9D292003D7691 /* Position.swift */, - 5BC3777F271F1CFE00444D5E /* WKWebView+PBMWKWebViewCompatible.h */, 9247FEFD2808175E00ACD84A /* VideoControlsConfiguration.swift */, + 5BC3777F271F1CFE00444D5E /* WKWebView+PBMWKWebViewCompatible.h */, ); path = AdView; sourceTree = ""; @@ -2349,20 +2363,20 @@ 5BC37745271F1CFE00444D5E /* Modals */ = { isa = PBXGroup; children = ( - 5BC37746271F1CFE00444D5E /* PBMModalViewController.h */, - 5BC37747271F1CFE00444D5E /* PBMDeferredModalState.h */, - 5BC37748271F1CFE00444D5E /* PBMModalViewController+Private.h */, 5BC37749271F1CFE00444D5E /* ModalAnimator */, - 5BC37750271F1CFE00444D5E /* PBMModalManagerDelegate.h */, - 5BC37751271F1CFE00444D5E /* PBMNonModalViewController.m */, + 5BC37747271F1CFE00444D5E /* PBMDeferredModalState.h */, + 5BC37754271F1CFE00444D5E /* PBMDeferredModalState.m */, 5BC37752271F1CFE00444D5E /* PBMModalManager.h */, + 5BC37759271F1CFE00444D5E /* PBMModalManager.m */, + 5BC37750271F1CFE00444D5E /* PBMModalManagerDelegate.h */, + 5BC37758271F1CFE00444D5E /* PBMModalState.h */, 5BC37753271F1CFE00444D5E /* PBMModalState.m */, - 5BC37754271F1CFE00444D5E /* PBMDeferredModalState.m */, + 5BC37746271F1CFE00444D5E /* PBMModalViewController.h */, 5BC37755271F1CFE00444D5E /* PBMModalViewController.m */, - 5BC37756271F1CFE00444D5E /* PBMNonModalViewController.h */, + 5BC37748271F1CFE00444D5E /* PBMModalViewController+Private.h */, 5BC37757271F1CFE00444D5E /* PBMModalViewControllerDelegate.h */, - 5BC37758271F1CFE00444D5E /* PBMModalState.h */, - 5BC37759271F1CFE00444D5E /* PBMModalManager.m */, + 5BC37756271F1CFE00444D5E /* PBMNonModalViewController.h */, + 5BC37751271F1CFE00444D5E /* PBMNonModalViewController.m */, ); path = Modals; sourceTree = ""; @@ -2928,6 +2942,7 @@ 539D4C6F29B5DDFD00B6B30E /* SafariOpenerTests.swift */, 53B221D22A0E3DA900C91CCB /* PrebidJSLibraryManagerTests.swift */, 53138B2D2A713A7800B18B5C /* PrebidGAMVersionCheckerTest.swift */, + 534C61452CB562E40026119A /* CloseActionManagerTests.swift */, ); path = Tests; sourceTree = ""; @@ -3468,6 +3483,7 @@ 5BC3790F271F1CFF00444D5E /* PBMDeviceAccessManager.h in Headers */, 53A657B12A8B650900AE0B4F /* PBMORTBSDKConfiguration.h in Headers */, 5BC379CA271F1D0000444D5E /* PBMTransaction.h in Headers */, + 534C613F2CB5504D0026119A /* PBMCloseActionManager.h in Headers */, 5BC379F5271F1D0000444D5E /* PBMTrackingURLVisitors.h in Headers */, 5BC378E3271F1CFF00444D5E /* PBMORTBImp.h in Headers */, 5BC37A18271F1D0000444D5E /* PBMViewControllerProvider.h in Headers */, @@ -3865,6 +3881,7 @@ 925D5E662737F47500A8A2B5 /* PBMVastLoaderCheckForAds.swift in Sources */, 929638BD27AB20FB00D30F3D /* NativeDataTests.swift in Sources */, 925D5D762737B85400A8A2B5 /* PBMVastCreativeCompanionAdsTest.swift in Sources */, + 534C61462CB562E40026119A /* CloseActionManagerTests.swift in Sources */, 925D5E222737EA1E00A8A2B5 /* MediationBannerAdUnitTest.swift in Sources */, 925D5E6C2737F4DF00A8A2B5 /* PBMVastLoaderTestOMVerificationOneInline.swift in Sources */, 925D5D912737C0A300A8A2B5 /* PBMUIViewTests.swift in Sources */, @@ -3915,6 +3932,7 @@ 606FAC4A2201F248008EAE5E /* AdUnitTests.swift in Sources */, 922AFD712737335C00732C53 /* PBMRewardedVideoCreativeTestCloseDelay.swift in Sources */, FAEBF2A2237ECFEF006BA972 /* StorageUtilsTests.swift in Sources */, + 534C61442CB5619B0026119A /* MockVideoView.swift in Sources */, 922AFD65273730FB00732C53 /* PBMMRAIDControllerTest_Base.swift in Sources */, 922AFD1A27371BCF00732C53 /* PBMCircularProgressBarLayerTests.swift in Sources */, 925D5DAB2737C4F600A8A2B5 /* PBMAdLoadFlowControllerTest.swift in Sources */, @@ -4169,6 +4187,7 @@ 53A447D12CAECA3C008DE6C0 /* BaseRewardedAdUnit.swift in Sources */, 92EE5A0D27F9D292003D7691 /* Position.swift in Sources */, 92C3A83627F989E200DC05E9 /* AutoRefreshCountConfig.swift in Sources */, + 534C61402CB5504D0026119A /* PBMCloseActionManager.m in Sources */, 5BC37A72271F1D0000444D5E /* BidResponse.swift in Sources */, 5BC379C8271F1D0000444D5E /* PBMAutoRefreshManager.m in Sources */, 5BC37950271F1D0000444D5E /* PBMCreativeFactory.m in Sources */, @@ -4339,6 +4358,7 @@ 5BC37913271F1CFF00444D5E /* PBMDownloadDataHelper.m in Sources */, 5BC378BE271F1CFF00444D5E /* NSMutableDictionary+PBMExtensions.m in Sources */, FAEE4D17262DC2B200AD9966 /* NativeRequest.swift in Sources */, + 534C61422CB55D980026119A /* BackgroundAwareTimer.swift in Sources */, 5BC37ACA271F1D0100444D5E /* PBMNetworkParameterBuilder.m in Sources */, 5BC378F1271F1CFF00444D5E /* PBMORTBDeviceExtPrebid.m in Sources */, 5BC37AA6271F1D0000444D5E /* MediationBidInfoWrapper.swift in Sources */, diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.h index 1729da0b2..aed0f987f 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.h @@ -22,6 +22,7 @@ @class PBMModalManager; @class PBMOpenMeasurementSession; @class PBMInterstitialDisplayProperties; +@class PBMCloseActionManager; @interface PBMModalViewController : UIViewController diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m index 692189676..568759b7f 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m @@ -20,9 +20,9 @@ #import "PBMOpenMeasurementSession.h" #import "PBMFunctions+Private.h" #import "UIView+PBMExtensions.h" -#import "PBMMacros.h" #import "PBMModalManager.h" #import "PBMWebView.h" +#import "PBMCloseActionManager.h" #import "PrebidMobileSwiftHeaders.h" #if __has_include("PrebidMobile-Swift.h") @@ -261,7 +261,24 @@ - (void)setupCloseButtonVisibility { - (void)creativeDisplayCompleted:(PBMAbstractCreative *)creative { if (self.modalState.adConfiguration.isRewarded) { - self.closeButtonDecorator.button.hidden = NO; + PBMRewardedConfig * rewardedConfig = creative.creativeModel.adConfiguration.rewardedConfig; + + NSString * ortbAction = rewardedConfig.closeAction ?: @""; + + PBMCloseAction action = [PBMCloseActionManager getActionWithDescription:ortbAction]; + + switch(action){ + case PBMCloseActionCloseButton: + self.closeButtonDecorator.button.hidden = NO; + break; + case PBMCloseActionAutoClose: + [self.modalViewControllerDelegate modalViewControllerCloseButtonTapped:self]; + break; + case PBMCloseActionUnknown: + // By default SDK should show close button + self.closeButtonDecorator.button.hidden = NO; + PBMLogWarn(@"SDK met unknown close action.") + } } } diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManager.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManager.m index 1de3674a8..69533b650 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManager.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManager.m @@ -209,13 +209,7 @@ - (void)creativeWasClicked:(PBMAbstractCreative *)creative { } - (void)creativeInterstitialDidClose:(PBMAbstractCreative *) creative { - if (self.adConfiguration.isRewarded) { - // In Rewarded Video, the Video remains on the screen with the last frame showing. - // Cleaning up here when the Interstial is closed.; - if (self.currentCreative.view && self.currentCreative.view.superview) { - [self.currentCreative.view removeFromSuperview]; - } - } else if (self.adConfiguration.winningBidAdFormat == AdFormat.video) { + if (self.adConfiguration.winningBidAdFormat == AdFormat.video) { self.videoInterstitialDidClose = YES; } @@ -282,6 +276,13 @@ - (void)creativeFullScreenDidFinish:(PBMAbstractCreative *)creative { [self.adViewManagerDelegate adDidClose]; } +/// NOTE: Rewarded API only +- (void)creativeDidSendRewardedEvent:(PBMAbstractCreative *)creative { + if (self.isInterstitial && self.isRewarded) { + [self.adViewManagerDelegate adDidSendRewardedEvent]; + } +} + #pragma mark - Utility Functions - (PBMTransaction *)currentTransaction { @@ -292,6 +293,10 @@ - (BOOL)isInterstitial { return self.adConfiguration.presentAsInterstitial; } +- (BOOL)isRewarded { + return self.adConfiguration.isRewarded; +} + //Do not load an ad if the current one is "opened" //Is the current creative an PBMHTMLCreative? If so, is a clickthrough browser visible/MRAID in Expanded mode? - (BOOL)isCreativeOpened { diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManagerDelegate.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManagerDelegate.h index e15262cd0..faf438aa6 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManagerDelegate.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMAdViewManagerDelegate.h @@ -62,6 +62,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)videoAdWasMuted; - (void)videoAdWasUnmuted; +// Used only for rewarded API +- (void)adDidSendRewardedEvent; + @end NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCloseActionManager.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCloseActionManager.h new file mode 100644 index 000000000..5145a89c4 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCloseActionManager.h @@ -0,0 +1,32 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, PBMCloseAction) { + PBMCloseActionCloseButton = 0, + PBMCloseActionAutoClose, + PBMCloseActionUnknown, +}; + +@interface PBMCloseActionManager : NSObject + ++ (PBMCloseAction)getActionWithDescription:(NSString * _Nonnull)description; + +@end + +NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCloseActionManager.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCloseActionManager.m new file mode 100644 index 000000000..35c99c721 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCloseActionManager.m @@ -0,0 +1,30 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "PBMCloseActionManager.h" + +@implementation PBMCloseActionManager + ++ (PBMCloseAction)getActionWithDescription:(NSString * _Nonnull)description { + if ([description isEqualToString:@"closebutton"]) { + return PBMCloseActionCloseButton; + } else if ([description isEqualToString:@"autoclose"]) { + return PBMCloseActionAutoClose; + } else { + return PBMCloseActionUnknown; + } +} + +@end diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeModel.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeModel.h index 98240296a..289edb18d 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeModel.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeModel.h @@ -55,6 +55,13 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) BOOL isCompanionAd; @property (atomic, assign) bool hasCompanionAd; +// NOTE: for rewarded ads only +@property (nonatomic, assign) BOOL userHasEarnedReward; +@property (nonatomic, assign) BOOL userPostRewardEventSent; + +@property (nonatomic, strong, nullable) NSNumber * rewardTime; +@property (nonatomic, strong, nullable) NSNumber * postRewardTime; + - (instancetype)initWithAdConfiguration:(nonnull PBMAdConfiguration *)adConfiguration; @end diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeModel.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeModel.m index c3ef15e68..b547de476 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeModel.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeModel.m @@ -35,6 +35,9 @@ -(instancetype)initWithAdConfiguration:(PBMAdConfiguration *)adConfiguration { self.trackingURLs = [NSDictionary new]; self.adConfiguration = adConfiguration; + + self.userHasEarnedReward = NO; + self.userPostRewardEventSent = NO; } return self; diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeViewDelegate.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeViewDelegate.h index 1f3bb6909..db8930c23 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeViewDelegate.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMCreativeViewDelegate.h @@ -26,6 +26,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)creativeInterstitialDidLeaveApp:(PBMAbstractCreative *)creative; - (void)creativeFullScreenDidFinish:(PBMAbstractCreative *)creative; +// Rewarded Ad Only +- (void)creativeDidSendRewardedEvent:(PBMAbstractCreative *)creative; + // MRAID Only - (void)creativeReadyToReimplant:(PBMAbstractCreative *)creative; - (void)creativeMraidDidCollapse:(PBMAbstractCreative *)creative; diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMTrackingEvent.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMTrackingEvent.h index 0c995ab79..6ab0f3c4b 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMTrackingEvent.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMTrackingEvent.h @@ -53,7 +53,9 @@ typedef NS_ENUM(NSInteger, PBMTrackingEvent) { PBMTrackingEventLoaded, - PBMTrackingEventPrebidWin + PBMTrackingEventPrebidWin, + + PBMTrackingEventUnknown }; @@ -61,6 +63,7 @@ NS_ASSUME_NONNULL_BEGIN @interface PBMTrackingEventDescription : NSObject + (NSString *)getDescription:(PBMTrackingEvent)event; ++ (PBMTrackingEvent)getEventWith:(NSString *)description; @end NS_ASSUME_NONNULL_END diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMTrackingEvent.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMTrackingEvent.m index 2f7027fdb..b44e6ad4e 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMTrackingEvent.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMTrackingEvent.m @@ -48,7 +48,76 @@ + (NSString *)getDescription:(PBMTrackingEvent)event { case PBMTrackingEventAcceptInvitation : return @"acceptInvitation"; case PBMTrackingEventLoaded : return @"loaded"; case PBMTrackingEventPrebidWin : return @"prebid_Win"; + case PBMTrackingEventUnknown : return @"unknown"; } } ++ (PBMTrackingEvent)getEventWith:(NSString *)description { + PBMTrackingEvent event; + + if ([description isEqualToString:@"creativeModelTrackingKey_Request"]) { + event = PBMTrackingEventRequest; + } else if ([description isEqualToString:@"creativeModelTrackingKey_Impression"]) { + event = PBMTrackingEventImpression; + } else if ([description isEqualToString:@"creativeModelTrackingKey_Click"]) { + event = PBMTrackingEventClick; + } else if ([description isEqualToString:@"creativeModelTrackingKey_OverlayClick"]) { + event = PBMTrackingEventOverlayClick; + } else if ([description isEqualToString:@"creativeModelTrackingKey_CompanionClick"]) { + event = PBMTrackingEventCompanionClick; + } else if ([description isEqualToString:@"creativeModelTrackingKey_Play"]) { + event = PBMTrackingEventPlay; + } else if ([description isEqualToString:@"pause"]) { + event = PBMTrackingEventPause; + } else if ([description isEqualToString:@"rewind"]) { + event = PBMTrackingEventRewind; + } else if ([description isEqualToString:@"resume"]) { + event = PBMTrackingEventResume; + } else if ([description isEqualToString:@"creativeModelTrackingKey_Skip"]) { + event = PBMTrackingEventSkip; + } else if ([description isEqualToString:@"creativeView"]) { + event = PBMTrackingEventCreativeView; + } else if ([description isEqualToString:@"start"]) { + event = PBMTrackingEventStart; + } else if ([description isEqualToString:@"firstquartile"]) { + event = PBMTrackingEventFirstQuartile; + } else if ([description isEqualToString:@"midpoint"]) { + event = PBMTrackingEventMidpoint; + } else if ([description isEqualToString:@"thirdquartile"]) { + event = PBMTrackingEventThirdQuartile; + } else if ([description isEqualToString:@"complete"]) { + event = PBMTrackingEventComplete; + } else if ([description isEqualToString:@"mute"]) { + event = PBMTrackingEventMute; + } else if ([description isEqualToString:@"unmute"]) { + event = PBMTrackingEventUnmute; + } else if ([description isEqualToString:@"fullscreen"]) { + event = PBMTrackingEventFullscreen; + } else if ([description isEqualToString:@"creativeModelTrackingKey_ExitFullscreen"]) { + event = PBMTrackingEventExitFullscreen; + } else if ([description isEqualToString:@"normal"]) { + event = PBMTrackingEventNormal; + } else if ([description isEqualToString:@"expand"]) { + event = PBMTrackingEventExpand; + } else if ([description isEqualToString:@"collapse"]) { + event = PBMTrackingEventCollapse; + } else if ([description isEqualToString:@"close"]) { + event = PBMTrackingEventCloseLinear; + } else if ([description isEqualToString:@"creativeModelTrackingKey_CloseOverlay"]) { + event = PBMTrackingEventCloseOverlay; + } else if ([description isEqualToString:@"creativeModelTrackingKey_Error"]) { + event = PBMTrackingEventError; + } else if ([description isEqualToString:@"acceptInvitation"]) { + event = PBMTrackingEventAcceptInvitation; + } else if ([description isEqualToString:@"loaded"]) { + event = PBMTrackingEventLoaded; + } else if ([description isEqualToString:@"prebid_Win"]) { + event = PBMTrackingEventPrebidWin; + } else { + event = PBMTrackingEventUnknown; + } + + return event; +} + @end diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.h index 295fb421d..6bbd9cacf 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.h @@ -17,6 +17,8 @@ #import "PBMAbstractCreative.h" #import "PBMVideoViewDelegate.h" +@class PBMRewardedConfig; + @interface PBMVideoCreative : PBMAbstractCreative @property (class, readonly) NSInteger maxSizeForPreRenderContent; diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.m index c163eedd3..b770e161b 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoCreative.m @@ -48,6 +48,7 @@ @interface PBMVideoCreative () @property (nonatomic, strong) PBMVideoView *videoView; @property (nonatomic, strong) NSData *data; +@property (nonatomic, strong) PBMRewardedConfig *rewardedConfig; @end @@ -76,6 +77,10 @@ - (instancetype)initWithCreativeModel:(PBMCreativeModel *)creativeModel self.videoView = [[PBMVideoView alloc] initWithCreative:self]; self.videoView.videoViewDelegate = self; self.view = self.videoView; + + self.rewardedConfig = self.creativeModel.adConfiguration.rewardedConfig; + self.creativeModel.rewardTime = [self calculateRewardTime]; + self.creativeModel.postRewardTime = [self calculatePostRewardTimeWith:self.creativeModel.rewardTime]; } return self; @@ -220,6 +225,42 @@ - (void)learnMoreWasClicked { }]; } +- (void)videoViewCurrentPlayingTime:(NSNumber *)currentPlayingTime { + // NOTE: Rewarded API only + // Signal to the application that the user has earned the reward after + // the certain period of time that the ad is on the screen. + if (!self.creativeModel.adConfiguration.isRewarded) { + return; + } + + // NOTE: This logic apllicable only to the creatives without endcard. + if (self.creativeModel.hasCompanionAd) { + return; + } + + // Try track reward event + if (!self.creativeModel.userHasEarnedReward && + [self.creativeModel.rewardTime doubleValue] >= 0 && + [currentPlayingTime doubleValue] >= [self.creativeModel.rewardTime doubleValue]) { + + self.creativeModel.userHasEarnedReward = YES; + [self.creativeViewDelegate creativeDidSendRewardedEvent:self]; + + // The SDK shows the Learn More button only when the reward clause is met. + self.videoView.showLearnMore = YES; + [self.videoView updateLearnMoreButton]; + } + + // Try track post-reward event + if(!self.creativeModel.userPostRewardEventSent && + [self.creativeModel.postRewardTime doubleValue] >= 0 && + [currentPlayingTime doubleValue] >= [self.creativeModel.postRewardTime doubleValue]) { + + self.creativeModel.userPostRewardEventSent = YES; + [self.modalManager creativeDisplayCompleted:self]; + } +} + - (void)videoViewWasTapped { if (self.creativeModel.adConfiguration.clickHandlerOverride != nil) { [self.eventManager trackEvent:PBMTrackingEventClick]; @@ -288,7 +329,7 @@ - (PBMInterstitialDisplayProperties *)createInterstitialPropertiesForCurrentVide // TODO: - Clarify the requirements and fix calculation logic - (NSTimeInterval)calculateCloseDelayForPubCloseDelay:(NSTimeInterval)pubCloseDelay { - if (self.creativeModel.adConfiguration.isRewarded || self.creativeModel.hasCompanionAd) { + if (self.creativeModel.hasCompanionAd) { return [self.creativeModel.displayDurationInSeconds doubleValue]; } else if (self.creativeModel.adConfiguration.videoControlsConfig.skipDelay && self.creativeModel.adConfiguration.videoControlsConfig.skipDelay <= self.creativeModel.displayDurationInSeconds.doubleValue) { return self.creativeModel.adConfiguration.videoControlsConfig.skipDelay; @@ -308,4 +349,63 @@ - (NSTimeInterval)calculateCloseDelayForPubCloseDelay:(NSTimeInterval)pubCloseDe } } +- (NSNumber *)calculateRewardTime { + if (!self.creativeModel.adConfiguration.isRewarded) { + return @-1; + } + + NSString * ortbPlaybackevent = self.rewardedConfig.videoPlaybackevent; + NSNumber * ortbVideoTime = self.rewardedConfig.videoTime; + + // If both complition criteria are missing (playbackevent and time) - use default configuration + if (!ortbPlaybackevent && !ortbVideoTime) { + ortbPlaybackevent = self.rewardedConfig.defaultVideoPlaybackEvent; + } + + CGFloat videoDuration = [self.creativeModel.displayDurationInSeconds doubleValue]; + + // If completion criteria is playback event + if (ortbPlaybackevent) { + PBMTrackingEvent event = [PBMTrackingEventDescription getEventWith:ortbPlaybackevent]; + + switch(event) { + case PBMTrackingEventStart: + return @0; + case PBMTrackingEventFirstQuartile: + return @(0.25 * videoDuration); + case PBMTrackingEventMidpoint: + return @(0.5 * videoDuration); + case PBMTrackingEventThirdQuartile: + return @(0.75 * videoDuration); + case PBMTrackingEventComplete: + return @(videoDuration); + default: + return @(videoDuration); + } + } + + // If completion criteria is time and if 0 <= completion.video.time <= videoDuration + if (ortbVideoTime && [ortbVideoTime doubleValue] >= 0 && [ortbVideoTime doubleValue] <= videoDuration) { + double rewardTime = [ortbVideoTime doubleValue]; + return [NSNumber numberWithDouble:rewardTime]; + } + + // Return video duration by default + return @(videoDuration); +} + +- (NSNumber *)calculatePostRewardTimeWith:(NSNumber *)calculatedRewardTime { + NSNumber * checkedRewardTime = (!calculatedRewardTime || [calculatedRewardTime doubleValue] < 0.0) + ? @0.0 : calculatedRewardTime; + + NSNumber * ortbPostrewardedTime = self.rewardedConfig.postRewardTime; + NSNumber * checkedPostrewardedTime = (!ortbPostrewardedTime || [ortbPostrewardedTime doubleValue] < 0.0) + ? @0.0 : ortbPostrewardedTime; + + NSNumber * postRewardTime = [NSNumber numberWithDouble: + [checkedRewardTime doubleValue] + [checkedPostrewardedTime doubleValue]]; + + return postRewardTime; +} + @end diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.h index d6426e47d..54952af5d 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.h @@ -34,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, nullable) PBMCircularProgressBarView *progressBar; @property (nonatomic, assign, getter=isMuted) BOOL muted; +@property (nonatomic, assign) BOOL showLearnMore; // Indicates that video reached the VAST Duration // We must use this flag instead of player’s state to prevent double-stopping of the video due to async work of observers. @@ -45,6 +46,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithCreative:(PBMVideoCreative *)creative; +- (void)updateLearnMoreButton; + - (void)showMediaFileURL:(NSURL *)mediaFileURL preloadedData:(NSData *)preloadedData; - (void)startPlayback; diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m index 4a1543101..a2562176e 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m @@ -54,7 +54,6 @@ @interface PBMVideoView () @property (nonatomic, weak) PBMVideoCreative *creative; @property (nonatomic, strong) PBMEventManager *eventManager; @property (nonatomic, strong) PBMTouchDownRecognizer *tapdownGestureRecognizer; -@property (nonatomic, assign) BOOL showLearnMore; #pragma mark UI @@ -85,6 +84,10 @@ @interface PBMVideoView () @property (nonatomic, assign) BOOL isPlaybackStarted; @property (nonatomic, assign) BOOL isPlaybackFinished; +@property (nonatomic, strong, nonnull) NSNumber * progressBarDuration; + +- (NSNumber *)calculateProgressBarDuration; + @end #pragma mark - Implementation @@ -107,12 +110,17 @@ - (void)setAvPlayer:(AVPlayer *)avPlayer { layer.player = avPlayer; } +- (PBMAdConfiguration *)adConfiguration { + return self.creative.creativeModel.adConfiguration; +} + #pragma mark - Initialization - (instancetype)initWithEventManager:(PBMEventManager *)eventManager { self = [super init]; if (self) { [self setupWithEventManager:eventManager]; + self.progressBarDuration = [self calculateProgressBarDuration]; } return self; @@ -157,7 +165,7 @@ - (void)setupWithEventManager:(PBMEventManager *)eventManager { self.accessibilityIdentifier = @"PBMVideoView"; if (!self.creative.creativeModel.adConfiguration.isInterstitialAd || - (self.creative.creativeModel.adConfiguration.isRewarded && !self.creative.creativeModel.hasCompanionAd)) { + (!self.creative.creativeModel.adConfiguration.isRewarded)) { [self setupTapRecognizer]; } @@ -197,6 +205,7 @@ - (void)showMediaFileURL:(NSURL *)mediaFileURL preloadedData:(NSData *)preloaded } - (void)updateControls { + [self updateLearnMoreButtonVisibility]; [self updateLearnMoreButton]; [self resetMuteControls]; @@ -339,7 +348,6 @@ - (void)updateLearnMoreButton { [self.btnLearnMore removeFromSuperview]; } - [self updateLearnMoreButtonVisibility]; if (!self.showLearnMore) { return; } @@ -493,7 +501,9 @@ - (void)handleSkipDelay:(NSTimeInterval)skipDelay videoDuration:(NSTimeInterval) return; } - if (!self.creative.creativeModel.hasCompanionAd || self.creative.creativeModel.adConfiguration.isRewarded || self.creative.creativeModel.adConfiguration.isBuiltInVideo) { + if (!self.creative.creativeModel.hasCompanionAd || + self.creative.creativeModel.adConfiguration.isRewarded || + self.creative.creativeModel.adConfiguration.isBuiltInVideo) { return; } @@ -616,7 +626,8 @@ - (void)startPlayback { [self.avPlayer play]; - [self handleSkipDelay:self.creative.creativeModel.adConfiguration.videoControlsConfig.skipDelay videoDuration:self.creative.creativeModel.displayDurationInSeconds.doubleValue]; + [self handleSkipDelay:self.adConfiguration.videoControlsConfig.skipDelay + videoDuration:self.creative.creativeModel.displayDurationInSeconds.doubleValue]; if (!self.isPlaybackStarted) { self.isPlaybackStarted = YES; @@ -638,8 +649,8 @@ - (void)initTimeObserver { }]; } - if (self.creative.creativeModel.adConfiguration.isRewarded) { - self.progressBar.duration = [self requiredVideoDuration]; + if (self.adConfiguration.isRewarded) { + self.progressBar.duration = [self.progressBarDuration doubleValue]; } } @@ -759,13 +770,13 @@ - (void)completeVideoViewDisplayWith:(PBMTrackingEvent)trackingEvent { [self.videoViewDelegate videoViewCompletedDisplay]; - if (self.creative.creativeModel.adConfiguration.isRewarded) { + if (self.adConfiguration.isRewarded) { self.progressBar.hidden = YES; } - if (self.creative.creativeModel.adConfiguration.isBuiltInVideo && !self.creative.creativeModel.hasCompanionAd) { + if (self.adConfiguration.isBuiltInVideo && !self.creative.creativeModel.hasCompanionAd) { // UI: need to give some time to hide the interstitial before showing the Watch Again - if (self.creative.creativeModel.adConfiguration.presentAsInterstitial) { + if (self.adConfiguration.presentAsInterstitial) { @weakify(self); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ @strongify(self); @@ -827,12 +838,22 @@ - (CGFloat)handlePeriodicTimeEvent { } CGFloat playingTime = CMTimeGetSeconds(currentTime); - CGFloat remainingTime = [self requiredVideoDuration] - playingTime; + CGFloat remainingTime = [self.progressBarDuration doubleValue] - playingTime; if (self.creative.creativeModel.adConfiguration.isRewarded) { - [self.progressBar updateProgress:remainingTime]; + + // Update progress bar + if(remainingTime >= 0) { + [self.progressBar updateProgress:remainingTime]; + } else { + if (self.progressBar.superview) { + [self.progressBar removeFromSuperview]; + } + } } + [self.videoViewDelegate videoViewCurrentPlayingTime:[NSNumber numberWithDouble:playingTime]]; + [self stopAdIfNeeded]; return remainingTime; @@ -1002,4 +1023,69 @@ - (void)recordTapEvent:(UITapGestureRecognizer *)tap { } } +- (NSNumber *)calculateProgressBarDuration { + // Get video duration + CGFloat videoDuration = [self requiredVideoDuration]; + + // If creative is not rewarded or has companion ad - return video duration. + if (!self.creative.creativeModel.adConfiguration.isRewarded || + self.creative.creativeModel.hasCompanionAd) { + return [NSNumber numberWithDouble:videoDuration]; + } + + PBMRewardedConfig * rewardedConfig = self.creative.creativeModel.adConfiguration.rewardedConfig; + + NSString * ortbPlaybackevent = rewardedConfig.videoPlaybackevent; + NSNumber * ortbVideoTime = rewardedConfig.videoTime; + NSNumber * ortbPostrewardedTime = rewardedConfig.postRewardTime ?: 0; + + // If both completion criteria are missing (playbackevent and time) - use default configuration + if (!ortbPlaybackevent && !ortbVideoTime) { + ortbPlaybackevent = rewardedConfig.defaultVideoPlaybackEvent; + } + + double progressBarDuration = ([ortbPostrewardedTime doubleValue] >= 0) ? [ortbPostrewardedTime doubleValue] : 0.0; + + // If completion criteria is playback event + if (ortbPlaybackevent) { + PBMTrackingEvent event = [PBMTrackingEventDescription getEventWith:ortbPlaybackevent]; + + switch(event) { + case PBMTrackingEventStart: + break; + case PBMTrackingEventFirstQuartile: + progressBarDuration += 0.25 * videoDuration; + break; + case PBMTrackingEventMidpoint: + progressBarDuration += 0.5 * videoDuration; + break; + case PBMTrackingEventThirdQuartile: + progressBarDuration += 0.75 * videoDuration; + break; + case PBMTrackingEventComplete: + progressBarDuration = videoDuration; + break; + default: + break; + } + + // if calculated value is bigger than video duration => return video duration + return (progressBarDuration > videoDuration) ? [NSNumber numberWithDouble:videoDuration] : + [NSNumber numberWithDouble:progressBarDuration]; + } + + // If completion criteria is time + if (ortbVideoTime && [ortbVideoTime doubleValue] >= 0.0) { + progressBarDuration += [ortbVideoTime doubleValue]; + + // if calculated value is bigger than video duration => return video duration + return (progressBarDuration > videoDuration) ? [NSNumber numberWithDouble:videoDuration] : + [NSNumber numberWithDouble:progressBarDuration]; + } + + // Return video duration by default + return [NSNumber numberWithDouble:[self requiredVideoDuration]]; +} + + @end diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoViewDelegate.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoViewDelegate.h index ee67f0edd..9a621b495 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoViewDelegate.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoViewDelegate.h @@ -25,6 +25,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)videoViewCompletedDisplay; - (void)videoViewWasTapped; +- (void)videoViewCurrentPlayingTime:(NSNumber *)currentPlayingTime; + - (void)learnMoreWasClicked; @end diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.h index b32ecb0b9..c57266ba9 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.h @@ -61,6 +61,8 @@ typedef NS_ENUM(NSInteger, PBMWebViewState) { @property (nonatomic, assign) BOOL isMRAID; @property (nonatomic, assign, getter=isRotationEnabled) BOOL rotationEnabled; +@property (nonatomic, strong, nullable) NSString *rewardedAdURL; + #pragma mark - Initialization - (instancetype)initWithFrame:(CGRect)frame; diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.m index 1f260c9f3..586e1fad2 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.m @@ -287,7 +287,8 @@ - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfigurat #pragma mark - WKNavigationDelegate -- (void) webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { +- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction + decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { //If there's no URL, bail NSURL *url = navigationAction.request.URL; @@ -309,6 +310,21 @@ - (void) webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigat decisionHandler(WKNavigationActionPolicyCancel); return; } + + //Identify and process Rewarded events + if (self.rewardedAdURL) { + if ([url.absoluteString isEqualToString:self.rewardedAdURL]) { + @weakify(self); + dispatch_async(dispatch_get_main_queue(), ^{ + @strongify(self); + if (!self) { return; } + [self.delegate webView:self receivedRewardedEventLink:url]; + }); + + decisionHandler(WKNavigationActionPolicyCancel); + return; + } + } //If this is the first URL, allow it. if (self.state == PBMWebViewStateLoading) { diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebViewDelegate.h b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebViewDelegate.h index b7cf33d44..65ae0a72c 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebViewDelegate.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebViewDelegate.h @@ -23,6 +23,7 @@ - (void)webView:(nonnull PBMWebView *)webView failedToLoadWithError:(nonnull NSError *)error; - (void)webView:(nonnull PBMWebView *)webView receivedClickthroughLink:(nonnull NSURL *)url; - (void)webView:(nonnull PBMWebView *)webView receivedMRAIDLink:(nonnull NSURL *)url; +- (void)webView:(nonnull PBMWebView *)webView receivedRewardedEventLink:(nonnull NSURL *)url; @end diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/PBMHTMLCreative.h b/PrebidMobile/PrebidMobileRendering/AdTypes/PBMHTMLCreative.h index be1fce218..af493988d 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/PBMHTMLCreative.h +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/PBMHTMLCreative.h @@ -19,6 +19,7 @@ #import "PBMCreativeFactory.h" @class PBMMRAIDResizeProperties; +@class PBMBackgroundAwareTimer; @interface PBMHTMLCreative : PBMAbstractCreative diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/PBMHTMLCreative.m b/PrebidMobile/PrebidMobileRendering/AdTypes/PBMHTMLCreative.m index afc316c40..a5cc9da7d 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/PBMHTMLCreative.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/PBMHTMLCreative.m @@ -63,6 +63,9 @@ @interface PBMHTMLCreative() @property (nonatomic, strong) Prebid *sdkConfiguration; @property (nonatomic, strong) PBMMRAIDController *MRAIDController; +@property (nonatomic, strong) PBMRewardedConfig *rewardedConfig; +@property (nonatomic, strong, nullable) PBMBackgroundAwareTimer *backgroundAwareTimer; + @end #pragma mark - Implementation @@ -96,6 +99,8 @@ - (nonnull instancetype)initWithCreativeModel:(PBMCreativeModel *)creativeModel if (webView) { self.prebidWebView = webView; } + + self.rewardedConfig = self.creativeModel.adConfiguration.rewardedConfig; } return self; @@ -135,6 +140,12 @@ - (void)setupView { self.prebidWebView.frame = rect; } + if (self.creativeModel.isCompanionAd) { + self.prebidWebView.rewardedAdURL = self.rewardedConfig.endcardEvent; + } else { + self.prebidWebView.rewardedAdURL = self.rewardedConfig.bannerEvent; + } + self.prebidWebView.delegate = self; self.view = self.prebidWebView; @@ -163,8 +174,11 @@ - (void)displayWithRootViewController:(UIViewController*)viewController { if (self.creativeModel.isCompanionAd == YES) { [self.eventManager trackEvent:PBMTrackingEventCreativeView]; - // FIXME: extremly ugly. It makes creative highly coupled with modal manager. Need to split responsibilities more carefully. - [self.modalManager creativeDisplayCompleted:self]; + // For rewarded we have different logic for display completion. + // See `setupRewardTimerIfNeeded` for more details + if (!self.creativeModel.adConfiguration.isRewarded) { + [self.modalManager creativeDisplayCompleted:self]; + } } [self.viewabilityTracker start]; @@ -173,9 +187,10 @@ - (void)displayWithRootViewController:(UIViewController*)viewController { - (void)onAdDisplayed { [super onAdDisplayed]; [self setupDisplayTimer]; + [self setupRewardTimerIfNeeded]; } -- (void) setupDisplayTimer { +- (void)setupDisplayTimer { //Banners display for a set amount of time and then signal creativeDidComplete. //Interstitials display for as long as the user is enjoying their presence. if (self.creativeModel.adConfiguration.presentAsInterstitial) { @@ -203,6 +218,86 @@ - (void) setupDisplayTimer { }); } +- (void)setupRewardTimerIfNeeded { + // NOTE: Rewarded API only + // Signal to the application that the user has earned the reward after + // the certain period of time that the ad is on the screen. + if (!self.creativeModel.adConfiguration.isRewarded) { + return; + } + + if (!self.rewardedConfig) { + return; + } + + NSTimeInterval rewardNotificationInterval = 0.0; + + if (self.creativeModel.isCompanionAd) { + NSNumber * videoEndcardTime = self.rewardedConfig.endcardTime; + NSNumber * defaultEndcardTime = self.rewardedConfig.defaultCompletionTime; + rewardNotificationInterval = (videoEndcardTime) ? [videoEndcardTime intValue] : [defaultEndcardTime intValue]; + } else { + NSNumber * bannerEndcardTime = self.rewardedConfig.bannerTime; + NSNumber * defaultBannerTime = self.rewardedConfig.defaultCompletionTime; + rewardNotificationInterval = (bannerEndcardTime) ? [bannerEndcardTime intValue] : [defaultBannerTime intValue]; + } + + self.backgroundAwareTimer = [PBMBackgroundAwareTimer new]; + + // Track user did earn reward + @weakify(self); + [self.backgroundAwareTimer startTimerWith:rewardNotificationInterval + completion:^{ + @strongify(self); + + if (!self) { return; } + + if (!self.creativeModel.userHasEarnedReward) { + self.creativeModel.userHasEarnedReward = YES; + [self.creativeViewDelegate creativeDidSendRewardedEvent:self]; + } + + // Track post reward event + [self setupPostRewardTimer]; + }]; +} + +- (void)setupPostRewardTimer { + // NOTE: Rewarded API only + // Signal to the SDK about the post reward event in order to execute close ad logic. + if (!self.creativeModel.adConfiguration.isRewarded) { + return; + } + + if (!self.rewardedConfig) { + return; + } + + NSTimeInterval postRewardTime = [self.rewardedConfig.postRewardTime doubleValue] ?: 0; + + if (postRewardTime < 0.0 || !self.creativeModel.userHasEarnedReward || + self.creativeModel.userPostRewardEventSent) { + return; + } + + self.backgroundAwareTimer = [PBMBackgroundAwareTimer new]; + + // Track user did earn reward + @weakify(self); + [self.backgroundAwareTimer startTimerWith:postRewardTime + completion:^{ + @strongify(self); + + if (!self) { return; } + + if (!self.creativeModel.userPostRewardEventSent) { + self.creativeModel.userPostRewardEventSent = YES; + [self.modalManager creativeDisplayCompleted:self]; + } + }]; +} + + // The session must be created only after WebView finishes loading - (void)createOpenMeasurementSession { @@ -276,6 +371,14 @@ - (void)webView:(PBMWebView *)webView receivedMRAIDLink:(NSURL *)url { } } +- (void)webView:(PBMWebView *)webView receivedRewardedEventLink:(NSURL *)url { + if (!self.creativeModel.userHasEarnedReward) { + [self.creativeViewDelegate creativeDidSendRewardedEvent:self]; + self.creativeModel.userHasEarnedReward = YES; + + [self setupPostRewardTimer]; + } +} #pragma mark - PBMModalManagerDelegate @@ -291,13 +394,6 @@ - (void)modalManagerDidFinishPop:(PBMModalState *)state { [self.creativeViewDelegate creativeClickthroughDidClose:self]; self.clickthroughVisible = NO; - //Pop to root after clickthroughs - if (self.creativeModel.adConfiguration.presentAsInterstitial) { - if (self.dismissInterstitialModalState) { - self.dismissInterstitialModalState(); - } - } - return; } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift index 3f2643a7c..fb0a6187b 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift @@ -13,7 +13,6 @@  limitations under the License.  */ -import Foundation import UIKit public class InterstitialController: NSObject, PBMAdViewManagerDelegate { @@ -61,6 +60,7 @@ public class InterstitialController: NSObject, PBMAdViewManagerDelegate { @objc public convenience init(bid: Bid, configId: String) { let adConfig = AdUnitConfig(configId: configId) adConfig.adConfiguration.isInterstitialAd = true + adConfig.adConfiguration.isRewarded = bid.rewardedConfig != nil self.init(bid: bid, adConfiguration: adConfig) } @@ -69,9 +69,15 @@ public class InterstitialController: NSObject, PBMAdViewManagerDelegate { self.renderer = PrebidMobilePluginRegister.shared.getPluginForPreferredRenderer(bid: bid) - let connection: PrebidServerConnectionProtocol = PrebidServerConnection.shared - self.renderer?.createInterstitialController?(bid: bid, adConfiguration: adConfiguration, connection: connection, adViewManagerDelegate: self, videoControlsConfig: videoControlsConfig) + + self.renderer?.createInterstitialController?( + bid: bid, + adConfiguration: adConfiguration, + connection: connection, + adViewManagerDelegate: self, + videoControlsConfig: videoControlsConfig + ) } @objc public func show() { @@ -144,6 +150,12 @@ public class InterstitialController: NSObject, PBMAdViewManagerDelegate { } } + @objc public func adDidSendRewardedEvent() { + if let delegate = interactionDelegate as? RewardedEventInteractionDelegate { + delegate.userDidEarnReward(self, PrebidReward(with: bid.rewardedConfig?.reward)) + } + } + @objc public func interstitialDisplayProperties() -> PBMInterstitialDisplayProperties { displayProperties } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/PrebidRenderer.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/PrebidRenderer.swift index c4eeb847b..998034fca 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/PrebidRenderer.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/PrebidRenderer.swift @@ -74,9 +74,6 @@ public class PrebidRenderer: NSObject, PrebidMobilePluginRenderer { adViewManager?.handleExternalTransaction(transaction) } - - - public func createInterstitialController(bid: Bid, adConfiguration: AdUnitConfig, connection: PrebidServerConnectionProtocol, adViewManagerDelegate adViewDelegate: InterstitialController?, @@ -88,6 +85,10 @@ public class PrebidRenderer: NSObject, PrebidMobilePluginRenderer { adConfiguration.adConfiguration.winningBidAdFormat = bid.adFormat videoControlsConfig?.initialize(with: bid.videoAdConfiguration) + if let ortbRewardedConfig = bid.rewardedConfig { + adConfiguration.adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: ortbRewardedConfig) + } + // This part is dedicating to test server-side ad configurations. // Need to be removed when ext.prebid.passthrough will be available. #if DEBUG diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m index fe7e0d279..2e0103927 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m @@ -14,7 +14,32 @@  */ #import "PBMORTBRewardedCompletion.h" +#import "PBMORTBRewardedCompletionBanner.h" +#import "PBMORTBRewardedCompletionVideo.h" @implementation PBMORTBRewardedCompletion +- (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { + if (!(self = [self init])) { + return nil; + } + + _banner = [[PBMORTBRewardedCompletionBanner alloc] initWithJsonDictionary:jsonDictionary[@"banner"]]; + _video = [[PBMORTBRewardedCompletionVideo alloc] initWithJsonDictionary:jsonDictionary[@"video"]]; + + return self; +} + +- (PBMJsonDictionary *)toJsonDictionary { + PBMMutableJsonDictionary * const ret = [[PBMMutableJsonDictionary alloc] init]; + + ret[@"banner"] = [self.banner toJsonDictionary]; + ret[@"video"] = [self.video toJsonDictionary]; + + [ret pbmRemoveEmptyVals]; + + return ret; +} + + @end diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMSafariVCOpener.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMSafariVCOpener.m index 409effa9a..af3e71606 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMSafariVCOpener.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMSafariVCOpener.m @@ -150,28 +150,32 @@ - (BOOL)shouldOpenURLSchemeExternally:(NSString *)strURLscheme { - (BOOL)openClickthroughWithURL:(NSURL *)url viewController:(UIViewController *)viewControllerForPresentingModals { - self.safariViewController = [[SFSafariViewController alloc] initWithURL:url]; - self.safariViewController.delegate = self; - - PBMOpenMeasurementSession * const measurementSession = self.measurementSessionProvider(); - PBMWindowLocker * windowLocker = [[PBMWindowLocker alloc] initWithWindow:viewControllerForPresentingModals.view.window - measurementSession:measurementSession]; - [windowLocker lock]; - - UIViewController * presentingViewController = viewControllerForPresentingModals; - - if (self.modalManager.modalViewController) { - presentingViewController = self.modalManager.modalViewController; - } - - if (self.onWillLoadURLInClickthrough != nil) { - self.onWillLoadURLInClickthrough(); + @try { + self.safariViewController = [[SFSafariViewController alloc] initWithURL:url]; + self.safariViewController.delegate = self; + + PBMOpenMeasurementSession * const measurementSession = self.measurementSessionProvider(); + PBMWindowLocker * windowLocker = [[PBMWindowLocker alloc] initWithWindow:viewControllerForPresentingModals.view.window + measurementSession:measurementSession]; + [windowLocker lock]; + + UIViewController * presentingViewController = viewControllerForPresentingModals; + + if (self.modalManager.modalViewController) { + presentingViewController = self.modalManager.modalViewController; + } + + if (self.onWillLoadURLInClickthrough != nil) { + self.onWillLoadURLInClickthrough(); + } + + [presentingViewController presentViewController:self.safariViewController animated:YES completion:^{ + [windowLocker unlock]; + }]; + } @catch (NSException *exception) { + PBMLogError(@"Error occurred during URL opening: %@", exception.reason); } - [presentingViewController presentViewController:self.safariViewController animated:YES completion:^{ - [windowLocker unlock]; - }]; - return YES; } diff --git a/PrebidMobile/PrebidMobileRendering/Utilities/BackgroundAwareTimer.swift b/PrebidMobile/PrebidMobileRendering/Utilities/BackgroundAwareTimer.swift new file mode 100644 index 000000000..dcfe0acd5 --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/Utilities/BackgroundAwareTimer.swift @@ -0,0 +1,103 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ + +import UIKit + +/// Timer that stops in background and resumes in foreground. Fires callback on timer completion. +/// Can execute only one task at a time. +@objc(PBMBackgroundAwareTimer) @objcMembers +public class BackgroundAwareTimer: NSObject { + + private(set) var isRunning: Bool + private var remainingTime: TimeInterval + private var startTime: Date? + private var completion: (() -> Void)? + + private var gcdItem: DispatchWorkItem? + + public override init() { + self.remainingTime = 0 + self.isRunning = false + + super.init() + + NotificationCenter.default.addObserver( + self, + selector: #selector(applicationDidEnterBackground), + name: UIApplication.didEnterBackgroundNotification, + object: nil + ) + + NotificationCenter.default.addObserver( + self, + selector: #selector(applicationWillEnterForeground), + name: UIApplication.willEnterForegroundNotification, + object: nil + ) + } + + deinit { + invalidateTimer() + } + + public func startTimer(with interval: TimeInterval, completion: @escaping () -> Void) { + guard !isRunning else { return } + + startTime = Date() + remainingTime = interval + self.completion = completion + + let gcdItem = DispatchWorkItem { [weak self] in + guard let self = self else { return } + completion() + self.invalidateTimer() + } + + self.gcdItem = gcdItem + + DispatchQueue.main.asyncAfter( + deadline: .now() + remainingTime, + execute: gcdItem + ) + + isRunning = true + } + + public func invalidateTimer() { + gcdItem = nil + completion = nil + isRunning = false + NotificationCenter.default.removeObserver(self) + } + + private func stopTimer() { + guard isRunning else { return } + + gcdItem?.cancel() + gcdItem = nil + remainingTime -= Date().timeIntervalSince(startTime ?? Date()) + isRunning = false + } + + @objc private func applicationDidEnterBackground() { + stopTimer() + } + + @objc private func applicationWillEnterForeground() { + if let completion, !isRunning && remainingTime > 0 { + startTimer(with: remainingTime, completion: completion) + } + } +} diff --git a/PrebidMobileTests/PrebidMobileTest-Bridging-Header.h b/PrebidMobileTests/PrebidMobileTest-Bridging-Header.h index 409142ef5..4dc020b83 100644 --- a/PrebidMobileTests/PrebidMobileTest-Bridging-Header.h +++ b/PrebidMobileTests/PrebidMobileTest-Bridging-Header.h @@ -175,3 +175,5 @@ #import "PBMLocationManagerProtocol.h" #import "InternalUserConsentDataManager.h" + +#import "PBMCloseActionManager.h" diff --git a/PrebidMobileTests/RenderingTests/Mocks/MockVideoView.swift b/PrebidMobileTests/RenderingTests/Mocks/MockVideoView.swift new file mode 100644 index 000000000..83733b930 --- /dev/null +++ b/PrebidMobileTests/RenderingTests/Mocks/MockVideoView.swift @@ -0,0 +1,26 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ + +import Foundation +@testable import PrebidMobile + +class MockVideoView: PBMVideoView { + + var mockRequiredVideoDuration: CGFloat = 10 + + override func requiredVideoDuration() -> CGFloat { + mockRequiredVideoDuration + } +} diff --git a/PrebidMobileTests/RenderingTests/TestExtensions/PBMVideoView+pbmTestExtension.h b/PrebidMobileTests/RenderingTests/TestExtensions/PBMVideoView+pbmTestExtension.h index 80e1396f0..975272d0b 100644 --- a/PrebidMobileTests/RenderingTests/TestExtensions/PBMVideoView+pbmTestExtension.h +++ b/PrebidMobileTests/RenderingTests/TestExtensions/PBMVideoView+pbmTestExtension.h @@ -19,9 +19,11 @@ @property (nonatomic, weak, nullable) PBMVideoCreative *creative; @property (nonatomic, strong) PBMAdViewButtonDecorator * _Nonnull skipButtonDecorator; +@property (nonatomic, strong, nonnull) NSNumber * progressBarDuration; - (void)updateControls; - (CGFloat)requiredVideoDuration; - (void)handleSkipDelay:(NSTimeInterval)skipDelay videoDuration:(NSTimeInterval)videoDuration; +- (NSNumber * _Nonnull)calculateProgressBarDuration; @end diff --git a/PrebidMobileTests/RenderingTests/Tests/CloseActionManagerTests.swift b/PrebidMobileTests/RenderingTests/Tests/CloseActionManagerTests.swift new file mode 100644 index 000000000..fe82e4855 --- /dev/null +++ b/PrebidMobileTests/RenderingTests/Tests/CloseActionManagerTests.swift @@ -0,0 +1,40 @@ +/*   Copyright 2018-2023 Prebid.org, Inc. + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ + +import XCTest +@testable import PrebidMobile + +class PBMCloseActionManagerTests: XCTestCase { + + func testGetActionWithCloseButtonDescription() { + let action = PBMCloseActionManager.getActionWithDescription("closebutton") + XCTAssertEqual(action.rawValue, PBMCloseAction.closeButton.rawValue) + } + + func testGetActionWithAutoCloseDescription() { + let action = PBMCloseActionManager.getActionWithDescription( "autoclose") + XCTAssertEqual(action.rawValue, PBMCloseAction.autoClose.rawValue) + } + + func testGetActionWithUnknownDescription() { + let action = PBMCloseActionManager.getActionWithDescription("unknown") + XCTAssertEqual(action.rawValue, PBMCloseAction.unknown.rawValue) + } + + func testGetActionWithEmptyDescription() { + let action = PBMCloseActionManager.getActionWithDescription("") + XCTAssertEqual(action.rawValue, PBMCloseAction.unknown.rawValue) + } +} diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest.swift index 2a03549a8..18592996f 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest.swift @@ -13,12 +13,10 @@  limitations under the License.  */ -import Foundation import XCTest - import UIKit -@testable import PrebidMobile +@testable import PrebidMobile class PBMHTMLCreativeTest_PublicAPI: PBMHTMLCreativeTest_Base { @@ -36,46 +34,46 @@ class PBMHTMLCreativeTest_PublicAPI: PBMHTMLCreativeTest_Base { creativeModel: self.mockCreativeModel, transaction:UtilitiesForTesting.createEmptyTransaction(), webView: self.mockWebView, - sdkConfiguration: Prebid.mock + sdkConfiguration: Prebid.mock ) self.htmlCreative.setupView() PBMAssertEq(self.htmlCreative.view, nil) } - + func testSetupViewFailWithVast() { self.mockCreativeModel.html = UtilitiesForTesting.loadFileAsStringFromBundle("prebid_vast_response.xml") self.htmlCreative = MockPBMHTMLCreative( creativeModel: self.mockCreativeModel, transaction:UtilitiesForTesting.createEmptyTransaction(), webView: self.mockWebView, - sdkConfiguration: Prebid.mock + sdkConfiguration: Prebid.mock ) self.htmlCreative.setupView() - + PBMAssertEq(self.htmlCreative.view, nil) } - + func testSetupView_sizesWebViewCorrectly() { self.htmlCreative.setupView() - + let expectedFrame = CGRect(x: 0, y: 0, width: self.mockCreativeModel.width, height: self.mockCreativeModel.height) PBMAssertEq(self.htmlCreative.view?.frame, expectedFrame) } - + func testSetupView_sanitizesHTML() { self.mockCreativeModel.html = "

html content

" let expectedHTML = "\(self.mockCreativeModel.html!)" - + var actualHTML: String? mockWebView.mock_loadHTML = { (html, _, _) in actualHTML = html } - + self.htmlCreative.setupView() self.htmlCreative.display(withRootViewController:mockViewController) - + PBMAssertEq(actualHTML, expectedHTML) } - + func testDisplay_failsWithInvalidView() { //TODO: Update this test to check the log instead @@ -83,13 +81,13 @@ class PBMHTMLCreativeTest_PublicAPI: PBMHTMLCreativeTest_Base { self.htmlCreative.view = nil self.htmlCreative.display(withRootViewController: UIViewController()) PBMAssertEq(self.htmlCreative.view?.constraints, nil) - + //Set view to non-nil. Expect that display will succeed and this constraints will be non-nil. self.htmlCreative.view = UIView() self.htmlCreative.display(withRootViewController: UIViewController()) PBMAssertEq(self.htmlCreative.view?.constraints, []) } - + func testDisplay_triggersImpression() { Prebid.forcedIsViewable = true @@ -114,7 +112,7 @@ class PBMHTMLCreativeTest_PublicAPI: PBMHTMLCreativeTest_Base { } self.htmlCreative.display(withRootViewController: UIViewController()) - + self.waitForExpectations(timeout: 1) } @@ -125,7 +123,7 @@ class PBMHTMLCreativeTest_PublicAPI: PBMHTMLCreativeTest_Base { companionTrackingClickExpectation.fulfill() } } - + self.mockCreativeModel.isCompanionAd = true let mockViewController = MockViewController() self.htmlCreative.display(withRootViewController: mockViewController) @@ -150,7 +148,7 @@ class PBMHTMLCreativeTest_PublicAPI: PBMHTMLCreativeTest_Base { // Session's expectations let expectationSessionStart = self.expectation(description:"expectationSessionStart") let expectationSessionStop = self.expectation(description:"expectationSessionStop") - + measurement.initializeSessionClosure = { session in guard let session = session as? MockMeasurementSession else { XCTFail() @@ -180,19 +178,19 @@ class PBMHTMLCreativeTest_PublicAPI: PBMHTMLCreativeTest_Base { self.transaction = UtilitiesForTesting.createEmptyTransaction() transaction.measurementWrapper = measurement - + self.htmlCreative = MockPBMHTMLCreative( creativeModel: self.mockCreativeModel, transaction:transaction, webView: nil, - sdkConfiguration: Prebid.mock + sdkConfiguration: Prebid.mock ) self.htmlCreative.setupView() self.htmlCreative.display(withRootViewController:mockViewController) transaction.creatives.add(self.htmlCreative!) self.htmlCreative.createOpenMeasurementSession(); - + wait(for: measurementExpectations, timeout: 5, enforceOrder: true); self.htmlCreative = nil @@ -200,7 +198,7 @@ class PBMHTMLCreativeTest_PublicAPI: PBMHTMLCreativeTest_Base { wait(for: [expectationSessionStop], timeout: 1); } - + func testEventClick() { let expectation = self.expectation(description: "PBMTrackingEventClick Expectation") @@ -254,7 +252,7 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati override func setUp() { super.setUp() - + //There should be no network traffic MockServer.shared.reset() MockServer.shared.notFoundRule.mockServerReceivedRequestHandler = { (urlRequest:URLRequest) in @@ -270,7 +268,7 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati let pbmCreativeModel = PBMCreativeModel(adConfiguration: AdConfiguration()) pbmCreativeModel.displayDurationInSeconds = 30 pbmCreativeModel.html = "test html" - + self.htmlCreative = MockPBMHTMLCreative(creativeModel:pbmCreativeModel, transaction:UtilitiesForTesting.createEmptyTransaction()) self.htmlCreative.creativeResolutionDelegate = self self.htmlCreative.creativeViewDelegate = self @@ -294,13 +292,13 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati func testWebViewLoad() { self.expectationDownloadCompleted = self.expectation(description: "Expected downloadCompleted to be called") self.expectationBlockForAWhile = self.expectation(description: "Expected webViewReadyToDisplay to be called") - + self.htmlCreative.setupView() logToFile = .init() self.htmlCreative.display(withRootViewController:mockViewController) - + DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute:{ let log = Log.getLogFileAsString() ?? "" XCTAssertTrue(log.contains("PBMWebView is ready to display")) @@ -316,7 +314,7 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati self.htmlCreative.setupView() logToFile = .init() - + let webView = self.htmlCreative.view as! PBMWebView self.htmlCreative.webView(webView, failedToLoadWithError:PBMError.error(message: "Failed to load html", type: .internalError)) @@ -336,7 +334,7 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati self.htmlCreative.setupView() self.htmlCreative.display(withRootViewController:mockViewController) - + let webView = self.htmlCreative.view as! PBMWebView self.htmlCreative.webView(webView, receivedClickthroughLink:self.clickThroughURL) self.waitForExpectations(timeout: 5, handler: nil) @@ -367,7 +365,7 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati creativeModel: pbmCreativeModel, transaction:UtilitiesForTesting.createEmptyTransaction(), webView: mockWebView, - sdkConfiguration: sdkConfiguration + sdkConfiguration: sdkConfiguration ) PBMFunctions.application = mockApplication @@ -375,21 +373,21 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati waitForExpectations(timeout: 3) } - + func testHasVastTag() { let adConfiguration = AdConfiguration() let pbmCreativeModel = PBMCreativeModel(adConfiguration: adConfiguration) self.htmlCreative = MockPBMHTMLCreative(creativeModel: pbmCreativeModel, transaction: UtilitiesForTesting.createEmptyTransaction()) - + let validXML1 = "" XCTAssertTrue(self.htmlCreative.hasVastTag(validXML2)) - + let incorrectXML1 = "" XCTAssertFalse(self.htmlCreative.hasVastTag(incorrectXML1)) - + let incorrectXML2 = "VAST version=123" XCTAssertFalse(self.htmlCreative.hasVastTag(incorrectXML2)) } @@ -403,12 +401,12 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati parentWindow.frame = CGRect(x: 0.0, y: 0.0, width: 100, height: 100) self.htmlCreative.view?.frame = CGRect(x: 0.0, y: 0.0, width: 100, height: 50) - + parentView.addSubview(self.htmlCreative.view!) parentWindow.addSubview(parentView) self.expectationCreativeDidDisplay = self.expectation(description: "Expected creativeDidDisplay to be called") - + let viewabilityTracker = PBMCreativeViewabilityTracker(creative: self.htmlCreative) viewabilityTracker.checkViewability() @@ -416,7 +414,7 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati self.htmlCreative.view?.removeFromSuperview() self.htmlCreative.view?.frame = CGRect(x: 101.0, y: 101.0, width: 100, height: 100) - + parentView.addSubview(self.htmlCreative.view!) self.expectationCreativeDidDisplay = self.expectation(description: "Expected creativeDidDisplay should not be called") @@ -425,7 +423,160 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati self.waitForExpectations(timeout: 1, handler: nil) } - + + func testRewardEvent_Banner() { + let time: NSNumber = 5 + let exp = expectation(description: "Reward completion") + + let ortbRewarded = PBMORTBRewardedConfiguration() + ortbRewarded.completion = PBMORTBRewardedCompletion() + ortbRewarded.completion?.banner = PBMORTBRewardedCompletionBanner() + ortbRewarded.completion?.banner?.time = time + + let adConfiguration = AdConfiguration() + adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: ortbRewarded) + adConfiguration.isRewarded = true + let creativeModel = PBMCreativeModel(adConfiguration: adConfiguration) + self.htmlCreative = MockPBMHTMLCreative( + creativeModel: creativeModel, + transaction: UtilitiesForTesting.createEmptyTransaction() + ) + + htmlCreative.onViewabilityChanged( + true, + viewExposure: PBMViewExposure( + exposureFactor: 5, + visibleRectangle: CGRect(origin: .zero, size: CGSize(width: 300, height: 250)) + ) + ) + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(time.intValue + 1)) { + if self.htmlCreative.creativeModel?.userHasEarnedReward == true { + exp.fulfill() + } + } + + waitForExpectations(timeout: 10) + } + + func testRewardEvent_Endcard() { + let time: NSNumber = 5 + let exp = expectation(description: "Reward completion") + + let ortbRewarded = PBMORTBRewardedConfiguration() + ortbRewarded.completion = PBMORTBRewardedCompletion() + ortbRewarded.completion?.video = PBMORTBRewardedCompletionVideo() + ortbRewarded.completion?.video?.endcard = PBMORTBRewardedCompletionVideoEndcard() + ortbRewarded.completion?.video?.endcard?.time = time + + let adConfiguration = AdConfiguration() + adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: ortbRewarded) + adConfiguration.isRewarded = true + let creativeModel = PBMCreativeModel(adConfiguration: adConfiguration) + self.htmlCreative = MockPBMHTMLCreative( + creativeModel: creativeModel, + transaction: UtilitiesForTesting.createEmptyTransaction() + ) + + htmlCreative.creativeModel?.isCompanionAd = true + + htmlCreative.onViewabilityChanged( + true, + viewExposure: PBMViewExposure( + exposureFactor: 5, + visibleRectangle: CGRect(origin: .zero, size: CGSize(width: 300, height: 250)) + ) + ) + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(time.intValue + 1)) { + + if self.htmlCreative.creativeModel?.userHasEarnedReward == true { + exp.fulfill() + } + } + + waitForExpectations(timeout: 10) + } + + func testPostRewardEvent_Banner() { + let rewardTime: NSNumber = 2 + let postRewardTime: NSNumber = 2 + let exp = expectation(description: "Post reward completion") + + let ortbRewarded = PBMORTBRewardedConfiguration() + ortbRewarded.completion = PBMORTBRewardedCompletion() + ortbRewarded.completion?.banner = PBMORTBRewardedCompletionBanner() + ortbRewarded.completion?.banner?.time = rewardTime + ortbRewarded.close = PBMORTBRewardedClose() + ortbRewarded.close?.postrewardtime = postRewardTime + + let adConfiguration = AdConfiguration() + adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: ortbRewarded) + adConfiguration.isRewarded = true + let creativeModel = PBMCreativeModel(adConfiguration: adConfiguration) + self.htmlCreative = MockPBMHTMLCreative( + creativeModel: creativeModel, + transaction: UtilitiesForTesting.createEmptyTransaction() + ) + + htmlCreative.onViewabilityChanged( + true, + viewExposure: PBMViewExposure( + exposureFactor: 5, + visibleRectangle: CGRect(origin: .zero, size: CGSize(width: 300, height: 250)) + ) + ) + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(rewardTime.intValue + postRewardTime.intValue + 1)) { + if self.htmlCreative.creativeModel?.userPostRewardEventSent == true { + exp.fulfill() + } + } + + waitForExpectations(timeout: 10) + } + + func testPostRewardEvent_Endcard() { + let rewardTime: NSNumber = 2 + let postRewardTime: NSNumber = 2 + let exp = expectation(description: "Post reward completion") + + let ortbRewarded = PBMORTBRewardedConfiguration() + ortbRewarded.completion = PBMORTBRewardedCompletion() + ortbRewarded.completion?.video = PBMORTBRewardedCompletionVideo() + ortbRewarded.completion?.video?.endcard = PBMORTBRewardedCompletionVideoEndcard() + ortbRewarded.completion?.video?.endcard?.time = rewardTime + ortbRewarded.close = PBMORTBRewardedClose() + ortbRewarded.close?.postrewardtime = postRewardTime + + let adConfiguration = AdConfiguration() + adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: ortbRewarded) + adConfiguration.isRewarded = true + let creativeModel = PBMCreativeModel(adConfiguration: adConfiguration) + self.htmlCreative = MockPBMHTMLCreative( + creativeModel: creativeModel, + transaction: UtilitiesForTesting.createEmptyTransaction() + ) + + htmlCreative.creativeModel?.isCompanionAd = true + + htmlCreative.onViewabilityChanged( + true, + viewExposure: PBMViewExposure( + exposureFactor: 5, + visibleRectangle: CGRect(origin: .zero, size: CGSize(width: 300, height: 250)) + ) + ) + + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(rewardTime.intValue + postRewardTime.intValue + 1)) { + if self.htmlCreative.creativeModel?.userPostRewardEventSent == true { + exp.fulfill() + } + } + + waitForExpectations(timeout: 10) + } + //MARK: - PBMCreativeResolutionDelegate func creativeDidComplete(_ creative: PBMAbstractCreative) { @@ -462,4 +613,5 @@ class PBMHTMLCreativeTest : XCTestCase, PBMCreativeResolutionDelegate, PBMCreati } func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} } diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest_Base.swift b/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest_Base.swift index 983881156..e16599ab0 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest_Base.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest_Base.swift @@ -130,6 +130,8 @@ class PBMHTMLCreativeTest_Base: XCTestCase, PBMCreativeViewDelegate { func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} + // MARK: - Utilities /** Setup an expectation and associated, mocked `PBMWebView` to fulfill that expectation. diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest_MRAIDClose.swift b/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest_MRAIDClose.swift index 066f42003..9d809c6e4 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest_MRAIDClose.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMHTMLCreativeTest_MRAIDClose.swift @@ -133,4 +133,5 @@ class PBMHTMLCreativeTest_MRAIDClose: XCTestCase, PBMCreativeViewDelegate { func creativeMraidDidExpand(_ creative: PBMAbstractCreative) {} func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} } diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMMRAIDControllerTest_Base.swift b/PrebidMobileTests/RenderingTests/Tests/PBMMRAIDControllerTest_Base.swift index 988d06939..c2e8ab989 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMMRAIDControllerTest_Base.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMMRAIDControllerTest_Base.swift @@ -132,6 +132,7 @@ class PBMMRAIDControllerTest_Base: XCTestCase, PBMCreativeViewDelegate { func creativeDidDisplay(_ creative: PBMAbstractCreative) {} func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} // MARK: - Utilities /** diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMModalViewControllerTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMModalViewControllerTest.swift index be4d20836..f297a4902 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMModalViewControllerTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMModalViewControllerTest.swift @@ -125,21 +125,30 @@ class PBMModalViewControllerTest: XCTestCase, PBMModalViewControllerDelegate { XCTAssertFalse(viewController.prefersStatusBarHidden) } - func testCreativeDisplayCompleted() { + func testCreativeDisplayCompleted_Rewarded() { let controller = PBMModalViewController() let displayProperties = PBMInterstitialDisplayProperties() displayProperties.closeDelayLeft = 3 let adConfiguration = AdConfiguration() adConfiguration.isRewarded = true + adConfiguration.winningBidAdFormat = .video + + let modalState = PBMModalState( + view: UIView(), + adConfiguration: adConfiguration, + displayProperties: displayProperties, + onStatePopFinished: nil, + onStateHasLeftApp: nil + ) - let modalState = PBMModalState(view: UIView(), adConfiguration: adConfiguration, displayProperties:displayProperties, onStatePopFinished: nil, onStateHasLeftApp: nil) controller.modalState = modalState - controller.closeButtonDecorator.button.isHidden = true; + controller.closeButtonDecorator.button.isHidden = true XCTAssertTrue(controller.closeButtonDecorator.button.isHidden) let creative = UtilitiesForTesting.createHTMLCreative() + creative.creativeModel?.adConfiguration = adConfiguration controller.creativeDisplayCompleted(creative) XCTAssertFalse(controller.closeButtonDecorator.button.isHidden) } diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMVideoViewTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMVideoViewTest.swift index 8e524bbd6..27bb08117 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMVideoViewTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMVideoViewTest.swift @@ -1,23 +1,23 @@ /*   Copyright 2018-2021 Prebid.org, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ import XCTest @testable import PrebidMobile class PBMVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCreativeViewDelegate, PBMVideoViewDelegate { - + var vc: UIViewController? let connection = UtilitiesForTesting.createConnectionForMockedTest() @@ -36,7 +36,7 @@ class PBMVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCreativeVi override func setUp() { MockServer.shared.reset() } - + override func tearDown() { MockServer.shared.reset() self.videoCreative = nil @@ -145,7 +145,7 @@ class PBMVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCreativeVi // Expected duration of video small.mp4 is 6 sec let expectedVideoDuration = 6.0 let expectedPausedTime = 3.0 - + setupVideoCreative(videoFileURL: "http://get_video/small.mp4", localVideoFileName: "small.mp4") self.videoCreative.creativeModel!.displayDurationInSeconds = expectedVideoDuration as NSNumber @@ -187,7 +187,7 @@ class PBMVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCreativeVi // Expected duration of video small.mp4 is 6 sec let expectedVideoDuration = 6.0 let expectedStoppedDely = 3.0 - + setupVideoCreative(videoFileURL: "http://get_video/small.mp4", localVideoFileName: "small.mp4") self.videoCreative.creativeModel!.displayDurationInSeconds = expectedVideoDuration as NSNumber @@ -262,7 +262,7 @@ class PBMVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCreativeVi // Expected duration of video small.mp4 is 6 sec let expectedVideoDuration = 6.0 - + setupVideoCreative(videoFileURL: "http://get_video/small.mp4", localVideoFileName: "small.mp4") self.videoCreative.creativeModel!.displayDurationInSeconds = expectedVideoDuration as NSNumber @@ -317,6 +317,212 @@ class PBMVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCreativeVi waitForExpectations(timeout: 2, handler: nil) } + func testCalculateProgressBarDuration_whenNotRewardedAndHasCompanionAd() { + let adConfiguration = AdConfiguration() + adConfiguration.isRewarded = true + + let model = PBMCreativeModel(adConfiguration:adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:model, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + let mockVideoView = MockVideoView(creative: self.videoCreative) + mockVideoView.mockRequiredVideoDuration = 10 + + let expectedDuration = mockVideoView.requiredVideoDuration() + let result = mockVideoView.calculateProgressBarDuration().doubleValue + + XCTAssertEqual(result, expectedDuration) + } + + func testCalculateProgressBarDuration_whenPlaybackEventIsStart() { + let postRewardTime: NSNumber = 5 + + let adConfiguration = AdConfiguration() + adConfiguration.isRewarded = true + adConfiguration.rewardedConfig = createRewardedConfig(postRewardTime: postRewardTime, playbackevent: "start") + + let model = PBMCreativeModel(adConfiguration:adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:model, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + let mockVideoView = MockVideoView(creative: self.videoCreative) + mockVideoView.mockRequiredVideoDuration = 10 + + let expectedDuration = postRewardTime.doubleValue + let result = mockVideoView.calculateProgressBarDuration().doubleValue + + XCTAssertEqual(result, expectedDuration) + } + + func testCalculateProgressBarDuration_whenPlaybackEventIsFirstQuartile() { + let postRewardTime: NSNumber = 5 + + let adConfiguration = AdConfiguration() + adConfiguration.isRewarded = true + adConfiguration.rewardedConfig = createRewardedConfig(postRewardTime: postRewardTime, playbackevent: "firstquartile") + + let model = PBMCreativeModel(adConfiguration:adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:model, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + let mockVideoView = MockVideoView(creative: self.videoCreative) + + let expectedDuration = 0.25 * mockVideoView.requiredVideoDuration() + postRewardTime.doubleValue + let result = mockVideoView.calculateProgressBarDuration().doubleValue + + XCTAssertEqual(result, expectedDuration) + } + + func testCalculateProgressBarDuration_whenPlaybackEventIsMidpoint() { + let postRewardTime: NSNumber = 5 + + let adConfiguration = AdConfiguration() + adConfiguration.isRewarded = true + adConfiguration.rewardedConfig = createRewardedConfig(postRewardTime: postRewardTime, playbackevent: "midpoint") + + let model = PBMCreativeModel(adConfiguration:adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:model, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + let mockVideoView = MockVideoView(creative: self.videoCreative) + + let expectedDuration = 0.5 * mockVideoView.requiredVideoDuration() + postRewardTime.doubleValue + let result = mockVideoView.calculateProgressBarDuration().doubleValue + + XCTAssertEqual(result, expectedDuration) + } + + func testCalculateProgressBarDuration_whenPlaybackEventIsThirdQuartile() { + let postRewardTime: NSNumber = 5 + let adConfiguration = AdConfiguration() + adConfiguration.isRewarded = true + adConfiguration.rewardedConfig = createRewardedConfig(postRewardTime: postRewardTime, playbackevent: "thirdquartile") + + let model = PBMCreativeModel(adConfiguration:adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:model, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + let mockVideoView = MockVideoView(creative: self.videoCreative) + + let expectedDuration = 0.5 * mockVideoView.requiredVideoDuration() + postRewardTime.doubleValue + let result = mockVideoView.calculateProgressBarDuration().doubleValue + + XCTAssertEqual(result, expectedDuration) + } + + func testCalculateProgressBarDuration_whenPlaybackEventIsComplete() { + let postRewardTime: NSNumber = 5 + + let adConfiguration = AdConfiguration() + adConfiguration.isRewarded = true + adConfiguration.rewardedConfig = createRewardedConfig(postRewardTime: postRewardTime, playbackevent: "complete") + + let model = PBMCreativeModel(adConfiguration:adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:model, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + let mockVideoView = MockVideoView(creative: self.videoCreative) + + let expectedDuration = mockVideoView.requiredVideoDuration() + let result = mockVideoView.calculateProgressBarDuration().doubleValue + + XCTAssertEqual(result, expectedDuration) + } + + func testCalculateProgressBarDuration_whenCompletionCriteriaIsTime() { + let rewardTime: NSNumber = 2 + let postRewardTime: NSNumber = 5 + + let adConfiguration = AdConfiguration() + adConfiguration.isRewarded = true + adConfiguration.rewardedConfig = createRewardedConfig(postRewardTime: postRewardTime, time: rewardTime) + + let model = PBMCreativeModel(adConfiguration:adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:model, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + let mockVideoView = MockVideoView(creative: self.videoCreative) + + let expectedDuration = rewardTime.doubleValue + postRewardTime.doubleValue + let result = mockVideoView.calculateProgressBarDuration().doubleValue + + XCTAssertEqual(result, expectedDuration) + } + + func testCalculateProgressBarDuration_whenCompletionCriteriaIsTimeAndExceedsVideoDuration() { + let rewardTime: NSNumber = 100 + let postRewardTime: NSNumber = 5 + + let adConfiguration = AdConfiguration() + adConfiguration.isRewarded = true + adConfiguration.rewardedConfig = createRewardedConfig(postRewardTime: postRewardTime, time: rewardTime) + + let model = PBMCreativeModel(adConfiguration:adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:model, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + let mockVideoView = MockVideoView(creative: self.videoCreative) + + let expectedDuration = mockVideoView.requiredVideoDuration() + let result = mockVideoView.calculateProgressBarDuration().doubleValue + + XCTAssertEqual(result, expectedDuration) + } + + func testCalculateProgressBarDuration_default() { + let adConfiguration = AdConfiguration() + adConfiguration.isRewarded = true + adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: PBMORTBRewardedConfiguration()) + + let model = PBMCreativeModel(adConfiguration: adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:model, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + let mockVideoView = MockVideoView(creative: self.videoCreative) + + let expectedDuration = mockVideoView.requiredVideoDuration() + let result = mockVideoView.calculateProgressBarDuration().doubleValue + + XCTAssertEqual(result, expectedDuration) + } + + // MARK: - PBMCreativeDownloadDelegate func creativeReady(_ creative: PBMAbstractCreative) { @@ -365,7 +571,8 @@ class PBMVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCreativeVi func learnMoreWasClicked() {} func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} - + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} + func videoViewCurrentPlayingTime(_ currentPlayingTime: NSNumber) {} // MARK: - Helper Methods @@ -418,7 +625,20 @@ class PBMVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCreativeVi self.expectationVideoViewCompletedDisplay = expectation(description: "expectationVideoViewCompletedDisplay") waitForExpectations(timeout: expectedDuration + 5, handler:nil) - + XCTAssertTrue(self.isVideoViewCompletedDisplay) } + + private func createRewardedConfig(postRewardTime: NSNumber = 0, playbackevent: String? = nil, + time: NSNumber? = nil) -> RewardedConfig { + let ortbRewarded = PBMORTBRewardedConfiguration() + ortbRewarded.completion = PBMORTBRewardedCompletion() + ortbRewarded.completion?.video = PBMORTBRewardedCompletionVideo() + ortbRewarded.completion?.video?.playbackevent = playbackevent + ortbRewarded.completion?.video?.time = time + ortbRewarded.close = PBMORTBRewardedClose() + ortbRewarded.close?.postrewardtime = postRewardTime + + return RewardedConfig(ortbRewarded: ortbRewarded) + } } diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMWebViewTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMWebViewTest.swift index 7ee160fd1..c174326ec 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMWebViewTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMWebViewTest.swift @@ -1055,6 +1055,8 @@ class PBMWebViewTest : XCTestCase, PBMWebViewDelegate { expectationWebViewReceivedMRAIDLink?.fulfill() } + func webView(_ webView: PBMWebView, receivedRewardedEventLink url: URL) {} + // MARK: - Check methods private func checkJSEvaluating( webView: PBMWebView, diff --git a/PrebidMobileTests/RenderingTests/Tests/Prebid/PBMORTBTest.swift b/PrebidMobileTests/RenderingTests/Tests/Prebid/PBMORTBTest.swift index 432753fdf..b8c7fdd27 100644 --- a/PrebidMobileTests/RenderingTests/Tests/Prebid/PBMORTBTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/Prebid/PBMORTBTest.swift @@ -311,6 +311,35 @@ class PBMORTBTest: XCTestCase { } } + func testRewardedResponse() { + let rewarded = PBMORTBRewardedConfiguration() + + rewarded.completion = PBMORTBRewardedCompletion() + + rewarded.completion?.banner = PBMORTBRewardedCompletionBanner() + rewarded.completion?.banner?.time = 5 + rewarded.completion?.banner?.event = "rwdd" + + rewarded.completion?.video = PBMORTBRewardedCompletionVideo() + rewarded.completion?.video?.time = 5 + rewarded.completion?.video?.playbackevent = "complete" + + rewarded.completion?.video?.endcard = PBMORTBRewardedCompletionVideoEndcard() + rewarded.completion?.video?.endcard?.time = 5 + rewarded.completion?.video?.endcard?.event = "rwdd" + + rewarded.close = PBMORTBRewardedClose() + rewarded.close?.action = "closebutton" + rewarded.close?.postrewardtime = 5 + + rewarded.reward = PBMORTBRewardedReward() + rewarded.reward?.type = "coins" + rewarded.reward?.count = 5 + + codeAndDecode(abstract: rewarded, expectedString: "{\"close\":{\"action\":\"closebutton\",\"postrewardtime\":5},\"completion\":{\"banner\":{\"event\":\"rwdd\",\"time\":5},\"video\":{\"endcard\":{\"event\":\"rwdd\",\"time\":5},\"playbackevent\":\"complete\",\"time\":5}},\"reward\":{\"count\":5,\"type\":\"coins\"}}") + } + + // MARK: - Private helpers private func codeAndDecode(abstract:T, expectedString:String, file: StaticString = #file, line: UInt = #line, decoder: (JsonDictionary) -> T?) { diff --git a/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/PBMRewardedVideoViewTest.swift b/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/PBMRewardedVideoViewTest.swift index 535a51e62..6636f7d4b 100644 --- a/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/PBMRewardedVideoViewTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/RewardedVideo/PBMRewardedVideoViewTest.swift @@ -121,6 +121,7 @@ class PBMRewardedVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCr // MARK: - PBMVideoViewDelegate + func videoViewCurrentPlayingTime(_ currentPlayingTime: NSNumber) {} func videoViewFailedWithError(_ error: Error) {} func videoViewReadyToDisplay() {} func videoViewCompletedDisplay() {} @@ -152,6 +153,7 @@ class PBMRewardedVideoViewTest: XCTestCase, PBMCreativeResolutionDelegate, PBMCr func learnMoreWasClicked() {} func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} // MARK: - Helper Methods private func setupVideoCreative(videoFileURL:String = "http://get_video/small.mp4", localVideoFileName:String = "small.mp4") { diff --git a/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMRewardedVideoCreativeTest.swift b/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMRewardedVideoCreativeTest.swift index bb15f9547..062c636e5 100644 --- a/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMRewardedVideoCreativeTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMRewardedVideoCreativeTest.swift @@ -87,6 +87,7 @@ class PBMRewardedVideoCreativeTest: XCTestCase, PBMCreativeResolutionDelegate, P func creativeMraidDidCollapse(_ creative: PBMAbstractCreative) {} func creativeMraidDidExpand(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} func creativeReady(_ creative: PBMAbstractCreative) { self.expectationDownloadCompleted.fulfill() diff --git a/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMVideoCreativeTest.swift b/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMVideoCreativeTest.swift index aa4416d65..4a924d71b 100644 --- a/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMVideoCreativeTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/VASTTests/PBMVideoCreativeTest.swift @@ -13,7 +13,6 @@  limitations under the License.  */ -import Foundation import UIKit import XCTest import AVFoundation @@ -31,6 +30,7 @@ class VideoCreativeDelegateTest: XCTestCase, PBMCreativeResolutionDelegate, PBMC var expectationDownloadFailed:XCTestExpectation! var expectationDidLeaveApp:XCTestExpectation! var expectationVideoViewCompletedDisplay:XCTestExpectation? + var expectationCreativeDidSendRewardedEvent:XCTestExpectation? var isVideoViewCompletedDisplay = false; private var logToFile: LogToFileLock? @@ -324,7 +324,75 @@ class VideoCreativeDelegateTest: XCTestCase, PBMCreativeResolutionDelegate, PBMC waitForExpectations(timeout: 1) } - //MARK: - PBMCreativeResolutionDelegate + func testRewardEvent() { + let time: NSNumber = 5 + expectationCreativeDidSendRewardedEvent = expectation(description: "Reward event - creativeDidSendRewardedEvent called") + + let ortbRewarded = PBMORTBRewardedConfiguration() + ortbRewarded.completion = PBMORTBRewardedCompletion() + ortbRewarded.completion?.video = PBMORTBRewardedCompletionVideo() + ortbRewarded.completion?.video?.time = time + + let adConfiguration = AdConfiguration() + adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: ortbRewarded) + adConfiguration.isRewarded = true + + let creativeModel = PBMCreativeModel(adConfiguration: adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:creativeModel, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + self.videoCreative.creativeResolutionDelegate = self + self.videoCreative.creativeViewDelegate = self + + self.videoCreative.videoViewCurrentPlayingTime(time) + + waitForExpectations(timeout: 1) + + // If video without endcard - we should show learn more button when reward completion is fired + XCTAssertTrue(videoCreative.videoView.showLearnMore) + } + + func testPostRewardEvent() { + let rewardTime: NSNumber = 5 + let postRewardTime: NSNumber = 2 + expectationCreativeDidSendRewardedEvent = expectation(description: "Reward event - creativeDidSendRewardedEvent called") + + let ortbRewarded = PBMORTBRewardedConfiguration() + ortbRewarded.completion = PBMORTBRewardedCompletion() + ortbRewarded.completion?.video = PBMORTBRewardedCompletionVideo() + ortbRewarded.completion?.video?.time = rewardTime + ortbRewarded.close = PBMORTBRewardedClose() + ortbRewarded.close?.postrewardtime = postRewardTime + + let adConfiguration = AdConfiguration() + adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: ortbRewarded) + adConfiguration.isRewarded = true + + let creativeModel = PBMCreativeModel(adConfiguration: adConfiguration) + + self.videoCreative = PBMVideoCreative( + creativeModel:creativeModel, + transaction:UtilitiesForTesting.createEmptyTransaction(), + videoData:Data() + ) + + self.videoCreative.creativeResolutionDelegate = self + self.videoCreative.creativeViewDelegate = self + + self.videoCreative.videoViewCurrentPlayingTime(rewardTime) + self.videoCreative.videoViewCurrentPlayingTime(postRewardTime) + + XCTAssertTrue(videoCreative.creativeModel!.userPostRewardEventSent) + + waitForExpectations(timeout: 1) + } + + + // MARK: - PBMCreativeResolutionDelegate func creativeReady(_ creative:PBMAbstractCreative) { self.expectationDownloadCompleted.fulfill() self.videoCreative.display(withRootViewController: UIViewController()) @@ -364,6 +432,12 @@ class VideoCreativeDelegateTest: XCTestCase, PBMCreativeResolutionDelegate, PBMC func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func videoViewReadyToDisplay() {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) { + expectationCreativeDidSendRewardedEvent?.fulfill() + } + + func videoViewCurrentPlayingTime(_ currentPlayingTime: NSNumber) {} + func videoViewCompletedDisplay() { isVideoViewCompletedDisplay = true self.expectationVideoViewCompletedDisplay?.fulfill() diff --git a/PrebidMobileTests/RenderingTests/Tests/VASTTests/RewardedVideoEventsTest.swift b/PrebidMobileTests/RenderingTests/Tests/VASTTests/RewardedVideoEventsTest.swift index 5bc5588c7..7312747fc 100644 --- a/PrebidMobileTests/RenderingTests/Tests/VASTTests/RewardedVideoEventsTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/VASTTests/RewardedVideoEventsTest.swift @@ -165,6 +165,7 @@ class RewardedVideoEventsTest : XCTestCase, PBMCreativeViewDelegate { func creativeInterstitialDidLeaveApp(_ creative:PBMAbstractCreative) {} func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} //MARK: - Utility diff --git a/PrebidMobileTests/RenderingTests/Tests/VASTTests/VastEventTrackingTest.swift b/PrebidMobileTests/RenderingTests/Tests/VASTTests/VastEventTrackingTest.swift index d278ed812..0925878c7 100644 --- a/PrebidMobileTests/RenderingTests/Tests/VASTTests/VastEventTrackingTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/VASTTests/VastEventTrackingTest.swift @@ -151,7 +151,8 @@ class VastEventTrackingTest : XCTestCase, PBMCreativeViewDelegate { self.wait(for: [inlineVastRequestSuccessfulExpectation], timeout: 1) } - //MARK: - CreativeViewDelegate + // MARK: - CreativeViewDelegate + func videoCreativeDidComplete(_ creative: PBMAbstractCreative) {} func creativeDidComplete(_ creative:PBMAbstractCreative) {} func creativeWasClicked(_ creative: PBMAbstractCreative) {} @@ -164,6 +165,7 @@ class VastEventTrackingTest : XCTestCase, PBMCreativeViewDelegate { func creativeDidDisplay(_ creative: PBMAbstractCreative) {} func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} //MARK: - Utility diff --git a/PrebidMobileTests/RenderingTests/Tests/VASTTests/VideoEventsTest.swift b/PrebidMobileTests/RenderingTests/Tests/VASTTests/VideoEventsTest.swift index 23cf66d30..7924bf52f 100644 --- a/PrebidMobileTests/RenderingTests/Tests/VASTTests/VideoEventsTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/VASTTests/VideoEventsTest.swift @@ -167,6 +167,7 @@ class VideoEventsTest : XCTestCase, PBMCreativeViewDelegate, PBMVideoViewDelegat func learnMoreWasClicked() {} func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} // MARK: - PBMVideoViewDelegate @@ -178,4 +179,5 @@ class VideoEventsTest : XCTestCase, PBMCreativeViewDelegate, PBMVideoViewDelegat } func videoWasClicked() {} + func videoViewCurrentPlayingTime(_ currentPlayingTime: NSNumber) {} } diff --git a/PrebidMobileTests/RenderingTests/Tests/VASTTests/VideoFileTypeTest.swift b/PrebidMobileTests/RenderingTests/Tests/VASTTests/VideoFileTypeTest.swift index 9b4001e5a..1b5ba26c7 100644 --- a/PrebidMobileTests/RenderingTests/Tests/VASTTests/VideoFileTypeTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/VASTTests/VideoFileTypeTest.swift @@ -145,6 +145,8 @@ class VideoFileTypeTest : XCTestCase, PBMCreativeViewDelegate, PBMVideoViewDeleg func creativeViewWasClicked(_ creative: PBMAbstractCreative) {} func creativeFullScreenDidFinish(_ creative: PBMAbstractCreative) {} + func creativeDidSendRewardedEvent(_ creative: PBMAbstractCreative) {} + // MARK: - PBMVideoViewDelegate func videoViewFailedWithError(_ error: Error) {} @@ -155,4 +157,5 @@ class VideoFileTypeTest : XCTestCase, PBMCreativeViewDelegate, PBMVideoViewDeleg } func videoWasClicked() {} + func videoViewCurrentPlayingTime(_ currentPlayingTime: NSNumber) {} } From 486b457bba61b89035224f3267048f4f9eb26785 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Wed, 9 Oct 2024 13:36:23 +0300 Subject: [PATCH 09/18] feat: add rwdd flag to request & update tests and InternalTestApp --- .../PrebidMobileDemoRendering/Model/TestCasesManager.swift | 2 +- .../PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m | 1 + PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.h | 3 +++ PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.m | 2 ++ .../RenderingTests/Tests/PBMCreativeFactoryJobTest.swift | 4 ++-- .../RenderingTests/Tests/PBMORTBAbstractTest.swift | 3 ++- PrebidMobileTests/RenderingTests/Tests/PBMWebViewObjCTest.m | 2 +- 7 files changed, 12 insertions(+), 5 deletions(-) diff --git a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift index d0a3c3c5f..422712970 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift @@ -2060,7 +2060,7 @@ struct TestCaseManager { let rewardedAdController = PrebidRewardedController(rootController: adapterVC) - rewardedAdController.prebidConfigId = "prebid-video-rewarded-endcard-time" + rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time" adapterVC.setup(adapter: rewardedAdController) setupCustomParams(for: rewardedAdController.prebidConfigId) diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m index a2562176e..90076ee04 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMVideoView.m @@ -133,6 +133,7 @@ - (instancetype)initWithCreative:(PBMVideoCreative *)creative { if (self) { self.creative = creative; [self setupWithEventManager:creative.eventManager]; + self.progressBarDuration = [self calculateProgressBarDuration]; } return self; diff --git a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.h b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.h index 92cccb132..82a5f064f 100644 --- a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.h +++ b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.h @@ -97,6 +97,9 @@ NS_ASSUME_NONNULL_BEGIN //support can be assumed. @property (nonatomic, strong) NSNumber *secure; +//Indicates whether the ad is rewarded +@property (nonatomic, strong, nullable) NSNumber *rewarded; + //Array of exchange-specific names of supported iframe busters. //Note: iframebuster is not supported. diff --git a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.m b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.m index 6c6b06010..a0c2f9c9b 100644 --- a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.m +++ b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBImp.m @@ -55,6 +55,7 @@ - (nonnull PBMJsonDictionary *)toJsonDictionary { ret[@"tagid"] = self.tagid; ret[@"clickbrowser"] = self.clickbrowser; ret[@"secure"] = self.secure; + ret[@"rwdd"] = self.rewarded; ret[@"ext"] = [[self extDictionary] nullIfEmpty]; @@ -91,6 +92,7 @@ - (instancetype)initWithJsonDictionary:(nonnull PBMJsonDictionary *)jsonDictiona _tagid = jsonDictionary[@"tagid"]; _clickbrowser = jsonDictionary[@"clickbrowser"]; _secure = jsonDictionary[@"secure"]; + _rewarded = jsonDictionary[@"rwdd"]; _extPrebid = [[PBMORTBImpExtPrebid alloc] initWithJsonDictionary:jsonDictionary[@"ext"][@"prebid"]]; _extSkadn = [[PBMORTBImpExtSkadn alloc] initWithJsonDictionary:jsonDictionary[@"ext"][@"skadn"]]; diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMCreativeFactoryJobTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMCreativeFactoryJobTest.swift index e2d44b3ee..5b3feaf03 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMCreativeFactoryJobTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMCreativeFactoryJobTest.swift @@ -230,8 +230,8 @@ class PBMCreativeFactoryJobTest: XCTestCase { // banner display let transaction = UtilitiesForTesting.createEmptyTransaction() - var adConfig = AdConfiguration() - var model = PBMCreativeModel(adConfiguration: adConfig) + let adConfig = AdConfiguration() + let model = PBMCreativeModel(adConfiguration: adConfig) let finishedCallback = { (job: PBMCreativeFactoryJob, error: Error?) in } diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMORTBAbstractTest.swift b/PrebidMobileTests/RenderingTests/Tests/PBMORTBAbstractTest.swift index f6f4161f7..6b067e50f 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMORTBAbstractTest.swift +++ b/PrebidMobileTests/RenderingTests/Tests/PBMORTBAbstractTest.swift @@ -256,11 +256,12 @@ class PBMORTBAbstractTest : XCTestCase { pbmORTBImp.displaymanager = "MOCK_SDK_NAME" pbmORTBImp.displaymanagerver = "MOCK_SDK_VERSION" pbmORTBImp.instl = 1 + pbmORTBImp.rewarded = 1 pbmORTBImp.tagid = "tagid" pbmORTBImp.secure = 1 pbmORTBImp.extData = ["lookup_words": ["dragon", "flame"]] - codeAndDecode(abstract: pbmORTBImp, expectedString: "{\"clickbrowser\":0,\"displaymanager\":\"MOCK_SDK_NAME\",\"displaymanagerver\":\"MOCK_SDK_VERSION\",\"ext\":{\"data\":{\"lookup_words\":[\"dragon\",\"flame\"]},\"dlp\":1},\"id\":\"\(uuid)\",\"instl\":1,\"native\":{\"ver\":\"1.2\"},\"secure\":1,\"tagid\":\"tagid\"}") + codeAndDecode(abstract: pbmORTBImp, expectedString: "{\"clickbrowser\":0,\"displaymanager\":\"MOCK_SDK_NAME\",\"displaymanagerver\":\"MOCK_SDK_VERSION\",\"ext\":{\"data\":{\"lookup_words\":[\"dragon\",\"flame\"]},\"dlp\":1},\"id\":\"\(uuid)\",\"instl\":1,\"native\":{\"ver\":\"1.2\"},\"rwdd\":1,\"secure\":1,\"tagid\":\"tagid\"}") } func testPBMORTBImpExtSkadnToJsonString() { diff --git a/PrebidMobileTests/RenderingTests/Tests/PBMWebViewObjCTest.m b/PrebidMobileTests/RenderingTests/Tests/PBMWebViewObjCTest.m index 378e98c9b..8695a92da 100644 --- a/PrebidMobileTests/RenderingTests/Tests/PBMWebViewObjCTest.m +++ b/PrebidMobileTests/RenderingTests/Tests/PBMWebViewObjCTest.m @@ -92,7 +92,7 @@ - (void)testEvaluateJSNil { NSString *str = nil; [webView evaluateJavaScript:str]; - [self waitForExpectationsWithTimeout:5.0 handler:nil]; + [self waitForExpectationsWithTimeout:10.0 handler:nil]; } #pragma mark - WKNavigationDelegate From 98593321e689ffd4a241fcdc19cc672a68da70e3 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Thu, 10 Oct 2024 21:34:59 +0300 Subject: [PATCH 10/18] feat: add test cases to apps & minor changes --- .../PrebidDemo.xcodeproj/project.pbxproj | 40 +++ .../AdMobDisplayRewardedViewController.h | 28 ++ .../AdMobDisplayRewardedViewController.m | 89 ++++++ .../AdMob/AdMobVideoRewardedViewController.m | 8 +- .../GAMDisplayRewardedViewController.h | 28 ++ .../GAMDisplayRewardedViewController.m | 58 ++++ .../GAMVideoRewardedViewController.m | 2 +- .../InApp/InAppBannerRewardedViewController.h | 26 ++ .../InApp/InAppBannerRewardedViewController.m | 59 ++++ .../InApp/InAppVideoRewardedViewController.m | 6 +- .../MAX/MAXDisplayRewardedViewController.h | 28 ++ .../MAX/MAXDisplayRewardedViewController.m | 92 +++++++ .../IntegrationCase/AdFormat.h | 1 + .../IntegrationCase/AdFormatDescriptor.m | 2 + .../IntegrationCase/IntegrationCaseManager.m | 44 +++ .../AdMobDisplayRewardedViewController.swift | 81 ++++++ .../AdMobVideoRewardedViewController.swift | 7 +- .../GAMDisplayRewardedViewController.swift | 64 +++++ .../GAMVideoRewardedViewController.swift | 12 +- .../InAppBannerRewardedViewController.swift | 54 ++++ .../InAppDisplayRewardedViewController.swift | 54 ++++ ...oInterstitialLandscapeViewController.swift | 2 +- ...eoInterstitialVerticalViewController.swift | 2 +- .../InAppVideoRewardedViewController.swift | 6 +- .../MAXDisplayRewardedViewController.swift | 83 ++++++ .../MAX/MAXVideoRewardedViewController.swift | 7 +- .../IntegrationCase/AdFormat.swift | 3 + .../IntegrationCaseManager.swift | 40 ++- .../Model/TestCasesManager.swift | 253 ++++++++++-------- .../GAM/PrebidGAMRewardedController.swift | 2 +- .../OpenX/PrebidRewardedController.swift | 3 +- .../Integrations/GAM/RewardedAdUnit.swift | 2 +- .../Integrations/GAM/RewardedConfig.swift | 22 +- .../PBMCacheRenderers/PrebidRenderer.swift | 4 +- .../PBMCore/PBMPrebidParameterBuilder.m | 6 +- 35 files changed, 1079 insertions(+), 139 deletions(-) create mode 100644 Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.h create mode 100644 Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m create mode 100644 Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.h create mode 100644 Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m create mode 100644 Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.h create mode 100644 Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.m create mode 100644 Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.h create mode 100644 Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m create mode 100644 Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift create mode 100644 Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.swift create mode 100644 Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppBannerRewardedViewController.swift create mode 100644 Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppDisplayRewardedViewController.swift create mode 100644 Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXDisplayRewardedViewController.swift diff --git a/Example/PrebidDemo/PrebidDemo.xcodeproj/project.pbxproj b/Example/PrebidDemo/PrebidDemo.xcodeproj/project.pbxproj index b054d5d0d..b5ced847a 100644 --- a/Example/PrebidDemo/PrebidDemo.xcodeproj/project.pbxproj +++ b/Example/PrebidDemo/PrebidDemo.xcodeproj/project.pbxproj @@ -67,6 +67,14 @@ 5344E6C12922A97200A1F582 /* MAXVideoInterstitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5344E6C02922A97200A1F582 /* MAXVideoInterstitialViewController.swift */; }; 5344E6C32922AAE500A1F582 /* MAXVideoRewardedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5344E6C22922AAE500A1F582 /* MAXVideoRewardedViewController.swift */; }; 5344E6C52922AC2C00A1F582 /* MAXNativeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5344E6C42922AC2C00A1F582 /* MAXNativeViewController.swift */; }; + 534C614D2CB7EFD50026119A /* InAppDisplayRewardedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C614C2CB7EFD50026119A /* InAppDisplayRewardedViewController.swift */; }; + 534C614F2CB7F20A0026119A /* GAMDisplayRewardedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C614E2CB7F20A0026119A /* GAMDisplayRewardedViewController.swift */; }; + 534C61552CB7F32D0026119A /* MAXDisplayRewardedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61542CB7F32D0026119A /* MAXDisplayRewardedViewController.swift */; }; + 534C61572CB7F4780026119A /* AdMobDisplayRewardedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61562CB7F4780026119A /* AdMobDisplayRewardedViewController.swift */; }; + 534C615B2CB809F70026119A /* InAppBannerRewardedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C615A2CB809F70026119A /* InAppBannerRewardedViewController.m */; }; + 534C615E2CB84DCB0026119A /* AdMobDisplayRewardedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C615D2CB84DCB0026119A /* AdMobDisplayRewardedViewController.m */; }; + 534C61612CB850FD0026119A /* GAMDisplayRewardedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61602CB850FD0026119A /* GAMDisplayRewardedViewController.m */; }; + 534C61642CB851C10026119A /* MAXDisplayRewardedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61632CB851C10026119A /* MAXDisplayRewardedViewController.m */; }; 539928BF292534EB0078053C /* IntegrationCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 539928BE292534EA0078053C /* IntegrationCase.m */; }; 539928C2292535B70078053C /* AdFormatDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 539928C1292535B70078053C /* AdFormatDescriptor.m */; }; 539928C92925379C0078053C /* IntegrationKindDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 539928C82925379C0078053C /* IntegrationKindDescriptor.m */; }; @@ -273,6 +281,18 @@ 5344E6C02922A97200A1F582 /* MAXVideoInterstitialViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MAXVideoInterstitialViewController.swift; sourceTree = ""; }; 5344E6C22922AAE500A1F582 /* MAXVideoRewardedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MAXVideoRewardedViewController.swift; sourceTree = ""; }; 5344E6C42922AC2C00A1F582 /* MAXNativeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MAXNativeViewController.swift; sourceTree = ""; }; + 534C614C2CB7EFD50026119A /* InAppDisplayRewardedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppDisplayRewardedViewController.swift; sourceTree = ""; }; + 534C614E2CB7F20A0026119A /* GAMDisplayRewardedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GAMDisplayRewardedViewController.swift; sourceTree = ""; }; + 534C61542CB7F32D0026119A /* MAXDisplayRewardedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MAXDisplayRewardedViewController.swift; sourceTree = ""; }; + 534C61562CB7F4780026119A /* AdMobDisplayRewardedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdMobDisplayRewardedViewController.swift; sourceTree = ""; }; + 534C61592CB809F70026119A /* InAppBannerRewardedViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InAppBannerRewardedViewController.h; sourceTree = ""; }; + 534C615A2CB809F70026119A /* InAppBannerRewardedViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InAppBannerRewardedViewController.m; sourceTree = ""; }; + 534C615C2CB84DCB0026119A /* AdMobDisplayRewardedViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AdMobDisplayRewardedViewController.h; sourceTree = ""; }; + 534C615D2CB84DCB0026119A /* AdMobDisplayRewardedViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AdMobDisplayRewardedViewController.m; sourceTree = ""; }; + 534C615F2CB850FD0026119A /* GAMDisplayRewardedViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GAMDisplayRewardedViewController.h; sourceTree = ""; }; + 534C61602CB850FD0026119A /* GAMDisplayRewardedViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GAMDisplayRewardedViewController.m; sourceTree = ""; }; + 534C61622CB851C10026119A /* MAXDisplayRewardedViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MAXDisplayRewardedViewController.h; sourceTree = ""; }; + 534C61632CB851C10026119A /* MAXDisplayRewardedViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MAXDisplayRewardedViewController.m; sourceTree = ""; }; 5354C0C62923E99800DB25EA /* TestUtils.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TestUtils.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 539928BD292534BB0078053C /* IntegrationCase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntegrationCase.h; sourceTree = ""; }; 539928BE292534EA0078053C /* IntegrationCase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntegrationCase.m; sourceTree = ""; }; @@ -536,6 +556,7 @@ 53072B802922753D00228462 /* InAppVideoInterstitialLandscapeViewController.swift */, 53072B7E2922748200228462 /* InAppVideoInterstitialVerticalViewController.swift */, 53072B7C2922733800228462 /* InAppVideoInterstitialViewController.swift */, + 534C614C2CB7EFD50026119A /* InAppDisplayRewardedViewController.swift */, 53072B82292275EF00228462 /* InAppVideoRewardedViewController.swift */, ); path = "In-App"; @@ -558,6 +579,7 @@ 5344E6B629228CE600A1F582 /* AdMobNativeViewController.swift */, 5344E6AE2922885200A1F582 /* AdMobVideoBannerViewController.swift */, 5344E6B229228AAB00A1F582 /* AdMobVideoInterstitialViewController.swift */, + 534C61562CB7F4780026119A /* AdMobDisplayRewardedViewController.swift */, 5344E6B429228B7C00A1F582 /* AdMobVideoRewardedViewController.swift */, ); path = AdMob; @@ -572,6 +594,7 @@ 5344E6C42922AC2C00A1F582 /* MAXNativeViewController.swift */, 5344E6BC2922A67D00A1F582 /* MAXVideoBannerViewController.swift */, 5344E6C02922A97200A1F582 /* MAXVideoInterstitialViewController.swift */, + 534C61542CB7F32D0026119A /* MAXDisplayRewardedViewController.swift */, 5344E6C22922AAE500A1F582 /* MAXVideoRewardedViewController.swift */, ); path = MAX; @@ -642,6 +665,7 @@ 5344E6AA2922826100A1F582 /* GAMNativeViewController.swift */, 5344E6A229227DE100A1F582 /* GAMVideoBannerViewController.swift */, 5344E6A62922808500A1F582 /* GAMVideoInterstitialViewController.swift */, + 534C614E2CB7F20A0026119A /* GAMDisplayRewardedViewController.swift */, 5344E6A82922815000A1F582 /* GAMVideoRewardedViewController.swift */, ); path = RenderingAPI; @@ -791,6 +815,8 @@ 53F35F0829267A30001C1183 /* GAMDisplayInterstitialViewController.m */, 53F35F0A29267C65001C1183 /* GAMVideoInterstitialViewController.h */, 53F35F0B29267C65001C1183 /* GAMVideoInterstitialViewController.m */, + 534C615F2CB850FD0026119A /* GAMDisplayRewardedViewController.h */, + 534C61602CB850FD0026119A /* GAMDisplayRewardedViewController.m */, 53F35F0D29267E36001C1183 /* GAMVideoRewardedViewController.h */, 53F35F0E29267E36001C1183 /* GAMVideoRewardedViewController.m */, 53F35F1029267FEE001C1183 /* GAMNativeViewController.h */, @@ -812,6 +838,8 @@ 53F35F1729268C62001C1183 /* AdMobVideoBannerViewController.m */, 53F35F1D29269668001C1183 /* AdMobVideoInterstitialViewController.h */, 53F35F1E29269668001C1183 /* AdMobVideoInterstitialViewController.m */, + 534C615C2CB84DCB0026119A /* AdMobDisplayRewardedViewController.h */, + 534C615D2CB84DCB0026119A /* AdMobDisplayRewardedViewController.m */, 53F35F202926982E001C1183 /* AdMobVideoRewardedViewController.h */, 53F35F212926982E001C1183 /* AdMobVideoRewardedViewController.m */, ); @@ -830,6 +858,8 @@ 53F35F452926CCD5001C1183 /* MAXDisplayInterstitialViewController.m */, 53F35F472926CFE3001C1183 /* MAXVideoInterstitialViewController.h */, 53F35F482926CFE3001C1183 /* MAXVideoInterstitialViewController.m */, + 534C61622CB851C10026119A /* MAXDisplayRewardedViewController.h */, + 534C61632CB851C10026119A /* MAXDisplayRewardedViewController.m */, 53F35F4A2926D130001C1183 /* MAXVideoRewardedViewController.h */, 53F35F4B2926D130001C1183 /* MAXVideoRewardedViewController.m */, 53F35F4D2926D5C0001C1183 /* MAXNativeViewController.h */, @@ -853,6 +883,8 @@ 53F35F332926BAFE001C1183 /* InAppVideoInterstitialVerticalViewController.m */, 53F35F352926BCAF001C1183 /* InAppVideoInterstitialLandscapeViewController.h */, 53F35F362926BCAF001C1183 /* InAppVideoInterstitialLandscapeViewController.m */, + 534C61592CB809F70026119A /* InAppBannerRewardedViewController.h */, + 534C615A2CB809F70026119A /* InAppBannerRewardedViewController.m */, 53F35F382926BDB7001C1183 /* InAppVideoRewardedViewController.h */, 53F35F392926BDB7001C1183 /* InAppVideoRewardedViewController.m */, 53F35F3B2926BF39001C1183 /* InAppNativeViewController.h */, @@ -1476,6 +1508,7 @@ 5344E6C32922AAE500A1F582 /* MAXVideoRewardedViewController.swift in Sources */, 53072B6929217D1800228462 /* GAMOriginalAPIVideoInstreamViewController.swift in Sources */, 5344E6A92922815000A1F582 /* GAMVideoRewardedViewController.swift in Sources */, + 534C61572CB7F4780026119A /* AdMobDisplayRewardedViewController.swift in Sources */, 53072B7B292270EE00228462 /* InAppDisplayInterstitialViewController.swift in Sources */, 53072B5E2921522000228462 /* GAMOriginalAPIVideoRewardedViewController.swift in Sources */, 530D4AA6291A4BC600A2C796 /* AppDelegate.swift in Sources */, @@ -1484,6 +1517,7 @@ 53072B812922753D00228462 /* InAppVideoInterstitialLandscapeViewController.swift in Sources */, 5344E6C12922A97200A1F582 /* MAXVideoInterstitialViewController.swift in Sources */, 53072B7D2922733800228462 /* InAppVideoInterstitialViewController.swift in Sources */, + 534C614F2CB7F20A0026119A /* GAMDisplayRewardedViewController.swift in Sources */, 5344E6C52922AC2C00A1F582 /* MAXNativeViewController.swift in Sources */, 53B03DA5291BCCE1000117E1 /* GAMOriginalAPIDisplayBannerViewController.swift in Sources */, 53A368F82AB8482300A03B3E /* GAMOriginalAPIMultiformatInAppNativeViewController.swift in Sources */, @@ -1504,7 +1538,9 @@ 53072B592921023E00228462 /* InterstitialBaseViewController.swift in Sources */, 53072B672921726C00228462 /* GAMOriginalAPINativeViewController.swift in Sources */, 53072B732922621600228462 /* GAMOriginalAPIVideoBannerViewController.swift in Sources */, + 534C61552CB7F32D0026119A /* MAXDisplayRewardedViewController.swift in Sources */, 53072B6529215D4200228462 /* GAMOriginalAPINativeBannerViewController.swift in Sources */, + 534C614D2CB7EFD50026119A /* InAppDisplayRewardedViewController.swift in Sources */, 5344E6A129227BFE00A1F582 /* GAMDisplayBannerViewController.swift in Sources */, 530D4AA8291A4BC600A2C796 /* SceneDelegate.swift in Sources */, 5344E6BF2922A79000A1F582 /* MAXDisplayInterstitialViewController.swift in Sources */, @@ -1531,6 +1567,7 @@ 53BA02BA292531D000BE6015 /* ExamplesViewController.m in Sources */, 5399290429264C5A0078053C /* GAMOriginalAPIVideoInstreamViewController.m in Sources */, 53F35F2E2926A6D6001C1183 /* InAppDisplayInterstitialViewController.m in Sources */, + 534C615E2CB84DCB0026119A /* AdMobDisplayRewardedViewController.m in Sources */, 53F35F1229267FEE001C1183 /* GAMNativeViewController.m in Sources */, 53F35F06292675A0001C1183 /* GAMVideoBannerViewController.m in Sources */, 539928BF292534EB0078053C /* IntegrationCase.m in Sources */, @@ -1542,6 +1579,7 @@ 53A369012AB8CDEB00A03B3E /* GAMOriginalAPIMultiformatInAppNativeViewController.m in Sources */, 539928DB29254F2A0078053C /* BannerBaseViewController.m in Sources */, 53F35F57292792D6001C1183 /* SettingsViewController.m in Sources */, + 534C61642CB851C10026119A /* MAXDisplayRewardedViewController.m in Sources */, 539928E22925505B0078053C /* InterstitialBaseViewController.m in Sources */, 53F35F432926C84E001C1183 /* MAXVideoBannerViewController.m in Sources */, 5399290A292665D80078053C /* GAMOriginalAPINativeViewController.m in Sources */, @@ -1549,6 +1587,7 @@ 539F960629DEEA0A0061E7A5 /* GAMOriginalAPIMultiformatBannerViewController.m in Sources */, 53BA02B4292531D000BE6015 /* AppDelegate.m in Sources */, 539929072926580B0078053C /* GAMOriginalAPINativeBannerViewController.m in Sources */, + 534C615B2CB809F70026119A /* InAppBannerRewardedViewController.m in Sources */, 53F35F492926CFE3001C1183 /* MAXVideoInterstitialViewController.m in Sources */, 53F35F03292671E7001C1183 /* GAMDisplayBannerViewController.m in Sources */, 533784CC2AC2CFF5009A8650 /* GAMOriginalAPIMultiformatNativeStylesViewController.m in Sources */, @@ -1562,6 +1601,7 @@ 53F35F152926845C001C1183 /* AdMobDisplayBannerViewController.m in Sources */, 539928F12925519D0078053C /* InstreamBaseViewController.m in Sources */, 53F35F222926982E001C1183 /* AdMobVideoRewardedViewController.m in Sources */, + 534C61612CB850FD0026119A /* GAMDisplayRewardedViewController.m in Sources */, 53F35F402926C2B7001C1183 /* MAXDisplayBannerViewController.m in Sources */, 539928CC292539700078053C /* IntegrationCaseManager.m in Sources */, 53F35F372926BCAF001C1183 /* InAppVideoInterstitialLandscapeViewController.m in Sources */, diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.h b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.h new file mode 100644 index 000000000..2587466e5 --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.h @@ -0,0 +1,28 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "InterstitialBaseViewController.h" + +@import GoogleMobileAds; +@import PrebidMobile; +@import PrebidMobileAdMobAdapters; + +NS_ASSUME_NONNULL_BEGIN + +@interface AdMobDisplayRewardedViewController : InterstitialBaseViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m new file mode 100644 index 000000000..6ffd2c774 --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m @@ -0,0 +1,89 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "AdMobDisplayRewardedViewController.h" +#import "PrebidDemoMacros.h" + +NSString * const storedImpDisplayRewardedAdMob = @"prebid-demo-banner-rewarded-time"; +NSString * const adMobAdUnitDisplayRewardedId = @"ca-app-pub-5922967660082475/7397370641"; + +@interface AdMobDisplayRewardedViewController () + +// Prebid +@property (nonatomic) MediationRewardedAdUnit * admobRewardedAdUnit; +@property (nonatomic) AdMobMediationRewardedUtils * mediationDelegate; + +// AdMob +@property (nonatomic) GADRewardedAd * gadRewardedAd; + +@end + +@implementation AdMobDisplayRewardedViewController + +- (void)loadView { + [super loadView]; + + [self createAd]; +} + +- (void)createAd { + // 1. Create a GADRequest + GADRequest * gadRequest = [GADRequest new]; + + // 2. Create an AdMobMediationRewardedUtils + self.mediationDelegate = [[AdMobMediationRewardedUtils alloc] initWithGadRequest:gadRequest]; + + // 3. Create a MediationRewardedAdUnit + self.admobRewardedAdUnit = [[MediationRewardedAdUnit alloc] initWithConfigId:storedImpDisplayRewardedAdMob + mediationDelegate:self.mediationDelegate]; + + // 4. Make a bid request to Prebid Server + @weakify(self); + [self.admobRewardedAdUnit fetchDemandWithCompletion:^(enum ResultCode resultCode) { + @strongify(self); + + // 5. Load the rewarded ad + @weakify(self); + [GADRewardedAd loadWithAdUnitID:adMobAdUnitDisplayRewardedId + request:gadRequest + completionHandler:^(GADRewardedAd * _Nullable rewardedAd, NSError * _Nullable error) { + @strongify(self); + if (!self) { return; } + + if (error != nil) { + PBMLogError(@"%@", error.localizedDescription); + return; + } + + // 6. Present the rewarded ad + if (rewardedAd != nil) { + self.gadRewardedAd = rewardedAd; + self.gadRewardedAd.fullScreenContentDelegate = self; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self.gadRewardedAd presentFromRootViewController:self userDidEarnRewardHandler:^{ + }]; + }); + } + }]; + }]; +} + +// MARK: - GADFullScreenContentDelegate + +- (void)ad:(id)ad didFailToPresentFullScreenContentWithError:(NSError *)error { + PBMLogError(@"%@", error.localizedDescription); +} + +@end diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m index 2fbb0ebe9..e2df00a21 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m @@ -16,8 +16,8 @@ #import "AdMobVideoRewardedViewController.h" #import "PrebidDemoMacros.h" -NSString * const storedImpVideoRewardedAdMob = @"prebid-demo-video-rewarded-320-480"; -NSString * const adMobAdUnitRewardedId = @"ca-app-pub-5922967660082475/7397370641"; +NSString * const storedImpVideoRewardedAdMob = @"prebid-demo-video-rewarded-endcard-time"; +NSString * const adMobAdUnitVideoRewardedId = @"ca-app-pub-5922967660082475/7397370641"; @interface AdMobVideoRewardedViewController () @@ -55,7 +55,9 @@ - (void)createAd { // 5. Load the rewarded ad @weakify(self); - [GADRewardedAd loadWithAdUnitID:adMobAdUnitRewardedId request:gadRequest completionHandler:^(GADRewardedAd * _Nullable rewardedAd, NSError * _Nullable error) { + [GADRewardedAd loadWithAdUnitID:adMobAdUnitVideoRewardedId + request:gadRequest + completionHandler:^(GADRewardedAd * _Nullable rewardedAd, NSError * _Nullable error) { @strongify(self); if (!self) { return; } diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.h b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.h new file mode 100644 index 000000000..dff54e985 --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.h @@ -0,0 +1,28 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "InterstitialBaseViewController.h" + +@import GoogleMobileAds; +@import PrebidMobile; +@import PrebidMobileGAMEventHandlers; + +NS_ASSUME_NONNULL_BEGIN + +@interface GAMDisplayRewardedViewController : InterstitialBaseViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m new file mode 100644 index 000000000..ce8dd10c2 --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m @@ -0,0 +1,58 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "GAMDisplayRewardedViewController.h" + +NSString * const storedImpGAMDisplayRewarded = @"prebid-demo-banner-rewarded-time"; +NSString * const gamAdUnitDisplayRewardedRendering = @"/21808260008/prebid_oxb_rewarded_video_test"; + +@interface GAMDisplayRewardedViewController () + +// Prebid +@property (nonatomic) RewardedAdUnit * rewardedAdUnit; + +@end + +@implementation GAMDisplayRewardedViewController + +- (void)loadView { + [super loadView]; + + [self createAd]; +} + +- (void)createAd { + // 1. Create a GAMRewardedAdEventHandler + GAMRewardedAdEventHandler * eventHandler = [[GAMRewardedAdEventHandler alloc] initWithAdUnitID:gamAdUnitDisplayRewardedRendering]; + + // 2. Create a RewardedAdUnit + self.rewardedAdUnit = [[RewardedAdUnit alloc] initWithConfigID:storedImpGAMDisplayRewarded eventHandler:eventHandler]; + self.rewardedAdUnit.delegate = self; + + // 3. Load the rewarded ad + [self.rewardedAdUnit loadAd]; +} + +// MARK: - RewardedAdUnitDelegate + +- (void)rewardedAdDidReceiveAd:(RewardedAdUnit *)rewardedAd { + [self.rewardedAdUnit showFrom:self]; +} + +- (void)rewardedAd:(RewardedAdUnit *)rewardedAd didFailToReceiveAdWithError:(NSError *)error { + PBMLogError(@"%@", error.localizedDescription); +} + +@end diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m index acf2fbcfc..7056dbb62 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m @@ -15,7 +15,7 @@ #import "GAMVideoRewardedViewController.h" -NSString * const storedImpGAMVideoRewarded = @"prebid-demo-video-rewarded-320-480"; +NSString * const storedImpGAMVideoRewarded = @"prebid-demo-video-rewarded-endcard-time"; NSString * const gamAdUnitVideoRewardedRendering = @"/21808260008/prebid_oxb_rewarded_video_test"; @interface GAMVideoRewardedViewController () diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.h b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.h new file mode 100644 index 000000000..8e154366d --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.h @@ -0,0 +1,26 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "InterstitialBaseViewController.h" + +@import PrebidMobile; + +NS_ASSUME_NONNULL_BEGIN + +@interface InAppBannerRewardedViewController : InterstitialBaseViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.m new file mode 100644 index 000000000..c271c8adc --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.m @@ -0,0 +1,59 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "InAppBannerRewardedViewController.h" +#import "PrebidDemoMacros.h" + +NSString * const storedImpBannerRewardedInApp = @"prebid-demo-banner-rewarded-time"; + +@interface InAppBannerRewardedViewController () + +// Prebid +@property (nonatomic) RewardedAdUnit * rewardedAdUnit; + +@end + +@implementation InAppBannerRewardedViewController + +- (void)loadView { + [super loadView]; + + [self createAd]; +} + +- (void)createAd { + // 1. Create a RewardedAdUnit + self.rewardedAdUnit = [[RewardedAdUnit alloc] initWithConfigID:storedImpBannerRewardedInApp]; + self.rewardedAdUnit.delegate = self; + + // 2. Load the rewarded ad + [self.rewardedAdUnit loadAd]; +} + +// MARK: - RewardedAdUnitDelegate + +- (void)rewardedAdDidReceiveAd:(RewardedAdUnit *)rewardedAd { + [self.rewardedAdUnit showFrom:self]; +} + +- (void)rewardedAd:(RewardedAdUnit *)rewardedAd didFailToReceiveAdWithError:(NSError *)error { + PBMLogError(@"%@", error.localizedDescription); +} + +- (void)rewardedAdUserDidEarnReward:(RewardedAdUnit *)rewardedAd reward:(PrebidReward *)reward { + NSLog(@"User did earn reward - type: %@, count: %f", reward.type, [reward.count doubleValue]); +} + +@end diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppVideoRewardedViewController.m index 8d67ce90c..8f8e5c389 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppVideoRewardedViewController.m @@ -16,7 +16,7 @@ #import "InAppVideoRewardedViewController.h" #import "PrebidDemoMacros.h" -NSString * const storedImpVideoRewardedInApp = @"prebid-demo-video-rewarded-320-480"; +NSString * const storedImpVideoRewardedInApp = @"prebid-demo-video-rewarded-endcard-time"; @interface InAppVideoRewardedViewController () @@ -52,4 +52,8 @@ - (void)rewardedAd:(RewardedAdUnit *)rewardedAd didFailToReceiveAdWithError:(NSE PBMLogError(@"%@", error.localizedDescription); } +- (void)rewardedAdUserDidEarnReward:(RewardedAdUnit *)rewardedAd reward:(PrebidReward *)reward { + NSLog(@"User did earn reward - type: %@, count: %f", reward.type, [reward.count doubleValue]); +} + @end diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.h b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.h new file mode 100644 index 000000000..48baf028f --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.h @@ -0,0 +1,28 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "InterstitialBaseViewController.h" + +@import AppLovinSDK; +@import PrebidMobile; +@import PrebidMobileMAXAdapters; + +NS_ASSUME_NONNULL_BEGIN + +@interface MAXDisplayRewardedViewController : InterstitialBaseViewController + +@end + +NS_ASSUME_NONNULL_END diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m new file mode 100644 index 000000000..7f7b64ab6 --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m @@ -0,0 +1,92 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MAXDisplayRewardedViewController.h" +#import "PrebidDemoMacros.h" + +NSString * const storedImpDisplayRewardedMAX = @"prebid-demo-video-rewarded-320-480"; +NSString * const maxAdUnitDisplayRewardedId = @"75edc39e22574a9d"; + +@interface MAXDisplayRewardedViewController () + +// Prebid +@property (nonatomic) MediationRewardedAdUnit * maxRewardedAdUnit; +@property (nonatomic) MAXMediationRewardedUtils * mediationDelegate; + +// MAX +@property (nonatomic) MARewardedAd * maxRewarded; + +@end + +@implementation MAXDisplayRewardedViewController + +- (void)loadView { + [super loadView]; + + [self createAd]; +} + +- (void)createAd { + // 1. Create a MARewardedAd + self.maxRewarded = [MARewardedAd sharedWithAdUnitIdentifier:maxAdUnitDisplayRewardedId]; + + // 2. Create a MAXMediationRewardedUtils + self.mediationDelegate = [[MAXMediationRewardedUtils alloc] initWithRewardedAd:self.maxRewarded]; + + // 3. Create a MediationRewardedAdUnit + self.maxRewardedAdUnit = [[MediationRewardedAdUnit alloc] initWithConfigId:storedImpDisplayRewardedMAX + mediationDelegate:self.mediationDelegate]; + + // 4. Make a bid request to Prebid Server + @weakify(self); + [self.maxRewardedAdUnit fetchDemandWithCompletion:^(enum ResultCode resultCode) { + @strongify(self); + if (!self) { return; } + + // 5. Load the rewarded ad + self.maxRewarded.delegate = self; + [self.maxRewarded loadAd]; + }]; +} + +// MARK: - MARewardedAdDelegate + +- (void)didLoadAd:(MAAd *)ad { + if (self.maxRewarded != nil && self.maxRewarded.isReady) { + [self.maxRewarded showAd]; + } +} + +- (void)didFailToDisplayAd:(MAAd *)ad withError:(MAError *)error { + PBMLogError(@"%@", error.message); +} + +- (void)didFailToLoadAdForAdUnitIdentifier:(NSString *)adUnitIdentifier withError:(MAError *)error { + PBMLogError(@"%@", error.message); +} + +- (void)didDisplayAd:(MAAd *)ad { +} + +- (void)didHideAd:(MAAd *)ad { +} + +- (void)didClickAd:(MAAd *)ad { +} + +- (void)didRewardUserForAd:(MAAd *)ad withReward:(MAReward *)reward { +} + +@end diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/AdFormat.h b/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/AdFormat.h index e34d3d77a..bb8f5487d 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/AdFormat.h +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/AdFormat.h @@ -21,6 +21,7 @@ typedef NS_ENUM(NSUInteger, AdFormat) { AdFormatNativeBanner, AdFormatDisplayInterstitial, AdFormatVideoInterstitial, + AdFormatDisplayRewarded, AdFormatVideoRewarded, AdFormatVideoInstream, AdFormatNative, diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/AdFormatDescriptor.m b/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/AdFormatDescriptor.m index c026f4a05..c61e45dfc 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/AdFormatDescriptor.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/AdFormatDescriptor.m @@ -30,6 +30,8 @@ + (NSString *)getDescriptionForAdFormat:(AdFormat)adFormat { return @"Display Interstitial"; case AdFormatVideoInterstitial: return @"Video Interstitial"; + case AdFormatDisplayRewarded: + return @"Display Rewarded"; case AdFormatVideoRewarded: return @"Video Rewarded"; case AdFormatVideoInstream: diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/IntegrationCaseManager.m b/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/IntegrationCaseManager.m index 0aad45540..17cdc1b2c 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/IntegrationCaseManager.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/IntegrationCaseManager.m @@ -35,6 +35,7 @@ #import "InAppVideoInterstitialViewController.h" #import "InAppVideoInterstitialVerticalViewController.h" #import "InAppVideoInterstitialLandscapeViewController.h" +#import "InAppBannerRewardedViewController.h" #import "InAppVideoRewardedViewController.h" #import "InAppNativeViewController.h" @@ -42,6 +43,7 @@ #import "GAMVideoBannerViewController.h" #import "GAMDisplayInterstitialViewController.h" #import "GAMVideoInterstitialViewController.h" +#import "GAMDisplayRewardedViewController.h" #import "GAMVideoRewardedViewController.h" #import "GAMNativeViewController.h" @@ -49,6 +51,7 @@ #import "AdMobVideoBannerViewController.h" #import "AdMobDisplayInterstitialViewController.h" #import "AdMobVideoInterstitialViewController.h" +#import "AdMobDisplayRewardedViewController.h" #import "AdMobVideoRewardedViewController.h" #import "AdMobNativeViewController.h" @@ -56,6 +59,7 @@ #import "MAXVideoBannerViewController.h" #import "MAXDisplayInterstitialViewController.h" #import "MAXVideoInterstitialViewController.h" +#import "MAXDisplayRewardedViewController.h" #import "MAXVideoRewardedViewController.h" #import "MAXNativeViewController.h" @@ -246,6 +250,16 @@ @implementation IntegrationCaseManager } ], + [ + [IntegrationCase alloc] + initWithTitle:@"In-App Banner Rewarded 320x480" + integrationKind:IntegrationKindInApp + adFormat:AdFormatVideoRewarded + configurationClosure:^UIViewController *{ + return [[InAppBannerRewardedViewController alloc] init]; + } + ], + [ [IntegrationCase alloc] initWithTitle:@"In-App Video Rewarded 320x480" @@ -306,6 +320,16 @@ @implementation IntegrationCaseManager } ], + [ + [IntegrationCase alloc] + initWithTitle:@"GAM Display Rewarded 320x480" + integrationKind:IntegrationKindGAM + adFormat:AdFormatDisplayRewarded + configurationClosure:^UIViewController *{ + return [[GAMDisplayRewardedViewController alloc] init]; + } + ], + [ [IntegrationCase alloc] initWithTitle:@"GAM Video Rewarded 320x480" @@ -366,6 +390,16 @@ @implementation IntegrationCaseManager } ], + [ + [IntegrationCase alloc] + initWithTitle:@"AdMob Display Rewarded 320x480" + integrationKind:IntegrationKindAdMob + adFormat:AdFormatDisplayRewarded + configurationClosure:^UIViewController *{ + return [[AdMobDisplayRewardedViewController alloc] init]; + } + ], + [ [IntegrationCase alloc] initWithTitle:@"AdMob Video Rewarded 320x480" @@ -426,6 +460,16 @@ @implementation IntegrationCaseManager } ], + [ + [IntegrationCase alloc] + initWithTitle:@"MAX Display Rewarded 320x480" + integrationKind:IntegrationKindMAX + adFormat:AdFormatDisplayRewarded + configurationClosure:^UIViewController *{ + return [[MAXDisplayRewardedViewController alloc] init]; + } + ], + [ [IntegrationCase alloc] initWithTitle:@"MAX Video Rewarded 320x480" diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift new file mode 100644 index 000000000..0cb51a328 --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift @@ -0,0 +1,81 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit +import PrebidMobile +import GoogleMobileAds +import PrebidMobileAdMobAdapters + +fileprivate let storedImpDisplayRewarded = "prebid-demo-banner-rewarded-time" +fileprivate let adMobAdUnitRewardedId = "ca-app-pub-5922967660082475/7397370641" + +class AdMobDisplayRewardedViewController: InterstitialBaseViewController, GADFullScreenContentDelegate { + + // Prebid + private var mediationDelegate: AdMobMediationRewardedUtils! + private var admobRewardedAdUnit: MediationRewardedAdUnit! + + // AdMob + private var gadRewardedAd: GADRewardedAd? + + override func loadView() { + super.loadView() + + createAd() + } + + func createAd() { + // 1. Create a GADRequest + let request = GADRequest() + + // 2. Create an AdMobMediationRewardedUtils + mediationDelegate = AdMobMediationRewardedUtils(gadRequest: request) + + // 3. Create a MediationRewardedAdUnit + admobRewardedAdUnit = MediationRewardedAdUnit( + configId: storedImpDisplayRewarded, + mediationDelegate: mediationDelegate + ) + + // 4. Make a bid request to Prebid Server + admobRewardedAdUnit.fetchDemand { [weak self] result in + guard let self = self else { return } + PrebidDemoLogger.shared.info("Prebid demand fetch for AdMob \(result.name())") + + // 5. Load the rewarded ad + GADRewardedAd.load(withAdUnitID: adMobAdUnitRewardedId, request: request) { [weak self] ad, error in + guard let self = self else { return } + + if let error = error { + Log.error(error.localizedDescription) + return + } + + // 6. Present the rewarded ad + self.gadRewardedAd = ad + self.gadRewardedAd?.fullScreenContentDelegate = self + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { + self.gadRewardedAd?.present(fromRootViewController: self, userDidEarnRewardHandler: {}) + } + } + } + } + + // MARK: - GADFullScreenContentDelegate + + func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) { + PrebidDemoLogger.shared.error("AdMob did fail to receive ad with error: \(error.localizedDescription)") + } +} diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift index 009350dd4..8386adf1a 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift @@ -18,7 +18,7 @@ import PrebidMobile import GoogleMobileAds import PrebidMobileAdMobAdapters -fileprivate let storedImpVideoRewarded = "prebid-demo-video-rewarded-320-480" +fileprivate let storedImpVideoRewarded = "prebid-demo-video-rewarded-endcard-time" fileprivate let adMobAdUnitRewardedId = "ca-app-pub-5922967660082475/7397370641" class AdMobVideoRewardedViewController: InterstitialBaseViewController, GADFullScreenContentDelegate { @@ -64,7 +64,10 @@ class AdMobVideoRewardedViewController: InterstitialBaseViewController, GADFullS self.gadRewardedAd = ad self.gadRewardedAd?.fullScreenContentDelegate = self DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { - self.gadRewardedAd?.present(fromRootViewController: self, userDidEarnRewardHandler: {}) + self.gadRewardedAd?.present( + fromRootViewController: self, + userDidEarnRewardHandler: {} + ) } } } diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.swift new file mode 100644 index 000000000..398b24941 --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.swift @@ -0,0 +1,64 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit +import GoogleMobileAds +import PrebidMobile +import PrebidMobileGAMEventHandlers + +fileprivate let storedImpDisplayRewarded = "prebid-demo-banner-rewarded-time" +fileprivate let gamAdUnitBannerRewardedRendering = "/21808260008/prebid_oxb_rewarded_video_test" + +class GAMDisplayRewardedViewController: InterstitialBaseViewController, RewardedAdUnitDelegate { + + // Prebid + private var rewardedAdUnit: RewardedAdUnit! + + override func loadView() { + super.loadView() + + createAd() + } + + func createAd() { + // 1. Create a GAMRewardedAdEventHandler + let eventHandler = GAMRewardedAdEventHandler(adUnitID: gamAdUnitBannerRewardedRendering) + + // 2. Create a RewardedAdUnit + rewardedAdUnit = RewardedAdUnit( + configID: storedImpDisplayRewarded, + eventHandler: eventHandler + ) + + rewardedAdUnit.delegate = self + + // 3. Load the rewarded ad + rewardedAdUnit.loadAd() + } + + // MARK: - RewardedAdUnitDelegate + + func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { + rewardedAdUnit.show(from: self) + } + + func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { + PrebidDemoLogger.shared.error("Rewarded ad unit failed to receive ad with error: \(error?.localizedDescription ?? "")") + } + + func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) { + PrebidDemoLogger.shared.info("User did earn reward: type - \(reward.type ?? ""), count - \(reward.count ?? 0)") + } +} diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.swift index 292f6c367..6645321e1 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.swift @@ -18,7 +18,7 @@ import GoogleMobileAds import PrebidMobile import PrebidMobileGAMEventHandlers -fileprivate let storedImpVideoRewarded = "prebid-demo-video-rewarded-320-480" +fileprivate let storedImpVideoRewarded = "prebid-demo-video-rewarded-endcard-time" fileprivate let gamAdUnitVideoRewardedRendering = "/21808260008/prebid_oxb_rewarded_video_test" class GAMVideoRewardedViewController: InterstitialBaseViewController, RewardedAdUnitDelegate { @@ -37,7 +37,11 @@ class GAMVideoRewardedViewController: InterstitialBaseViewController, RewardedAd let eventHandler = GAMRewardedAdEventHandler(adUnitID: gamAdUnitVideoRewardedRendering) // 2. Create a RewardedAdUnit - rewardedAdUnit = RewardedAdUnit(configID: storedImpVideoRewarded, eventHandler: eventHandler) + rewardedAdUnit = RewardedAdUnit( + configID: storedImpVideoRewarded, + eventHandler: eventHandler + ) + rewardedAdUnit.delegate = self // 3. Load the rewarded ad @@ -53,4 +57,8 @@ class GAMVideoRewardedViewController: InterstitialBaseViewController, RewardedAd func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { PrebidDemoLogger.shared.error("Rewarded ad unit failed to receive ad with error: \(error?.localizedDescription ?? "")") } + + func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) { + PrebidDemoLogger.shared.info("User did earn reward: type - \(reward.type ?? ""), count - \(reward.count ?? 0)") + } } diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppBannerRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppBannerRewardedViewController.swift new file mode 100644 index 000000000..a5f612eb3 --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppBannerRewardedViewController.swift @@ -0,0 +1,54 @@ +/* Copyright 2019-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit +import PrebidMobile + +fileprivate let storedImpBannerRewarded = "prebid-demo-banner-rewarded-time" + +class InAppDisplayRewardedViewController: InterstitialBaseViewController, RewardedAdUnitDelegate { + + // Prebid + private var rewardedAdUnit: RewardedAdUnit! + + override func loadView() { + super.loadView() + + createAd() + } + + func createAd() { + // 1. Create a RewardedAdUnit + rewardedAdUnit = RewardedAdUnit(configID: storedImpBannerRewarded) + rewardedAdUnit.delegate = self + + // 2. Load the rewarded ad + rewardedAdUnit.loadAd() + } + + // MARK: - RewardedAdUnitDelegate + + func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { + rewardedAdUnit.show(from: self) + } + + func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { + PrebidDemoLogger.shared.error("Rewarded ad unit did fail to receive ad: \(error?.localizedDescription ?? "")") + } + + func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) { + PrebidDemoLogger.shared.info("User did earn reward: type - \(reward.type ?? ""), count - \(reward.count ?? 0)") + } +} diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppDisplayRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppDisplayRewardedViewController.swift new file mode 100644 index 000000000..d7eff816a --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppDisplayRewardedViewController.swift @@ -0,0 +1,54 @@ +/* Copyright 2019-2024 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit +import PrebidMobile + +fileprivate let storedImpDisplayRewarded = "prebid-demo-banner-rewarded-time" + +class InAppDisplayRewardedViewController: InterstitialBaseViewController, RewardedAdUnitDelegate { + + // Prebid + private var rewardedAdUnit: RewardedAdUnit! + + override func loadView() { + super.loadView() + + createAd() + } + + func createAd() { + // 1. Create a RewardedAdUnit + rewardedAdUnit = RewardedAdUnit(configID: storedImpDisplayRewarded) + rewardedAdUnit.delegate = self + + // 2. Load the rewarded ad + rewardedAdUnit.loadAd() + } + + // MARK: - RewardedAdUnitDelegate + + func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { + rewardedAdUnit.show(from: self) + } + + func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { + PrebidDemoLogger.shared.error("Rewarded ad unit did fail to receive ad: \(error?.localizedDescription ?? "")") + } + + func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) { + PrebidDemoLogger.shared.info("User did earn reward: type - \(reward.type ?? ""), count - \(reward.count ?? 0)") + } +} diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoInterstitialLandscapeViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoInterstitialLandscapeViewController.swift index c8e22a589..15a96c647 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoInterstitialLandscapeViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoInterstitialLandscapeViewController.swift @@ -18,7 +18,7 @@ import PrebidMobile fileprivate let storedImpVideoInterstitialLandscape = "prebid-demo-video-interstitial-landscape-with-end-card" -class InAppVideoInterstitialLandscapeViewController: UIViewController { +class InAppVideoInterstitialLandscapeViewController: UIViewController, InterstitialAdUnitDelegate { // Prebid private var renderingInterstitial: InterstitialRenderingAdUnit! diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoInterstitialVerticalViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoInterstitialVerticalViewController.swift index 86914d68f..6fa888fc2 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoInterstitialVerticalViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoInterstitialVerticalViewController.swift @@ -18,7 +18,7 @@ import PrebidMobile fileprivate let storedImpVideoInterstitialVertical = "prebid-demo-video-interstitial-vertical" -class InAppVideoInterstitialVerticalViewController: UIViewController { +class InAppVideoInterstitialVerticalViewController: UIViewController, InterstitialAdUnitDelegate { // Prebid private var renderingInterstitial: InterstitialRenderingAdUnit! diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoRewardedViewController.swift index 35380e902..9f530158e 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoRewardedViewController.swift @@ -16,7 +16,7 @@ import UIKit import PrebidMobile -fileprivate let storedImpVideoRewarded = "prebid-demo-video-rewarded-320-480" +fileprivate let storedImpVideoRewarded = "prebid-demo-video-rewarded-endcard-time" class InAppVideoRewardedViewController: InterstitialBaseViewController, RewardedAdUnitDelegate { @@ -47,4 +47,8 @@ class InAppVideoRewardedViewController: InterstitialBaseViewController, Rewarded func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { PrebidDemoLogger.shared.error("Rewarded ad unit did fail to receive ad: \(error?.localizedDescription ?? "")") } + + func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) { + PrebidDemoLogger.shared.info("User did earn reward: type - \(reward.type ?? ""), count - \(reward.count ?? 0)") + } } diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXDisplayRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXDisplayRewardedViewController.swift new file mode 100644 index 000000000..b2a0ff2f5 --- /dev/null +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXDisplayRewardedViewController.swift @@ -0,0 +1,83 @@ +/* Copyright 2019-2022 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit +import PrebidMobile +import PrebidMobileMAXAdapters +import AppLovinSDK + +fileprivate let storedImpDisplayRewarded = "prebid-demo-banner-rewarded-time" +fileprivate let maxAdUnitRewardedId = "f7a08e702c6bec54" + +class MAXDisplayRewardedViewController: InterstitialBaseViewController, MARewardedAdDelegate { + + // Prebid + private var maxRewardedAdUnit: MediationRewardedAdUnit! + private var mediationDelegate: MAXMediationRewardedUtils! + + // MAX + private var maxRewarded: MARewardedAd! + + override func loadView() { + super.loadView() + + createAd() + } + + func createAd() { + // 1. Create a MARewardedAd + maxRewarded = MARewardedAd.shared(withAdUnitIdentifier: maxAdUnitRewardedId) + + // 2. Create a MAXMediationRewardedUtils + mediationDelegate = MAXMediationRewardedUtils(rewardedAd: maxRewarded) + + // 3. Create a MediationRewardedAdUnit + maxRewardedAdUnit = MediationRewardedAdUnit( + configId: storedImpDisplayRewarded, + mediationDelegate: mediationDelegate + ) + + // 4. Make a bid request to Prebid Server + maxRewardedAdUnit.fetchDemand { [weak self] result in + // 5. Load the rewarded ad + self?.maxRewarded.delegate = self + self?.maxRewarded.load() + } + } + + // MARK: - MARewardedAdDelegate + + func didLoad(_ ad: MAAd) { + if let maxRewarded = maxRewarded, maxRewarded.isReady { + maxRewarded.show() + } + } + + func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { + PrebidDemoLogger.shared.error("\(error.message)") + } + + func didFail(toDisplay ad: MAAd, withError error: MAError) { + PrebidDemoLogger.shared.error("\(error.message)") + } + + func didDisplay(_ ad: MAAd) {} + + func didHide(_ ad: MAAd) {} + + func didClick(_ ad: MAAd) {} + + func didRewardUser(for ad: MAAd, with reward: MAReward) {} +} diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXVideoRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXVideoRewardedViewController.swift index a2d65c0fd..618c50456 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXVideoRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXVideoRewardedViewController.swift @@ -18,7 +18,7 @@ import PrebidMobile import PrebidMobileMAXAdapters import AppLovinSDK -fileprivate let storedImpVideoRewarded = "prebid-demo-video-rewarded-320-480" +fileprivate let storedImpVideoRewarded = "prebid-demo-video-rewarded-endcard-time" fileprivate let maxAdUnitRewardedId = "f7a08e702c6bec54" class MAXVideoRewardedViewController: InterstitialBaseViewController, MARewardedAdDelegate { @@ -44,7 +44,10 @@ class MAXVideoRewardedViewController: InterstitialBaseViewController, MARewarded mediationDelegate = MAXMediationRewardedUtils(rewardedAd: maxRewarded) // 3. Create a MediationRewardedAdUnit - maxRewardedAdUnit = MediationRewardedAdUnit(configId: storedImpVideoRewarded, mediationDelegate: mediationDelegate) + maxRewardedAdUnit = MediationRewardedAdUnit( + configId: storedImpVideoRewarded, + mediationDelegate: mediationDelegate + ) // 4. Make a bid request to Prebid Server maxRewardedAdUnit.fetchDemand { [weak self] result in diff --git a/Example/PrebidDemo/PrebidDemoSwift/IntegrationCase/AdFormat.swift b/Example/PrebidDemo/PrebidDemoSwift/IntegrationCase/AdFormat.swift index d297edd90..aaaa1e4aa 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/IntegrationCase/AdFormat.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/IntegrationCase/AdFormat.swift @@ -22,6 +22,7 @@ enum AdFormat: CustomStringConvertible, CaseIterable { case nativeBanner case displayInterstitial case videoInterstitial + case displayRewarded case videoRewarded case videoInstream case native @@ -39,6 +40,8 @@ enum AdFormat: CustomStringConvertible, CaseIterable { return "Display Interstitial" case .videoInterstitial: return "Video Interstitial" + case .displayRewarded: + return "Display Rewarded" case .videoRewarded: return "Video Rewarded" case .videoInstream: diff --git a/Example/PrebidDemo/PrebidDemoSwift/IntegrationCase/IntegrationCaseManager.swift b/Example/PrebidDemo/PrebidDemoSwift/IntegrationCase/IntegrationCaseManager.swift index 078a85845..1635cec7c 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/IntegrationCase/IntegrationCaseManager.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/IntegrationCase/IntegrationCaseManager.swift @@ -187,6 +187,15 @@ struct IntegrationCaseManager { } ), + IntegrationCase( + title: "In-App Display Rewarded 320x480", + integrationKind: .inApp, + adFormat: .displayRewarded, + configurationClosure: { + InAppDisplayRewardedViewController() + } + ), + IntegrationCase( title: "In-App Video Rewarded 320x480", integrationKind: .inApp, @@ -241,6 +250,15 @@ struct IntegrationCaseManager { } ), + IntegrationCase( + title: "GAM Display Rewarded 320x480", + integrationKind: .gam, + adFormat: .displayRewarded, + configurationClosure: { + GAMDisplayRewardedViewController() + } + ), + IntegrationCase( title: "GAM Video Rewarded 320x480", integrationKind: .gam, @@ -295,6 +313,15 @@ struct IntegrationCaseManager { } ), + IntegrationCase( + title: "AdMob Display Rewarded 320x480", + integrationKind: .adMob, + adFormat: .displayRewarded, + configurationClosure: { + AdMobDisplayRewardedViewController() + } + ), + IntegrationCase( title: "AdMob Video Rewarded 320x480", integrationKind: .adMob, @@ -350,9 +377,18 @@ struct IntegrationCaseManager { ), IntegrationCase( - title: "MAX Rewarded 320x480", + title: "MAX Display Rewarded 320x480", integrationKind: .max, - adFormat: .videoInterstitial, + adFormat: .videoRewarded, + configurationClosure: { + MAXDisplayRewardedViewController() + } + ), + + IntegrationCase( + title: "MAX Video Rewarded 320x480", + integrationKind: .max, + adFormat: .videoRewarded, configurationClosure: { MAXVideoRewardedViewController() } diff --git a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift index 422712970..66613f53e 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift @@ -1954,10 +1954,10 @@ struct TestCaseManager { ]; }), - // MARK: ---- Video Rewarded (In-App) ---- + // MARK: ---- Rewarded (In-App) ---- - TestCase(title: "Video Rewarded 320x480 (In-App)", - tags: [.video, .inapp, .server], + TestCase(title: "Banner Rewarded Default 320x480 (In-App)", + tags: [.interstitial, .inapp, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -1965,15 +1965,13 @@ struct TestCaseManager { } let rewardedAdController = PrebidRewardedController(rootController: adapterVC) - - rewardedAdController.prebidConfigId = "prebid-ita-video-rewarded-320-480" + rewardedAdController.prebidConfigId = "prebid-demo-banner-rewarded-default" adapterVC.setup(adapter: rewardedAdController) - setupCustomParams(for: rewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 (In-App) [SKAdN]", - tags: [.video, .inapp, .server], + TestCase(title: "Banner Rewarded Time 320x480 (In-App)", + tags: [.interstitial, .inapp, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -1981,31 +1979,27 @@ struct TestCaseManager { } let rewardedAdController = PrebidRewardedController(rootController: adapterVC) - Targeting.shared.sourceapp = "InternalTestApp" - - rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-320-480-skadn" - + rewardedAdController.prebidConfigId = "prebid-demo-banner-rewarded-time" adapterVC.setup(adapter: rewardedAdController) - setupCustomParams(for: rewardedAdController.prebidConfigId) }), - - TestCase(title: "Video Rewarded 320x480 (In-App) [noBids]", - tags: [.video, .inapp, .server], - exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in + + TestCase(title: "Banner Rewarded Event 320x480 (In-App)", + tags: [.interstitial, .inapp, .server], + exampleVCStoryboardID: "AdapterViewController", + configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { return } let rewardedAdController = PrebidRewardedController(rootController: adapterVC) - rewardedAdController.prebidConfigId = "prebid-demo-no-bids" + rewardedAdController.prebidConfigId = "prebid-demo-banner-rewarded-event" adapterVC.setup(adapter: rewardedAdController) - setupCustomParams(for: rewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 without End Card (In-App)", - tags: [.video, .inapp, .server], + TestCase(title: "Video Rewarded Default 320x480 (In-App)", + tags: [.interstitial, .video, .inapp, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2013,14 +2007,13 @@ struct TestCaseManager { } let rewardedAdController = PrebidRewardedController(rootController: adapterVC) - rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-320-480-without-end-card" + rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-default" adapterVC.setup(adapter: rewardedAdController) - setupCustomParams(for: rewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 480x320 (In-App)", - tags: [.video, .inapp, .server], + TestCase(title: "Video Rewarded Playbackevent 320x480 (In-App)", + tags: [.interstitial, .video, .inapp, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2028,30 +2021,84 @@ struct TestCaseManager { } let rewardedAdController = PrebidRewardedController(rootController: adapterVC) - rewardedAdController.prebidConfigId = "prebid-ita-video-rewarded-320-480" + rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-playbackevent" adapterVC.setup(adapter: rewardedAdController) - setupCustomParams(for: rewardedAdController.prebidConfigId) }), + TestCase(title: "Video Rewarded Time 320x480 (In-App)", + tags: [.interstitial, .video, .inapp, .server], + exampleVCStoryboardID: "AdapterViewController", + configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { + return + } + + let rewardedAdController = PrebidRewardedController(rootController: adapterVC) + rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time" + adapterVC.setup(adapter: rewardedAdController) + setupCustomParams(for: rewardedAdController.prebidConfigId) + }), - TestCase(title: "Video Rewarded With Ad Configuration Server 320x480 (In-App)", - tags: [.video, .inapp, .server], + TestCase(title: "Video Rewarded Time 320x480 (In-App) [SKAdN]", + tags: [.interstitial, .video, .inapp, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { return } + + Targeting.shared.sourceapp = "InternalTestApp" let rewardedAdController = PrebidRewardedController(rootController: adapterVC) + rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time-skadn" + adapterVC.setup(adapter: rewardedAdController) + setupCustomParams(for: rewardedAdController.prebidConfigId) + }), + + TestCase(title: "Video Rewarded Time With Server Ad Configuration 320x480 (In-App)", + tags: [.interstitial, .video, .inapp, .server], + exampleVCStoryboardID: "AdapterViewController", + configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { + return + } - rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-320-480-with-ad-configuration" + let rewardedAdController = PrebidRewardedController(rootController: adapterVC) + rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time-ad-config" + adapterVC.setup(adapter: rewardedAdController) + setupCustomParams(for: rewardedAdController.prebidConfigId) + }), + + TestCase(title: "Video Rewarded Endcard Default 320x480 (In-App)", + tags: [.interstitial, .video, .inapp, .server], + exampleVCStoryboardID: "AdapterViewController", + configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { + return + } + + let rewardedAdController = PrebidRewardedController(rootController: adapterVC) + rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-endcard-default" + adapterVC.setup(adapter: rewardedAdController) + setupCustomParams(for: rewardedAdController.prebidConfigId) + }), + + TestCase(title: "Video Rewarded Endcard Event 320x480 (In-App)", + tags: [.interstitial, .video, .inapp, .server], + exampleVCStoryboardID: "AdapterViewController", + configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { + return + } + + let rewardedAdController = PrebidRewardedController(rootController: adapterVC) + rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-endcard-event" adapterVC.setup(adapter: rewardedAdController) - setupCustomParams(for: rewardedAdController.prebidConfigId) }), TestCase(title: "Video Rewarded Endcard Time 320x480 (In-App)", - tags: [.video, .inapp, .server], + tags: [.interstitial, .video, .inapp, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2059,52 +2106,60 @@ struct TestCaseManager { } let rewardedAdController = PrebidRewardedController(rootController: adapterVC) - - rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time" + rewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-endcard-time" + adapterVC.setup(adapter: rewardedAdController) + setupCustomParams(for: rewardedAdController.prebidConfigId) + }), + + TestCase(title: "Video Rewarded 320x480 (In-App) [noBids]", + tags: [.interstitial, .video, .inapp, .server], + exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { + return + } + + let rewardedAdController = PrebidRewardedController(rootController: adapterVC) + rewardedAdController.prebidConfigId = "prebid-demo-no-bids" adapterVC.setup(adapter: rewardedAdController) - setupCustomParams(for: rewardedAdController.prebidConfigId) }), - // MARK: ---- Video Rewarded (GAM) ---- + // MARK: ---- Rewarded (GAM) ---- - TestCase(title: "Video Rewarded 320x480 (GAM) [OK, Metadata]", - tags: [.video, .gam, .server], + TestCase(title: "Banner Rewarded Endcard Time 320x480 (GAM) [OK, Metadata]", + tags: [.interstitial, .gam, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { return } let gamRewardedAdController = PrebidGAMRewardedController(rootController: adapterVC) gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_test" - - gamRewardedAdController.prebidConfigId = "prebid-ita-video-rewarded-320-480" - + gamRewardedAdController.prebidConfigId = "prebid-demo-banner-rewarded-time" adapterVC.setup(adapter: gamRewardedAdController) - setupCustomParams(for: gamRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 With Ad Configuration Server (GAM) [OK, Metadata]", - tags: [.video, .gam, .server], + TestCase(title: "Video Rewarded Endcard Time 320x480 (GAM) [OK, Metadata]", + tags: [.interstitial, .video, .gam, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { return } let gamRewardedAdController = PrebidGAMRewardedController(rootController: adapterVC) gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_test" - gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-320-480-with-ad-configuration" - + gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-endcard-time" adapterVC.setup(adapter: gamRewardedAdController) - setupCustomParams(for: gamRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 (GAM) [OK, Random]", - tags: [.video, .gam, .server], + TestCase(title: "Video Rewarded Time 320x480 (GAM) [OK, Metadata]", + tags: [.interstitial, .video, .gam, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2112,15 +2167,14 @@ struct TestCaseManager { } let gamRewardedAdController = PrebidGAMRewardedController(rootController: adapterVC) - gamRewardedAdController.prebidConfigId = "prebid-ita-video-rewarded-320-480" - gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_random" + gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time" + gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_test" adapterVC.setup(adapter: gamRewardedAdController) - setupCustomParams(for: gamRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 (GAM) [noBids, GAM Ad]", - tags: [.video, .gam, .server], + TestCase(title: "Video Rewarded 320x480 Time With Server Ad Configuration (GAM) [OK, Metadata]", + tags: [.interstitial, .video, .gam, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2128,15 +2182,14 @@ struct TestCaseManager { } let gamRewardedAdController = PrebidGAMRewardedController(rootController: adapterVC) - gamRewardedAdController.prebidConfigId = "prebid-demo-no-bids" - gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_static" + gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_test" + gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time-ad-config" adapterVC.setup(adapter: gamRewardedAdController) - setupCustomParams(for: gamRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 without End Card (GAM) [OK, Metadata]", - tags: [.video, .gam, .server], + TestCase(title: "Video Rewarded 320x480 (GAM) [noBids, GAM Ad]", + tags: [.interstitial, .video, .gam, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2144,13 +2197,11 @@ struct TestCaseManager { } let gamRewardedAdController = PrebidGAMRewardedController(rootController: adapterVC) - gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-320-480-without-end-card" - gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_test" + gamRewardedAdController.prebidConfigId = "prebid-demo-no-bids" + gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_static" adapterVC.setup(adapter: gamRewardedAdController) - setupCustomParams(for: gamRewardedAdController.prebidConfigId) }), - // MARK: ---- MRAID (In-App) ---- @@ -2724,7 +2775,6 @@ struct TestCaseManager { admobInterstitialController.adFormats = [.video] admobInterstitialController.adMobAdUnitId = "ca-app-pub-5922967660082475/4527792002" adapterVC.setup(adapter: admobInterstitialController) - setupCustomParams(for: admobInterstitialController.prebidConfigId) }), @@ -2750,10 +2800,10 @@ struct TestCaseManager { setupCustomParams(for: interstitialController.prebidConfigId) }), - // MARK: ---- Video Rewarded (AdMob) ---- + // MARK: ---- Rewarded (AdMob) ---- - TestCase(title: "Video Rewarded 320x480 (AdMob) [OK, OXB Adapter]", - tags: [.video, .admob, .server], + TestCase(title: "Banner Rewarded Time 320x480 (AdMob) [OK, OXB Adapter]", + tags: [.interstitial, .video, .admob, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2762,14 +2812,13 @@ struct TestCaseManager { let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" - admobRewardedAdController.prebidConfigId = "prebid-ita-video-rewarded-320-480" + admobRewardedAdController.prebidConfigId = "prebid-demo-banner-rewarded-time" adapterVC.setup(adapter: admobRewardedAdController) - setupCustomParams(for: admobRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded With Ad Configuration 320x480 Server (AdMob) [OK, OXB Adapter]", - tags: [.video, .admob, .server], + TestCase(title: "Video Rewarded Endcard Time 320x480 (AdMob) [OK, OXB Adapter]", + tags: [.interstitial, .video, .admob, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2778,15 +2827,13 @@ struct TestCaseManager { let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" - admobRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-320-480-with-ad-configuration" - + admobRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-endcard-time" adapterVC.setup(adapter: admobRewardedAdController) - setupCustomParams(for: admobRewardedAdController.prebidConfigId) }), - - TestCase(title: "Video Rewarded 320x480 (AdMob) [noBids, AdMob Ad]", - tags: [.video, .admob, .server], + + TestCase(title: "Video Rewarded Time 320x480 (AdMob) [OK, OXB Adapter]", + tags: [.interstitial, .video, .admob, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2794,15 +2841,14 @@ struct TestCaseManager { } let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) - admobRewardedAdController.prebidConfigId = "prebid-demo-no-bids" + admobRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time" admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" adapterVC.setup(adapter: admobRewardedAdController) - setupCustomParams(for: admobRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 (AdMob) [OK, Random]", - tags: [.video, .admob, .server], + TestCase(title: "Video Rewarded Time With Server Ad Configuration 320x480 (AdMob) [OK, OXB Adapter]", + tags: [.interstitial, .video, .admob, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2810,15 +2856,14 @@ struct TestCaseManager { } let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) - admobRewardedAdController.prebidConfigId = "prebid-ita-video-rewarded-320-480" admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" + admobRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time-ad-config" adapterVC.setup(adapter: admobRewardedAdController) - setupCustomParams(for: admobRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 without End Card (AdMob) [OK, OXB Adapter]", - tags: [.video, .admob, .server], + TestCase(title: "Video Rewarded 320x480 (AdMob) [noBids, AdMob Ad]", + tags: [.interstitial, .video, .admob, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -2826,10 +2871,9 @@ struct TestCaseManager { } let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) - admobRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-320-480-without-end-card" + admobRewardedAdController.prebidConfigId = "prebid-demo-no-bids" admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" adapterVC.setup(adapter: admobRewardedAdController) - setupCustomParams(for: admobRewardedAdController.prebidConfigId) }), @@ -3033,6 +3077,7 @@ struct TestCaseManager { setupCustomParams(for: gamNativeAdController.prebidConfigId) }), + TestCase(title: "Native Ad (GAM) [OK, GADNativeCustomTemplateAd]", tags: [.native, .gam, .server], exampleVCStoryboardID: "AdapterViewController", @@ -3503,10 +3548,10 @@ struct TestCaseManager { setupCustomParams(for: interstitialController.prebidConfigId) }), - // MARK: ---- Video Rewarded (MAX) ---- + // MARK: ---- Rewarded (MAX) ---- - TestCase(title: "Video Rewarded 320x480 (MAX) [OK, OXB Adapter]", - tags: [.video, .max, .server], + TestCase(title: "Banner Rewarded Time 320x480 (MAX) [OK, OXB Adapter]", + tags: [.interstitial, .max, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -3515,14 +3560,13 @@ struct TestCaseManager { let maxRewardedAdController = PrebidMAXRewardedController(rootController: adapterVC) maxRewardedAdController.maxAdUnitId = "8c68716a67d5a5af" - maxRewardedAdController.prebidConfigId = "prebid-ita-video-rewarded-320-480" + maxRewardedAdController.prebidConfigId = "prebid-demo-banner-rewarded-time" adapterVC.setup(adapter: maxRewardedAdController) - setupCustomParams(for: maxRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 With Ad Configuration Server (MAX) [OK, OXB Adapter]", - tags: [.video, .max, .server], + TestCase(title: "Video Rewarded Endcard Time 320x480 (MAX) [OK, OXB Adapter]", + tags: [.interstitial, .video, .max, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -3531,14 +3575,13 @@ struct TestCaseManager { let maxRewardedAdController = PrebidMAXRewardedController(rootController: adapterVC) maxRewardedAdController.maxAdUnitId = "8c68716a67d5a5af" - maxRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-320-480-with-ad-configuration" + maxRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-endcard-time" adapterVC.setup(adapter: maxRewardedAdController) - setupCustomParams(for: maxRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 (MAX) [noBids, MAX Ad]", - tags: [.video, .max, .server], + TestCase(title: "Video Rewarded 320x480 Time (MAX) [OK, OXB Adapter]", + tags: [.interstitial, .video, .max, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -3547,14 +3590,14 @@ struct TestCaseManager { let maxRewardedAdController = PrebidMAXRewardedController(rootController: adapterVC) maxRewardedAdController.maxAdUnitId = "8c68716a67d5a5af" - maxRewardedAdController.prebidConfigId = "prebid-demo-no-bids" + maxRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time" adapterVC.setup(adapter: maxRewardedAdController) setupCustomParams(for: maxRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 (MAX) [OK, Random]", - tags: [.video, .max, .server], + TestCase(title: "Video Rewarded 320x480 Time With Server Ad Configuration (MAX) [OK, OXB Adapter]", + tags: [.interstitial, .video, .max, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -3563,14 +3606,14 @@ struct TestCaseManager { let maxRewardedAdController = PrebidMAXRewardedController(rootController: adapterVC) maxRewardedAdController.maxAdUnitId = "8c68716a67d5a5af" - maxRewardedAdController.prebidConfigId = "prebid-ita-video-rewarded-320-480" + maxRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time-ad-config" adapterVC.setup(adapter: maxRewardedAdController) setupCustomParams(for: maxRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 without End Card (MAX) [OK, OXB Adapter]", - tags: [.video, .max, .server], + TestCase(title: "Video Rewarded 320x480 (MAX) [noBids, MAX Ad]", + tags: [.interstitial, .video, .max, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in guard let adapterVC = vc as? AdapterViewController else { @@ -3579,7 +3622,7 @@ struct TestCaseManager { let maxRewardedAdController = PrebidMAXRewardedController(rootController: adapterVC) maxRewardedAdController.maxAdUnitId = "8c68716a67d5a5af" - maxRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-320-480-without-end-card" + maxRewardedAdController.prebidConfigId = "prebid-demo-no-bids" adapterVC.setup(adapter: maxRewardedAdController) setupCustomParams(for: maxRewardedAdController.prebidConfigId) diff --git a/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/GAM/PrebidGAMRewardedController.swift b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/GAM/PrebidGAMRewardedController.swift index 5561cf56b..377b95879 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/GAM/PrebidGAMRewardedController.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/GAM/PrebidGAMRewardedController.swift @@ -128,7 +128,7 @@ class PrebidGAMRewardedController: NSObject, AdaptedController, PrebidConfigurab rewardedAdDidClickAdButton.isEnabled = true } - func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit) { + func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) { rewardedAdUserDidEarnRewardButton.isEnabled = true } diff --git a/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OpenX/PrebidRewardedController.swift b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OpenX/PrebidRewardedController.swift index 12197916b..6220b9acd 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OpenX/PrebidRewardedController.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OpenX/PrebidRewardedController.swift @@ -124,8 +124,9 @@ class PrebidRewardedController: NSObject, AdaptedController, RewardedAdUnitDeleg rewardedAdDidClickAdButton.isEnabled = true } - func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit) { + func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) { rewardedAdUserDidEarnRewardButton.isEnabled = true + print("Did receive reward: type - \(reward.type ?? ""), count - \(reward.count ?? 0)") } // MARK: - Private Methods diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift index e5567a199..7c4265193 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift @@ -16,7 +16,7 @@ import UIKit /// Represents an rewarded ad unit. Built for rendering type of integration. -@objc +@objc @objcMembers public class RewardedAdUnit: NSObject, BaseInterstitialAdUnitProtocol { /// A delegate for handling interactions with the ad unit. diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedConfig.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedConfig.swift index 636d324a5..cabdbefbb 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedConfig.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedConfig.swift @@ -21,48 +21,48 @@ public class RewardedConfig: NSObject { // MARK: - Reward public var reward: PrebidReward? { - PrebidReward(with: ortbRewarded.reward) + PrebidReward(with: ortbRewarded?.reward) } // MARK: - Banner public var bannerTime: NSNumber? { - ortbRewarded.completion?.banner?.time + ortbRewarded?.completion?.banner?.time } public var bannerEvent: String? { - ortbRewarded.completion?.banner?.event + ortbRewarded?.completion?.banner?.event } // MARK: - Video public var videoTime: NSNumber? { - ortbRewarded.completion?.video?.time + ortbRewarded?.completion?.video?.time } public var videoPlaybackevent: String? { - ortbRewarded.completion?.video?.playbackevent + ortbRewarded?.completion?.video?.playbackevent } // MARK: - Endcard public var endcardTime: NSNumber? { - ortbRewarded.completion?.video?.endcard?.time + ortbRewarded?.completion?.video?.endcard?.time } public var endcardEvent: String? { - ortbRewarded.completion?.video?.endcard?.event + ortbRewarded?.completion?.video?.endcard?.event } // MARK: - Close public var closeAction: String? { - ortbRewarded.close?.action + ortbRewarded?.close?.action } public var postRewardTime: NSNumber? { - ortbRewarded.close?.postrewardtime + ortbRewarded?.close?.postrewardtime } // MARK: - Default Values @@ -73,9 +73,9 @@ public class RewardedConfig: NSObject { /// The playback event when the SDK should send a signal to the application that the user has earned the reward public let defaultVideoPlaybackEvent = "complete" - private let ortbRewarded: PBMORTBRewardedConfiguration + private let ortbRewarded: PBMORTBRewardedConfiguration? - init(ortbRewarded: PBMORTBRewardedConfiguration) { + init(ortbRewarded: PBMORTBRewardedConfiguration?) { self.ortbRewarded = ortbRewarded } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/PrebidRenderer.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/PrebidRenderer.swift index 998034fca..12576bcf7 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/PrebidRenderer.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/PrebidRenderer.swift @@ -85,9 +85,7 @@ public class PrebidRenderer: NSObject, PrebidMobilePluginRenderer { adConfiguration.adConfiguration.winningBidAdFormat = bid.adFormat videoControlsConfig?.initialize(with: bid.videoAdConfiguration) - if let ortbRewardedConfig = bid.rewardedConfig { - adConfiguration.adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: ortbRewardedConfig) - } + adConfiguration.adConfiguration.rewardedConfig = RewardedConfig(ortbRewarded: bid.rewardedConfig) // This part is dedicating to test server-side ad configurations. // Need to be removed when ext.prebid.passthrough will be available. diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m index a8978e73d..67e76ea70 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/PBMPrebidParameterBuilder.m @@ -185,9 +185,13 @@ - (void)buildBidRequest:(nonnull PBMORTBBidRequest *)bidRequest { nextImp.impID = [NSUUID UUID].UUIDString; nextImp.extPrebid.storedRequestID = self.adConfiguration.configId; nextImp.extPrebid.storedAuctionResponse = Prebid.shared.storedAuctionResponse; - nextImp.extPrebid.isRewardedInventory = self.adConfiguration.adConfiguration.isRewarded; nextImp.extGPID = self.adConfiguration.gpid; + nextImp.extPrebid.isRewardedInventory = self.adConfiguration.adConfiguration.isRewarded; + if (self.adConfiguration.adConfiguration.isRewarded) { + nextImp.rewarded = @(1); + } + if ([self.adConfiguration getExtData].count > 0) { nextImp.extData = [self.adConfiguration getExtData].mutableCopy; } From c28a8b15143e29b12048322c4bce874c51d405aa Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Thu, 10 Oct 2024 22:48:06 +0300 Subject: [PATCH 11/18] feat: changes in adapters --- .../EventHandlers.xcodeproj/project.pbxproj | 10 +- .../PrebidAdMobMediationBaseAdapter.swift | 5 +- .../Sources/PrebidAdMobRewardedAdapter.swift | 166 ++++++++++++++++++ .../PrebidAdMobRewardedVideoAdapter.swift | 147 ++-------------- ...nterstitialAdapter+MARewardedAdapter.swift | 164 ++++++++--------- .../AdMobDisplayRewardedViewController.m | 2 +- .../AdMob/AdMobVideoRewardedViewController.m | 2 +- .../AdMobDisplayRewardedViewController.swift | 2 +- .../AdMobVideoRewardedViewController.swift | 2 +- .../Model/TestCasesManager.swift | 10 +- .../GAM/BaseInterstitialAdUnit.swift | 1 + .../Integrations/GAM/BaseRewardedAdUnit.swift | 6 +- .../RewardedEventInteractionDelegate.swift | 4 +- .../InterstitialController.swift | 4 +- ...stitialControllerInteractionDelegate.swift | 3 +- 15 files changed, 285 insertions(+), 243 deletions(-) create mode 100644 EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedAdapter.swift diff --git a/EventHandlers/EventHandlers.xcodeproj/project.pbxproj b/EventHandlers/EventHandlers.xcodeproj/project.pbxproj index 06e83745a..5a8bce74b 100644 --- a/EventHandlers/EventHandlers.xcodeproj/project.pbxproj +++ b/EventHandlers/EventHandlers.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 344A7F0E250B749600743A93 /* GAMRequestWrapperTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344A7F0D250B749600743A93 /* GAMRequestWrapperTest.swift */; }; 344A7F14250B823F00743A93 /* GAMInterstitialAdWrapperTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344A7F13250B823F00743A93 /* GAMInterstitialAdWrapperTest.swift */; }; 344A7F1A250B8E5400743A93 /* GADRewardedAdWrapperTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344A7F19250B8E5400743A93 /* GADRewardedAdWrapperTest.swift */; }; + 534C61682CB861930026119A /* PrebidAdMobRewardedAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61672CB861930026119A /* PrebidAdMobRewardedAdapter.swift */; }; 53632B24290BC57A00139EF3 /* AdMobGMATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53632B23290BC57A00139EF3 /* AdMobGMATests.swift */; }; 53632B2C290BE17300139EF3 /* GMATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53632B2B290BE17300139EF3 /* GMATests.swift */; }; 5B36172626370A8700AFA1C2 /* GAMUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B36172526370A8700AFA1C2 /* GAMUtils.swift */; }; @@ -112,6 +113,7 @@ 34B64D5F24F7E41600FDD9F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 39183ECBC4E402BC48B3691D /* Pods_PrebidMobileGAMEventHandlersTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PrebidMobileGAMEventHandlersTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 42CE6323AC67980202BFDE74 /* Pods-PrebidMobileAdMobAdapters.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PrebidMobileAdMobAdapters.release.xcconfig"; path = "Target Support Files/Pods-PrebidMobileAdMobAdapters/Pods-PrebidMobileAdMobAdapters.release.xcconfig"; sourceTree = ""; }; + 534C61672CB861930026119A /* PrebidAdMobRewardedAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidAdMobRewardedAdapter.swift; sourceTree = ""; }; 53632B23290BC57A00139EF3 /* AdMobGMATests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdMobGMATests.swift; sourceTree = ""; }; 53632B2B290BE17300139EF3 /* GMATests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GMATests.swift; sourceTree = ""; }; 58B193FE14C1F3D7E795F7AC /* Pods-PrebidMobileMAXAdapters.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PrebidMobileMAXAdapters.release.xcconfig"; path = "Target Support Files/Pods-PrebidMobileMAXAdapters/Pods-PrebidMobileMAXAdapters.release.xcconfig"; sourceTree = ""; }; @@ -390,12 +392,13 @@ 92C7A868279AAEF1000D31CB /* AdMobMediationNativeUtils.swift */, 92C474EC2795B57E00C26E27 /* AdMobMediationRewardedUtils.swift */, 92A2380C27731B48000157AA /* AdMobUtils.swift */, + 92C474F42795E1A600C26E27 /* PrebidAdMobMediationBaseAdapter.swift */, 92E924FA2769ED96002B57F3 /* PrebidAdMobBannerAdapter.swift */, 926CBF1B278C837800E07BF2 /* PrebidAdMobInterstitialAdapter.swift */, - 92C474F42795E1A600C26E27 /* PrebidAdMobMediationBaseAdapter.swift */, - 92EB6DE42799FB4700470DEC /* PrebidAdMobNativeAdapter.swift */, - 92DDA43B278EE8EC0035F03E /* PrebidAdMobRewardedVideoAdapter.swift */, 9285B46527AAC5B1009BD3D3 /* PrebidAdMobVideoInterstitialAdapter.swift */, + 534C61672CB861930026119A /* PrebidAdMobRewardedAdapter.swift */, + 92DDA43B278EE8EC0035F03E /* PrebidAdMobRewardedVideoAdapter.swift */, + 92EB6DE42799FB4700470DEC /* PrebidAdMobNativeAdapter.swift */, ); path = Sources; sourceTree = ""; @@ -990,6 +993,7 @@ 9267B400276FCF9300F1ADF1 /* AdMobConstants.swift in Sources */, 92C474F52795E1A600C26E27 /* PrebidAdMobMediationBaseAdapter.swift in Sources */, 92E924FD276A0FD8002B57F3 /* AdMobMediationBannerUtils.swift in Sources */, + 534C61682CB861930026119A /* PrebidAdMobRewardedAdapter.swift in Sources */, 9285B46627AAC5B1009BD3D3 /* PrebidAdMobVideoInterstitialAdapter.swift in Sources */, 92C7A869279AAEF2000D31CB /* AdMobMediationNativeUtils.swift in Sources */, 92E924FF276A193E002B57F3 /* AdMobAdaptersError.swift in Sources */, diff --git a/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobMediationBaseAdapter.swift b/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobMediationBaseAdapter.swift index f58f7f9de..5afad275c 100644 --- a/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobMediationBaseAdapter.swift +++ b/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobMediationBaseAdapter.swift @@ -48,7 +48,10 @@ public class PrebidAdMobMediationBaseAdapter: NSObject, GADMediationAdapter { super.init() } - public static func setUpWith(_ configuration: GADMediationServerConfiguration, completionHandler: @escaping GADMediationAdapterSetUpCompletionBlock) { + public static func setUpWith( + _ configuration: GADMediationServerConfiguration, + completionHandler: @escaping GADMediationAdapterSetUpCompletionBlock + ) { // TODO: Add Prebid SDK initialization logic } } diff --git a/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedAdapter.swift b/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedAdapter.swift new file mode 100644 index 000000000..759310bcc --- /dev/null +++ b/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedAdapter.swift @@ -0,0 +1,166 @@ +/*   Copyright 2018-2021 Prebid.org, Inc. + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ + +import PrebidMobile +import GoogleMobileAds + +@objc(PrebidAdMobRewardedAdapter) +public class PrebidAdMobRewardedAdapter: + PrebidAdMobMediationBaseAdapter, + GADMediationRewardedAd, + InterstitialControllerLoadingDelegate, + InterstitialControllerInteractionDelegate { + + // MARK: - Private Properties + + var interstitialController: InterstitialController? + weak var rootViewController: UIViewController? + var adAvailable = false + + weak var delegate: GADMediationRewardedAdEventDelegate? + var completionHandler: GADMediationRewardedLoadCompletionHandler? + + // MARK: - GADMediationAdapter + + public func loadRewardedAd(for adConfiguration: GADMediationRewardedAdConfiguration, + completionHandler: @escaping GADMediationRewardedLoadCompletionHandler) { + self.completionHandler = completionHandler + + switch createInterstitialController(with: adConfiguration) { + case .success(let controller): + self.interstitialController = controller + interstitialController?.loadAd() + case .failure(let error): + delegate = completionHandler(nil, error) + } + } + + // MARK: - Helpers + + func createInterstitialController( + with adConfiguration: GADMediationRewardedAdConfiguration + ) -> Result { + + guard let serverParameter = adConfiguration.credentials.settings["parameter"] as? String else { + return .failure(AdMobAdaptersError.noServerParameter) + } + + guard let eventExtras = adConfiguration.extras as? GADCustomEventExtras, + let eventExtrasDictionary = eventExtras.extras(forLabel: AdMobConstants.PrebidAdMobEventExtrasLabel), + !eventExtrasDictionary.isEmpty else { + return .failure(AdMobAdaptersError.emptyCustomEventExtras) + } + + guard let targetingInfo = eventExtrasDictionary[PBMMediationTargetingInfoKey] as? [String: String] else { + return .failure(AdMobAdaptersError.noTargetingInfoInEventExtras) + } + + guard MediationUtils.isServerParameterInTargetingInfoDict(serverParameter, targetingInfo) else { + return .failure(AdMobAdaptersError.wrongServerParameter) + } + + guard let bid = eventExtrasDictionary[PBMMediationAdUnitBidKey] as? Bid else { + return .failure(AdMobAdaptersError.noBidInEventExtras) + } + + guard let configId = eventExtrasDictionary[PBMMediationConfigIdKey] as? String else { + return .failure(AdMobAdaptersError.noConfigIDInEventExtras) + } + + let interstitialController = InterstitialController(bid: bid, configId: configId) + interstitialController.loadingDelegate = self + interstitialController.interactionDelegate = self + interstitialController.isRewarded = true + + if let videoAdConfig = eventExtrasDictionary[PBMMediationVideoAdConfiguration] as? VideoControlsConfiguration { + interstitialController.videoControlsConfig = videoAdConfig + } + + if let videoParameters = eventExtrasDictionary[PBMMediationVideoParameters] as? VideoParameters { + interstitialController.videoParameters = videoParameters + } + + return .success(interstitialController) + } + + // MARK: - GADMediationRewardedAd + + public func present(from viewController: UIViewController) { + if adAvailable { + rootViewController = viewController + interstitialController?.show() + } else { + let error = AdMobAdaptersError.noAd + delegate?.didFailToPresentWithError(error) + + if let handler = completionHandler { + delegate = handler(nil, error) + } + } + } + + // MARK: - InterstitialControllerLoadingDelegate + + public func interstitialControllerDidLoadAd(_ interstitialController: InterstitialController) { + adAvailable = true + + if let handler = completionHandler { + delegate = handler(self, nil) + } + } + + public func interstitialController(_ interstitialController: InterstitialController, didFailWithError error: Error) { + adAvailable = false + } + + // MARK: - InterstitialControllerInteractionDelegate + + public func trackImpression(forInterstitialController: InterstitialController) { + delegate?.reportImpression() + } + + public func trackUserReward(_ interstitialController: InterstitialController, _ reward: PrebidReward) { + delegate?.didRewardUser() + } + + public func interstitialControllerDidClickAd(_ interstitialController: InterstitialController) { + delegate?.reportClick() + } + + public func interstitialControllerDidCloseAd(_ interstitialController: InterstitialController) { + adAvailable = false + delegate?.willDismissFullScreenView() + delegate?.didDismissFullScreenView() + } + + public func interstitialControllerDidDisplay(_ interstitialController: InterstitialController) { + delegate?.willPresentFullScreenView() + delegate?.didStartVideo() + delegate?.didEndVideo() + } + + public func interstitialControllerDidComplete(_ interstitialController: InterstitialController) { + adAvailable = false + rootViewController = nil + + delegate?.didRewardUser() + } + + public func viewControllerForModalPresentation(fromInterstitialController: InterstitialController) -> UIViewController? { + rootViewController + } + + public func interstitialControllerDidLeaveApp(_ interstitialController: InterstitialController) {} +} diff --git a/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedVideoAdapter.swift b/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedVideoAdapter.swift index 6e7a1790e..d570d9096 100644 --- a/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedVideoAdapter.swift +++ b/EventHandlers/PrebidMobileAdMobAdapters/Sources/PrebidAdMobRewardedVideoAdapter.swift @@ -13,149 +13,22 @@  limitations under the License.  */ -import Foundation import PrebidMobile import GoogleMobileAds +@available(*, deprecated, message: "This class is deprecated. Use PrebidAdMobRewardedAdapter instead.") @objc(PrebidAdMobRewardedVideoAdapter) -public class PrebidAdMobRewardedVideoAdapter: - PrebidAdMobMediationBaseAdapter, - GADMediationRewardedAd, - InterstitialControllerLoadingDelegate, - InterstitialControllerInteractionDelegate { +public class PrebidAdMobRewardedVideoAdapter: PrebidAdMobRewardedAdapter { - // MARK: - Private Properties - - var interstitialController: InterstitialController? - weak var rootViewController: UIViewController? - var adAvailable = false - - weak var delegate: GADMediationRewardedAdEventDelegate? - var completionHandler: GADMediationRewardedLoadCompletionHandler? - - // MARK: - GADMediationAdapter - - public func loadRewardedAd(for adConfiguration: GADMediationRewardedAdConfiguration, - completionHandler: @escaping GADMediationRewardedLoadCompletionHandler) { - self.completionHandler = completionHandler - - guard let serverParameter = adConfiguration.credentials.settings["parameter"] as? String else { - let error = AdMobAdaptersError.noServerParameter - delegate = completionHandler(nil, error) - return - } - - guard let eventExtras = adConfiguration.extras as? GADCustomEventExtras, - let eventExtrasDictionary = eventExtras.extras(forLabel: AdMobConstants.PrebidAdMobEventExtrasLabel), - !eventExtrasDictionary.isEmpty else { - let error = AdMobAdaptersError.emptyCustomEventExtras - delegate = completionHandler(nil, error) - return - } - - guard let targetingInfo = eventExtrasDictionary[PBMMediationTargetingInfoKey] as? [String: String] else { - let error = AdMobAdaptersError.noTargetingInfoInEventExtras - delegate = completionHandler(nil, error) - return - } - - guard MediationUtils.isServerParameterInTargetingInfoDict(serverParameter, targetingInfo) else { - let error = AdMobAdaptersError.wrongServerParameter - delegate = completionHandler(nil, error) - return - } - - guard let bid = eventExtrasDictionary[PBMMediationAdUnitBidKey] as? Bid else { - let error = AdMobAdaptersError.noBidInEventExtras - delegate = completionHandler(nil, error) - return - } - - guard let configId = eventExtrasDictionary[PBMMediationConfigIdKey] as? String else { - let error = AdMobAdaptersError.noConfigIDInEventExtras - delegate = completionHandler(nil, error) - return - } - - interstitialController = InterstitialController(bid: bid, configId: configId) - interstitialController?.loadingDelegate = self - interstitialController?.interactionDelegate = self - interstitialController?.adFormats = [.video] - interstitialController?.isRewarded = true - - if let videoAdConfig = eventExtrasDictionary[PBMMediationVideoAdConfiguration] as? VideoControlsConfiguration { - interstitialController?.videoControlsConfig = videoAdConfig - } - - if let videoParameters = eventExtrasDictionary[PBMMediationVideoParameters] as? VideoParameters { - interstitialController?.videoParameters = videoParameters - } - - interstitialController?.loadAd() - } - - // MARK: - GADMediationRewardedAd - - public func present(from viewController: UIViewController) { - if adAvailable { - rootViewController = viewController - interstitialController?.show() - } else { - let error = AdMobAdaptersError.noAd - delegate?.didFailToPresentWithError(error) - - if let handler = completionHandler { - delegate = handler(nil, error) - } + override func createInterstitialController( + with adConfiguration: GADMediationRewardedAdConfiguration + ) -> Result { + let result = super.createInterstitialController(with: adConfiguration) + if case .success(let controller) = result { + controller.adFormats = [.video] + return .success(controller) } - } - - // MARK: - InterstitialControllerLoadingDelegate - - public func interstitialControllerDidLoadAd(_ interstitialController: InterstitialController) { - adAvailable = true - if let handler = completionHandler { - delegate = handler(self, nil) - } + return result } - - public func interstitialController(_ interstitialController: InterstitialController, didFailWithError error: Error) { - adAvailable = false - } - - // MARK: - InterstitialControllerInteractionDelegate - - public func trackImpression(forInterstitialController: InterstitialController) { - delegate?.reportImpression() - } - - public func interstitialControllerDidClickAd(_ interstitialController: InterstitialController) { - delegate?.reportClick() - } - - public func interstitialControllerDidCloseAd(_ interstitialController: InterstitialController) { - adAvailable = false - delegate?.willDismissFullScreenView() - delegate?.didDismissFullScreenView() - } - - public func interstitialControllerDidDisplay(_ interstitialController: InterstitialController) { - delegate?.willPresentFullScreenView() - delegate?.didStartVideo() - delegate?.didEndVideo() - } - - public func interstitialControllerDidComplete(_ interstitialController: InterstitialController) { - adAvailable = false - rootViewController = nil - - delegate?.didRewardUser() - } - - public func viewControllerForModalPresentation(fromInterstitialController: InterstitialController) -> UIViewController? { - rootViewController - } - - public func interstitialControllerDidLeaveApp(_ interstitialController: InterstitialController) {} } diff --git a/EventHandlers/PrebidMobileMAXAdapters/Sources/PrebidMAXMediationAdapter+MAInterstitialAdapter+MARewardedAdapter.swift b/EventHandlers/PrebidMobileMAXAdapters/Sources/PrebidMAXMediationAdapter+MAInterstitialAdapter+MARewardedAdapter.swift index 2da86f5aa..3dd04e14b 100644 --- a/EventHandlers/PrebidMobileMAXAdapters/Sources/PrebidMAXMediationAdapter+MAInterstitialAdapter+MARewardedAdapter.swift +++ b/EventHandlers/PrebidMobileMAXAdapters/Sources/PrebidMAXMediationAdapter+MAInterstitialAdapter+MARewardedAdapter.swift @@ -13,7 +13,6 @@  limitations under the License.  */ -import Foundation import PrebidMobile import AppLovinSDK @@ -24,52 +23,20 @@ extension PrebidMAXMediationAdapter: MAInterstitialAdapter, // MARK: - MAInterstitialAdapter - public func loadInterstitialAd(for parameters: MAAdapterResponseParameters, andNotify delegate: MAInterstitialAdapterDelegate) { + public func loadInterstitialAd( + for parameters: MAAdapterResponseParameters, + andNotify delegate: MAInterstitialAdapterDelegate + ) { interstitialDelegate = delegate - guard let serverParameter = parameters.serverParameters[MAXCustomParametersKey] as? [String: String] else { - let error = MAAdapterError(nsError: MAXAdaptersError.noServerParameter) - interstitialDelegate?.didFailToLoadInterstitialAdWithError(error) - return + switch createInterstitialController(with: parameters) { + case .success(let controller): + self.interstitialController = controller + interstitialController?.loadAd() + case .failure(let error): + let maError = MAAdapterError(nsError: error) + interstitialDelegate?.didFailToLoadInterstitialAdWithError(maError) } - - guard let bid = parameters.localExtraParameters[PBMMediationAdUnitBidKey] as? Bid else { - let error = MAAdapterError(nsError: MAXAdaptersError.noBidInLocalExtraParameters) - interstitialDelegate?.didFailToLoadInterstitialAdWithError(error) - return - } - - guard let targetingInfo = bid.targetingInfo else { - let error = MAAdapterError(nsError: MAXAdaptersError.noTargetingInfoInBid) - interstitialDelegate?.didFailToLoadInterstitialAdWithError(error) - return - } - - guard MediationUtils.isServerParameterDictInTargetingInfoDict(serverParameter, targetingInfo) else { - let error = MAAdapterError(nsError: MAXAdaptersError.wrongServerParameter) - interstitialDelegate?.didFailToLoadInterstitialAdWithError(error) - return - } - - guard let configId = parameters.localExtraParameters[PBMMediationConfigIdKey] as? String else { - let error = MAAdapterError(nsError: MAXAdaptersError.noConfigIdInLocalExtraParameters) - interstitialDelegate?.didFailToLoadInterstitialAdWithError(error) - return - } - - interstitialController = InterstitialController(bid: bid, configId: configId) - interstitialController?.loadingDelegate = self - interstitialController?.interactionDelegate = self - - if let videoAdConfig = parameters.localExtraParameters[PBMMediationVideoAdConfiguration] as? VideoControlsConfiguration { - interstitialController?.videoControlsConfig = videoAdConfig - } - - if let videoParameters = parameters.localExtraParameters[PBMMediationVideoParameters] as? VideoParameters { - interstitialController?.videoParameters = videoParameters - } - - interstitialController?.loadAd() } public func showInterstitialAd(for parameters: MAAdapterResponseParameters, andNotify delegate: MAInterstitialAdapterDelegate) { @@ -85,58 +52,71 @@ extension PrebidMAXMediationAdapter: MAInterstitialAdapter, public func loadRewardedAd(for parameters: MAAdapterResponseParameters, andNotify delegate: MARewardedAdapterDelegate) { rewardedDelegate = delegate - guard let serverParameter = parameters.serverParameters[MAXCustomParametersKey] as? [String: String] else { - let error = MAAdapterError(nsError: MAXAdaptersError.noServerParameter) - rewardedDelegate?.didFailToLoadRewardedAdWithError(error) - return + switch createInterstitialController(with: parameters) { + case .success(let controller): + interstitialController = controller + interstitialController?.isRewarded = true + interstitialController?.loadAd() + case .failure(let error): + let maError = MAAdapterError(nsError: error) + rewardedDelegate?.didFailToLoadRewardedAdWithError(maError) + } + } + + public func showRewardedAd( + for parameters: MAAdapterResponseParameters, + andNotify delegate: MARewardedAdapterDelegate + ) { + if interstitialAdAvailable { + interstitialController?.show() + } else { + interstitialDelegate?.didFailToLoadInterstitialAdWithError(MAAdapterError.adNotReady) + } + } + + private func createInterstitialController( + with parameters: MAAdapterResponseParameters + ) -> Result { + + guard let serverParameter = parameters + .serverParameters[MAXCustomParametersKey] as? [String: String] else { + return .failure(MAXAdaptersError.noServerParameter) } - guard let bid = parameters.localExtraParameters[PBMMediationAdUnitBidKey] as? Bid else { - let error = MAAdapterError(nsError: MAXAdaptersError.noBidInLocalExtraParameters) - rewardedDelegate?.didFailToLoadRewardedAdWithError(error) - return + guard let bid = parameters + .localExtraParameters[PBMMediationAdUnitBidKey] as? Bid else { + return .failure(MAXAdaptersError.noBidInLocalExtraParameters) } guard let targetingInfo = bid.targetingInfo else { - let error = MAAdapterError(nsError: MAXAdaptersError.noTargetingInfoInBid) - rewardedDelegate?.didFailToLoadRewardedAdWithError(error) - return + return .failure(MAXAdaptersError.noTargetingInfoInBid) } - guard MediationUtils.isServerParameterDictInTargetingInfoDict(serverParameter, targetingInfo) else { - let error = MAAdapterError(nsError: MAXAdaptersError.wrongServerParameter) - rewardedDelegate?.didFailToLoadRewardedAdWithError(error) - return + guard MediationUtils + .isServerParameterDictInTargetingInfoDict(serverParameter, targetingInfo) else { + return .failure(MAXAdaptersError.wrongServerParameter) } - guard let configId = parameters.localExtraParameters[PBMMediationConfigIdKey] as? String else { - let error = MAAdapterError(nsError: MAXAdaptersError.noConfigIdInLocalExtraParameters) - rewardedDelegate?.didFailToLoadRewardedAdWithError(error) - return + guard let configId = parameters + .localExtraParameters[PBMMediationConfigIdKey] as? String else { + return .failure(MAXAdaptersError.noConfigIdInLocalExtraParameters) } - interstitialController = InterstitialController(bid: bid, configId: configId) - interstitialController?.loadingDelegate = self - interstitialController?.interactionDelegate = self - interstitialController?.isRewarded = true + let interstitialController = InterstitialController(bid: bid, configId: configId) + interstitialController.loadingDelegate = self + interstitialController.interactionDelegate = self - if let videoAdConfig = parameters.localExtraParameters[PBMMediationVideoAdConfiguration] as? VideoControlsConfiguration { - interstitialController?.videoControlsConfig = videoAdConfig + if let videoAdConfig = parameters + .localExtraParameters[PBMMediationVideoAdConfiguration] as? VideoControlsConfiguration { + interstitialController.videoControlsConfig = videoAdConfig } - if let videoParameters = parameters.localExtraParameters[PBMMediationVideoParameters] as? VideoParameters { - interstitialController?.videoParameters = videoParameters + if let videoParameters = parameters + .localExtraParameters[PBMMediationVideoParameters] as? VideoParameters { + interstitialController.videoParameters = videoParameters } - interstitialController?.loadAd() - } - - public func showRewardedAd(for parameters: MAAdapterResponseParameters, andNotify delegate: MARewardedAdapterDelegate) { - if interstitialAdAvailable { - interstitialController?.show() - } else { - interstitialDelegate?.didFailToLoadInterstitialAdWithError(MAAdapterError.adNotReady) - } + return .success(interstitialController) } // MARK: - InterstitialControllerLoadingDelegate @@ -156,9 +136,7 @@ extension PrebidMAXMediationAdapter: MAInterstitialAdapter, // MARK: - InterstitialControllerInteractionDelegate - public func trackImpression(forInterstitialController: InterstitialController) { - - } + public func trackImpression(forInterstitialController: InterstitialController) {} public func interstitialControllerDidClickAd(_ interstitialController: InterstitialController) { interstitialDelegate?.didClickInterstitialAd() @@ -170,9 +148,7 @@ extension PrebidMAXMediationAdapter: MAInterstitialAdapter, rewardedDelegate?.didHideRewardedAd() } - public func interstitialControllerDidLeaveApp(_ interstitialController: InterstitialController) { - - } + public func interstitialControllerDidLeaveApp(_ interstitialController: InterstitialController) {} public func interstitialControllerDidDisplay(_ interstitialController: InterstitialController) { interstitialDelegate?.didDisplayInterstitialAd() @@ -184,7 +160,21 @@ extension PrebidMAXMediationAdapter: MAInterstitialAdapter, rewardedDelegate?.didRewardUser(with: MAReward()) } - public func viewControllerForModalPresentation(fromInterstitialController: InterstitialController) -> UIViewController? { + public func viewControllerForModalPresentation( + fromInterstitialController: InterstitialController + ) -> UIViewController? { return UIApplication.shared.windows.first?.rootViewController } + + public func trackUserReward( + _ interstitialController: InterstitialController, + _ reward: PrebidReward + ) { + let reward = MAReward( + amount: reward.count?.intValue ?? 0, + label: reward.type ?? "" + ) + + rewardedDelegate?.didRewardUser(with: reward) + } } diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m index 6ffd2c774..bc87cdb09 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m @@ -17,7 +17,7 @@ #import "PrebidDemoMacros.h" NSString * const storedImpDisplayRewardedAdMob = @"prebid-demo-banner-rewarded-time"; -NSString * const adMobAdUnitDisplayRewardedId = @"ca-app-pub-5922967660082475/7397370641"; +NSString * const adMobAdUnitDisplayRewardedId = @"ca-app-pub-5922967660082475/5628505938"; @interface AdMobDisplayRewardedViewController () diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m index e2df00a21..5fe84d289 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m @@ -17,7 +17,7 @@ #import "PrebidDemoMacros.h" NSString * const storedImpVideoRewardedAdMob = @"prebid-demo-video-rewarded-endcard-time"; -NSString * const adMobAdUnitVideoRewardedId = @"ca-app-pub-5922967660082475/7397370641"; +NSString * const adMobAdUnitVideoRewardedId = @"ca-app-pub-5922967660082475/5628505938"; @interface AdMobVideoRewardedViewController () diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift index 0cb51a328..7b3607a38 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift @@ -19,7 +19,7 @@ import GoogleMobileAds import PrebidMobileAdMobAdapters fileprivate let storedImpDisplayRewarded = "prebid-demo-banner-rewarded-time" -fileprivate let adMobAdUnitRewardedId = "ca-app-pub-5922967660082475/7397370641" +fileprivate let adMobAdUnitRewardedId = "ca-app-pub-5922967660082475/5628505938" class AdMobDisplayRewardedViewController: InterstitialBaseViewController, GADFullScreenContentDelegate { diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift index 8386adf1a..bfb1086e6 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift @@ -19,7 +19,7 @@ import GoogleMobileAds import PrebidMobileAdMobAdapters fileprivate let storedImpVideoRewarded = "prebid-demo-video-rewarded-endcard-time" -fileprivate let adMobAdUnitRewardedId = "ca-app-pub-5922967660082475/7397370641" +fileprivate let adMobAdUnitRewardedId = "ca-app-pub-5922967660082475/5628505938" class AdMobVideoRewardedViewController: InterstitialBaseViewController, GADFullScreenContentDelegate { diff --git a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift index 66613f53e..75655ef53 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift @@ -2811,7 +2811,7 @@ struct TestCaseManager { } let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) - admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" + admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/5628505938" admobRewardedAdController.prebidConfigId = "prebid-demo-banner-rewarded-time" adapterVC.setup(adapter: admobRewardedAdController) setupCustomParams(for: admobRewardedAdController.prebidConfigId) @@ -2826,7 +2826,7 @@ struct TestCaseManager { } let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) - admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" + admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/5628505938" admobRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-endcard-time" adapterVC.setup(adapter: admobRewardedAdController) setupCustomParams(for: admobRewardedAdController.prebidConfigId) @@ -2842,7 +2842,7 @@ struct TestCaseManager { let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) admobRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time" - admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" + admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/5628505938" adapterVC.setup(adapter: admobRewardedAdController) setupCustomParams(for: admobRewardedAdController.prebidConfigId) }), @@ -2856,7 +2856,7 @@ struct TestCaseManager { } let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) - admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" + admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/5628505938" admobRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time-ad-config" adapterVC.setup(adapter: admobRewardedAdController) setupCustomParams(for: admobRewardedAdController.prebidConfigId) @@ -2872,7 +2872,7 @@ struct TestCaseManager { let admobRewardedAdController = PrebidAdMobRewardedViewController(rootController: adapterVC) admobRewardedAdController.prebidConfigId = "prebid-demo-no-bids" - admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/7397370641" + admobRewardedAdController.adMobAdUnitId = "ca-app-pub-5922967660082475/5628505938" adapterVC.setup(adapter: admobRewardedAdController) setupCustomParams(for: admobRewardedAdController.prebidConfigId) }), diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift index 9a800cf11..d56b10cfd 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseInterstitialAdUnit.swift @@ -215,6 +215,7 @@ class BaseInterstitialAdUnit: public func interstitialControllerDidDisplay(_ interstitialController: InterstitialController) {} public func interstitialControllerDidComplete(_ interstitialController: InterstitialController) {} + public func trackUserReward(_ interstitialController: InterstitialController, _ reward: PrebidReward) {} public func viewControllerForModalPresentation( fromInterstitialController: InterstitialController diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift index 2abe40c8c..f00d098f5 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift @@ -33,9 +33,13 @@ class BaseRewardedAdUnit: BaseInterstitialAdUnit, RewardedEventInteractionDelega adUnitConfig.adConfiguration.isRewarded = true } - func userDidEarnReward(_ interstitialController: InterstitialController, _ reward: PrebidReward) { + override func trackUserReward(_ interstitialController: InterstitialController, _ reward: PrebidReward) { DispatchQueue.main.async { self.delegate?.callDelegate_rewardedAdUserDidEarnReward?(reward: reward) } } + + func userDidEarnReward(_ reward: NSObject?) { + /// ?????? + } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift index 556d8f6e2..2f0771e17 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift @@ -16,7 +16,7 @@ import Foundation @objc public protocol RewardedEventInteractionDelegate: InterstitialEventInteractionDelegate { - + /// Call this when the ad server SDK decides the use has earned reward - func userDidEarnReward(_ interstitialController: InterstitialController, _ reward: PrebidReward) + func userDidEarnReward(_ reward: NSObject?) } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift index fb0a6187b..b5b49e46b 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialController.swift @@ -151,8 +151,8 @@ public class InterstitialController: NSObject, PBMAdViewManagerDelegate { } @objc public func adDidSendRewardedEvent() { - if let delegate = interactionDelegate as? RewardedEventInteractionDelegate { - delegate.userDidEarnReward(self, PrebidReward(with: bid.rewardedConfig?.reward)) + if let delegate = interactionDelegate { + delegate.trackUserReward?(self, PrebidReward(with: bid.rewardedConfig?.reward)) } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialControllerInteractionDelegate.swift b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialControllerInteractionDelegate.swift index eac1e8c15..12655b8b3 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialControllerInteractionDelegate.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCacheRenderers/InterstitialControllerInteractionDelegate.swift @@ -13,7 +13,6 @@  limitations under the License.  */ -import Foundation import UIKit @objc public protocol InterstitialControllerInteractionDelegate: NSObjectProtocol { @@ -27,4 +26,6 @@ import UIKit func interstitialControllerDidComplete(_ interstitialController: InterstitialController) func viewControllerForModalPresentation(fromInterstitialController: InterstitialController) -> UIViewController? + + @objc optional func trackUserReward(_ interstitialController: InterstitialController, _ reward: PrebidReward) } From fb65a590c9a9b46ae6eec1a40191b4e6a887915b Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Mon, 14 Oct 2024 10:00:01 +0300 Subject: [PATCH 12/18] feat: changes in adapters --- .../EventHandlers.xcodeproj/project.pbxproj | 14 ++- .../Sources/GAMInterstitialEventHandler.swift | 4 +- .../Sources/GAMRewardedEventHandler.swift | 10 +- .../Sources/Utils/GADReward+Extensions.swift | 17 ++- .../InternalTestApp.xcodeproj/project.pbxproj | 35 +++--- .../Model/TestCasesManager.swift | 16 +-- .../UITests/AdsLoaderUITestCase.swift | 25 ++-- .../UITests/PrebidExamplesUITest.swift | 112 +++++++++++------- .../UITests/PrebidRewardedVideoUITest.swift | 29 +++-- .../UITests/PrebidServerUITests.swift | 19 --- .../UITests/XCTestCaseExt.swift | 5 +- PrebidMobile.xcodeproj/project.pbxproj | 4 - .../GAM/AdLoading/PBMInterstitialAdLoader.m | 4 +- .../Integrations/GAM/BaseRewardedAdUnit.swift | 12 +- .../Integrations/GAM/PrebidReward.swift | 3 +- .../Integrations/GAM/RewardedAdUnit.swift | 2 +- .../GAM/RewardedEventHandlerProtocol.swift | 2 +- .../RewardedEventInteractionDelegate.swift | 4 +- .../RewardedEventHandlerStandalone.swift | 2 +- 19 files changed, 177 insertions(+), 142 deletions(-) rename PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventLoadingDelegate.swift => EventHandlers/PrebidMobileGAMEventHandlers/Sources/Utils/GADReward+Extensions.swift (66%) diff --git a/EventHandlers/EventHandlers.xcodeproj/project.pbxproj b/EventHandlers/EventHandlers.xcodeproj/project.pbxproj index 5a8bce74b..59a7bd111 100644 --- a/EventHandlers/EventHandlers.xcodeproj/project.pbxproj +++ b/EventHandlers/EventHandlers.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 534C61682CB861930026119A /* PrebidAdMobRewardedAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61672CB861930026119A /* PrebidAdMobRewardedAdapter.swift */; }; 53632B24290BC57A00139EF3 /* AdMobGMATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53632B23290BC57A00139EF3 /* AdMobGMATests.swift */; }; 53632B2C290BE17300139EF3 /* GMATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53632B2B290BE17300139EF3 /* GMATests.swift */; }; + 53F2A57B2CB94FBE009B74CA /* GADReward+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53F2A57A2CB94FB3009B74CA /* GADReward+Extensions.swift */; }; 5B36172626370A8700AFA1C2 /* GAMUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B36172526370A8700AFA1C2 /* GAMUtils.swift */; }; 5B3617FC2638131A00AFA1C2 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3617FB2638131A00AFA1C2 /* Constants.swift */; }; 5B36182326384C7D00AFA1C2 /* GAMRewardedEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B36182226384C7D00AFA1C2 /* GAMRewardedEventHandler.swift */; }; @@ -116,6 +117,7 @@ 534C61672CB861930026119A /* PrebidAdMobRewardedAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidAdMobRewardedAdapter.swift; sourceTree = ""; }; 53632B23290BC57A00139EF3 /* AdMobGMATests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdMobGMATests.swift; sourceTree = ""; }; 53632B2B290BE17300139EF3 /* GMATests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GMATests.swift; sourceTree = ""; }; + 53F2A57A2CB94FB3009B74CA /* GADReward+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GADReward+Extensions.swift"; sourceTree = ""; }; 58B193FE14C1F3D7E795F7AC /* Pods-PrebidMobileMAXAdapters.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PrebidMobileMAXAdapters.release.xcconfig"; path = "Target Support Files/Pods-PrebidMobileMAXAdapters/Pods-PrebidMobileMAXAdapters.release.xcconfig"; sourceTree = ""; }; 5B36172526370A8700AFA1C2 /* GAMUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GAMUtils.swift; sourceTree = ""; }; 5B3617FB2638131A00AFA1C2 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; @@ -338,6 +340,8 @@ 34B64D6D24F7E54700FDD9F4 /* Sources */ = { isa = PBXGroup; children = ( + 34C7C9E8250901410021C6D0 /* Boxes */, + 53F2A5792CB94FA8009B74CA /* Utils */, 5B69677F2642A56A0042372E /* PrebidMobileGAMEventHandlers.h */, 5B3617FB2638131A00AFA1C2 /* Constants.swift */, 5BF8E76D263BF4DF00341EE4 /* GAMBannerEventHandler.swift */, @@ -345,7 +349,6 @@ 5BF8E6B6263AC32800341EE4 /* GAMInterstitialEventHandler.swift */, 5B36182226384C7D00AFA1C2 /* GAMRewardedEventHandler.swift */, 5B36172526370A8700AFA1C2 /* GAMUtils.swift */, - 34C7C9E8250901410021C6D0 /* Boxes */, ); path = Sources; sourceTree = ""; @@ -363,6 +366,14 @@ path = Boxes; sourceTree = ""; }; + 53F2A5792CB94FA8009B74CA /* Utils */ = { + isa = PBXGroup; + children = ( + 53F2A57A2CB94FB3009B74CA /* GADReward+Extensions.swift */, + ); + path = Utils; + sourceTree = ""; + }; 927ADB28280583AF006EB8D5 /* Sources */ = { isa = PBXGroup; children = ( @@ -954,6 +965,7 @@ 5BF8E781263C363800341EE4 /* GAMRequestWrapper.swift in Sources */, 5BF8E789263C3B4000341EE4 /* GADNativeAdWrapper.swift in Sources */, 5B36172626370A8700AFA1C2 /* GAMUtils.swift in Sources */, + 53F2A57B2CB94FBE009B74CA /* GADReward+Extensions.swift in Sources */, 5B6967702642993B0042372E /* GAMEventHandlerError.swift in Sources */, 5BF8E779263C291300341EE4 /* GAMBannerViewWrapper.swift in Sources */, ); diff --git a/EventHandlers/PrebidMobileGAMEventHandlers/Sources/GAMInterstitialEventHandler.swift b/EventHandlers/PrebidMobileGAMEventHandlers/Sources/GAMInterstitialEventHandler.swift index f62a88f5a..f21afab45 100644 --- a/EventHandlers/PrebidMobileGAMEventHandlers/Sources/GAMInterstitialEventHandler.swift +++ b/EventHandlers/PrebidMobileGAMEventHandlers/Sources/GAMInterstitialEventHandler.swift @@ -127,9 +127,7 @@ public class GAMInterstitialEventHandler : } } - func interstitial(didFailToReceive ad:GAMInterstitialAdWrapper, - error: Error) - { + func interstitial(didFailToReceive ad: GAMInterstitialAdWrapper, error: Error) { if requestInterstitial === ad { requestInterstitial = nil forgetCurrentInterstitial() diff --git a/EventHandlers/PrebidMobileGAMEventHandlers/Sources/GAMRewardedEventHandler.swift b/EventHandlers/PrebidMobileGAMEventHandlers/Sources/GAMRewardedEventHandler.swift index 20b4759fe..54a3ec377 100644 --- a/EventHandlers/PrebidMobileGAMEventHandlers/Sources/GAMRewardedEventHandler.swift +++ b/EventHandlers/PrebidMobileGAMEventHandlers/Sources/GAMRewardedEventHandler.swift @@ -58,8 +58,7 @@ public class GAMRewardedAdEventHandler : // This is a very dirty hack based on dynamic properties of Objc Object. // Need to rewrite Interstitial ad loader to swift and find out how to pass the reward - public weak var loadingDelegate: RewardedEventLoadingDelegate? - + public weak var loadingDelegate: InterstitialEventLoadingDelegate? public weak var interactionDelegate: RewardedEventInteractionDelegate? // MARK: - Public Methods @@ -169,7 +168,7 @@ public class GAMRewardedAdEventHandler : forgetCurrentRewarded() embeddedRewarded = rewarded - loadingDelegate?.reward = rewarded?.reward + interactionDelegate?.userDidEarnReward(rewarded?.reward?.toPrebidReward()) loadingDelegate?.adServerDidWin() } } @@ -190,9 +189,9 @@ public class GAMRewardedAdEventHandler : embeddedRewarded = rewarded isExpectingAppEvent = false appEventTimer?.invalidate() - appEventTimer = nil; + appEventTimer = nil - loadingDelegate?.reward = rewarded?.reward + interactionDelegate?.userDidEarnReward(rewarded?.reward?.toPrebidReward()) loadingDelegate?.adServerDidWin() } @@ -211,7 +210,6 @@ public class GAMRewardedAdEventHandler : forgetCurrentRewarded() proxyRewarded = rewarded - loadingDelegate?.reward = rewarded?.reward loadingDelegate?.prebidDidWin() } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventLoadingDelegate.swift b/EventHandlers/PrebidMobileGAMEventHandlers/Sources/Utils/GADReward+Extensions.swift similarity index 66% rename from PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventLoadingDelegate.swift rename to EventHandlers/PrebidMobileGAMEventHandlers/Sources/Utils/GADReward+Extensions.swift index 25f49de06..78a5981ae 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventLoadingDelegate.swift +++ b/EventHandlers/PrebidMobileGAMEventHandlers/Sources/Utils/GADReward+Extensions.swift @@ -1,4 +1,4 @@ -/*   Copyright 2018-2021 Prebid.org, Inc. +/*   Copyright 2018-2024 Prebid.org, Inc.  Licensed under the Apache License, Version 2.0 (the "License");  you may not use this file except in compliance with the License. @@ -13,10 +13,15 @@  limitations under the License.  */ -import Foundation +import GoogleMobileAds +import PrebidMobile -@objc public protocol RewardedEventLoadingDelegate : InterstitialEventLoadingDelegate { - - // The reward to be given to the user. May be assigned on successful loading. - weak var reward: NSObject? { get set } +extension GADAdReward { + + func toPrebidReward() -> PrebidReward { + let reward = PrebidReward() + reward.type = type + reward.count = amount + return reward + } } diff --git a/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj b/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj index 5d871d749..9b7ee2550 100644 --- a/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj +++ b/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj @@ -884,27 +884,27 @@ 92700C66273C029F0006E9FA /* UITests */ = { isa = PBXGroup; children = ( + 92700C74273C029F0006E9FA /* AdsLoaderUITestCase.swift */, + 92700C78273C029F0006E9FA /* BaseUITestCase.swift */, + 92700C77273C029F0006E9FA /* ConsolidatedBannerUITest.swift */, + 92700C70273C029F0006E9FA /* PrebidBannerUITest.swift */, + 92700C7C273C029F0006E9FA /* PrebidExamplesUITest.swift */, + 92700C6D273C029F0006E9FA /* PrebidInterstitialUITest.swift */, + 92700C7A273C029F0006E9FA /* PrebidMRAID3MethodsUITest.swift */, 92700C67273C029F0006E9FA /* PrebidMRAID3UITest.swift */, - 92700C68273C029F0006E9FA /* XCTestCaseExt.swift */, - 92700C69273C029F0006E9FA /* PrebidVideoOutstreamUITest.swift */, 92700C6B273C029F0006E9FA /* PrebidMRAIDFullScreenUITest.swift */, - 92700C6C273C029F0006E9FA /* XCTestCase+Throwing.m */, - 92700C6D273C029F0006E9FA /* PrebidInterstitialUITest.swift */, + 92700C72273C029F0006E9FA /* PrebidMRAIDResizeExpandableUITest.swift */, + 92700C75273C029F0006E9FA /* PrebidMRAIDResizeUITest.swift */, + 92700C7B273C029F0006E9FA /* PrebidMRAIDResizeWithErrorsUITest.swift */, 92700C6E273C029F0006E9FA /* PrebidRewardedVideoUITest.swift */, 92700C6F273C029F0006E9FA /* PrebidServerUITests.swift */, - 92700C70273C029F0006E9FA /* PrebidBannerUITest.swift */, - 92700C71273C029F0006E9FA /* XCUIElementExt.swift */, - 92700C72273C029F0006E9FA /* PrebidMRAIDResizeExpandableUITest.swift */, 92700C73273C029F0006E9FA /* PrebidVideoInterstitialUITest.swift */, - 92700C74273C029F0006E9FA /* AdsLoaderUITestCase.swift */, - 92700C75273C029F0006E9FA /* PrebidMRAIDResizeUITest.swift */, - 92700C76273C029F0006E9FA /* XCTestCase+Throwing.h */, - 92700C77273C029F0006E9FA /* ConsolidatedBannerUITest.swift */, - 92700C78273C029F0006E9FA /* BaseUITestCase.swift */, + 92700C69273C029F0006E9FA /* PrebidVideoOutstreamUITest.swift */, 92700C79273C029F0006E9FA /* RepeatedUITestCase.swift */, - 92700C7A273C029F0006E9FA /* PrebidMRAID3MethodsUITest.swift */, - 92700C7B273C029F0006E9FA /* PrebidMRAIDResizeWithErrorsUITest.swift */, - 92700C7C273C029F0006E9FA /* PrebidExamplesUITest.swift */, + 92700C76273C029F0006E9FA /* XCTestCase+Throwing.h */, + 92700C6C273C029F0006E9FA /* XCTestCase+Throwing.m */, + 92700C68273C029F0006E9FA /* XCTestCaseExt.swift */, + 92700C71273C029F0006E9FA /* XCUIElementExt.swift */, ); path = UITests; sourceTree = ""; @@ -1182,7 +1182,6 @@ }; 93FED9C21A376EFE009A6E9F = { CreatedOnToolsVersion = 6.1.1; - DevelopmentTeam = 9TN4TUCG8N; LastSwiftMigration = 1020; ProvisioningStyle = Automatic; }; @@ -2115,7 +2114,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 9TN4TUCG8N; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2147,7 +2146,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 9TN4TUCG8N; + DEVELOPMENT_TEAM = ""; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift index 75655ef53..f05b106ae 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift @@ -2126,7 +2126,7 @@ struct TestCaseManager { // MARK: ---- Rewarded (GAM) ---- - TestCase(title: "Banner Rewarded Endcard Time 320x480 (GAM) [OK, Metadata]", + TestCase(title: "Banner Rewarded Time 320x480 (GAM) [OK, Metadata]", tags: [.interstitial, .gam, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in @@ -2142,23 +2142,22 @@ struct TestCaseManager { setupCustomParams(for: gamRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded Endcard Time 320x480 (GAM) [OK, Metadata]", + TestCase(title: "Video Rewarded Time 320x480 (GAM) [OK, Metadata]", tags: [.interstitial, .video, .gam, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in - guard let adapterVC = vc as? AdapterViewController else { return } let gamRewardedAdController = PrebidGAMRewardedController(rootController: adapterVC) + gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time" gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_test" - gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-endcard-time" adapterVC.setup(adapter: gamRewardedAdController) setupCustomParams(for: gamRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded Time 320x480 (GAM) [OK, Metadata]", + TestCase(title: "Video Rewarded 320x480 Time With Server Ad Configuration (GAM) [OK, Metadata]", tags: [.interstitial, .video, .gam, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in @@ -2167,23 +2166,24 @@ struct TestCaseManager { } let gamRewardedAdController = PrebidGAMRewardedController(rootController: adapterVC) - gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time" gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_test" + gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time-ad-config" adapterVC.setup(adapter: gamRewardedAdController) setupCustomParams(for: gamRewardedAdController.prebidConfigId) }), - TestCase(title: "Video Rewarded 320x480 Time With Server Ad Configuration (GAM) [OK, Metadata]", + TestCase(title: "Video Rewarded Endcard Time 320x480 (GAM) [OK, Metadata]", tags: [.interstitial, .video, .gam, .server], exampleVCStoryboardID: "AdapterViewController", configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { return } let gamRewardedAdController = PrebidGAMRewardedController(rootController: adapterVC) gamRewardedAdController.gamAdUnitId = "/21808260008/prebid_oxb_rewarded_video_test" - gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-time-ad-config" + gamRewardedAdController.prebidConfigId = "prebid-demo-video-rewarded-endcard-time" adapterVC.setup(adapter: gamRewardedAdController) setupCustomParams(for: gamRewardedAdController.prebidConfigId) }), diff --git a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/AdsLoaderUITestCase.swift b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/AdsLoaderUITestCase.swift index 97d487840..6d0d27760 100644 --- a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/AdsLoaderUITestCase.swift +++ b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/AdsLoaderUITestCase.swift @@ -115,17 +115,20 @@ class AdsLoaderUITestCase: RepeatedUITestCase { } } - func checkRewardedLoadResult(exampleName: String, - callbacks: (Bool) -> (String) = defaultRewardedCallbacks, - expectFailure: Bool = false, - file: StaticString = #file, - line: UInt = #line) - { - checkInterstitialLoadResult(exampleName: exampleName, - callbacks: callbacks, - expectFailure: expectFailure, - file: file, - line: line) + func checkRewardedLoadResult( + exampleName: String, + callbacks: (Bool) -> (String) = defaultRewardedCallbacks, + expectFailure: Bool = false, + file: StaticString = #file, + line: UInt = #line + ) { + checkInterstitialLoadResult( + exampleName: exampleName, + callbacks: callbacks, + expectFailure: expectFailure, + file: file, + line: line + ) } private static func defaultBannerCallbacks(ok: Bool) -> String { diff --git a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidExamplesUITest.swift b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidExamplesUITest.swift index 4ba3480e6..876236b5b 100644 --- a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidExamplesUITest.swift +++ b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidExamplesUITest.swift @@ -17,11 +17,6 @@ import UIKit class PrebidExamplesUITest: AdsLoaderUITestCase { - override func setUp() { - super.setUp() - - } - // MARK: - Banners (In-App) func testInAppBanner_Small_OK() { @@ -204,41 +199,6 @@ class PrebidExamplesUITest: AdsLoaderUITestCase { checkBannerLoadResult(exampleName: "Video Outstream (GAM) [noBids, GAM Ad]", video: true) } - // MARK: - Rewarded Video - - func testInAppRewarded_320x480() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 (In-App)") - } - - func testInAppRewarded_320x480_noBids() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 (In-App) [noBids]", - expectFailure: true) - } - - func testInAppRewarded_320x480_noEndCard() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 without End Card (In-App)") - } - - func testInAppRewarded_480x320() { - checkRewardedLoadResult(exampleName: "Video Rewarded 480x320 (In-App)") - } - - func testGAMRewarded_Ok_Metadata() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 (GAM) [OK, Metadata]") - } - - func testGAMRewarded_Ok_Random() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 (GAM) [OK, Random]") - } - - func testGAMRewarded_noBids_gamAd() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 (GAM) [noBids, GAM Ad]") - } - - func testGAMRewarded_noEndCard_Ok_Metadata() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 without End Card (GAM) [OK, Metadata]") - } - // MARK: - MRAID func testMRAID_Resize_InApp() { @@ -275,4 +235,76 @@ class PrebidExamplesUITest: AdsLoaderUITestCase { func testInAppNativeAd_Links() { checkNativeAdLoadResult(exampleName: "Native Ad Links (In-App)", successCallback: "getNativeAd success") } + + // MARK: - Rewarded + + func testRewardedBannerDefault() { + checkRewardedLoadResult(exampleName: "Banner Rewarded Default 320x480 (In-App)") + } + + func testRewardedBannerTime() { + checkRewardedLoadResult(exampleName: "Banner Rewarded Time 320x480 (In-App)") + } + + func testRewardedBannerEvent() { + checkRewardedLoadResult(exampleName: "Banner Rewarded Event 320x480 (In-App)") + } + + func testRewardedVideoDefault() { + checkRewardedLoadResult(exampleName: "Video Rewarded Default 320x480 (In-App)") + } + + func testRewardedVideoPlaybackevent() { + checkRewardedLoadResult(exampleName: "Video Rewarded Playbackevent 320x480 (In-App)") + } + + func testRewardedVideoTime() { + checkRewardedLoadResult(exampleName: "Video Rewarded Time 320x480 (In-App)") + } + + func testRewardedVideoTimeAdConfiguration() { + checkRewardedLoadResult(exampleName: "Video Rewarded Time With Server Ad Configuration 320x480 (In-App)") + } + + func testRewardedVideoEndcardDefault() { + checkRewardedLoadResult(exampleName: "Video Rewarded Endcard Default 320x480 (In-App)") + } + + func testRewardedVideoEndcardEvent() { + checkRewardedLoadResult(exampleName: "Video Rewarded Endcard Event 320x480 (In-App)") + } + + func testRewardedVideoEndcardTime() { + checkRewardedLoadResult(exampleName: "Video Rewarded Endcard Time 320x480 (In-App)") + } + + func testInAppRewarded_noBids() { + checkRewardedLoadResult( + exampleName: "Video Rewarded 320x480 (In-App) [noBids]", + expectFailure: true + ) + } + + func testGAMRewardedBannerTime() { + checkRewardedLoadResult(exampleName: "Banner Rewarded Time 320x480 (GAM) [OK, Metadata]") + } + + func testGAMRewardedVideoTime() { + checkRewardedLoadResult(exampleName: "Video Rewarded Time 320x480 (GAM) [OK, Metadata]") + } + + func testGAMRewardedVideoTimeAdConfiguration() { + checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 Time With Server Ad Configuration (GAM) [OK, Metadata]") + } + + func testGAMRewardedVideoEndcardTime() { + checkRewardedLoadResult(exampleName: "Video Rewarded Endcard Time 320x480 (GAM) [OK, Metadata]") + } + + func testGAMRewarded_noBids_gamAd() { + checkRewardedLoadResult( + exampleName: "Video Rewarded 320x480 (GAM) [noBids, GAM Ad]", + expectFailure: true + ) + } } diff --git a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidRewardedVideoUITest.swift b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidRewardedVideoUITest.swift index 1c0fbec13..3d07f17de 100644 --- a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidRewardedVideoUITest.swift +++ b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidRewardedVideoUITest.swift @@ -20,12 +20,8 @@ class PrebidRewardedVideoUITest: RepeatedUITestCase { private let waitingTimeout = 15.0 private let videoDuration = TimeInterval(17) - let videoRewardedTitle = "Video Rewarded 320x480 without End Card (In-App)" - let videoRewardedEndCardTitle = "Video Rewarded 320x480 (In-App)" - - override func setUp() { - super.setUp() - } + let videoRewardedTitle = "Video Rewarded Time 320x480 (In-App)" + let videoRewardedEndCardTitle = "Video Rewarded Endcard Time 320x480 (In-App)" func testTapEndCardThenClose() { repeatTesting(times: 7) { @@ -33,26 +29,33 @@ class PrebidRewardedVideoUITest: RepeatedUITestCase { // Tap on End card let endCardLink = app.links.firstMatch - waitForExists(element: endCardLink, waitSeconds: 5) + waitForExists(element: endCardLink, waitSeconds: 20) endCardLink.tap() //The video should still be visible. Close it. - closeAndVerifyPostEvents(expectClick: true) + let done = app.descendants(matching: .button)["Done"] + waitForExists(element: done, waitSeconds: waitingTimeout) + done.tapFrameCenter() + + // Wait for auto close action + sleep(10) + + verifyPostEvents(expectClick: true) } } - func testNoClickthrough () { + func testNoClickthrough() { repeatTesting(times: 7) { openVideoAndWait(title: videoRewardedEndCardTitle) - - closeAndVerifyPostEvents(expectClick: false) + // Wait for auto close action + sleep(10) + verifyPostEvents(expectClick: false) } } func testAutoClose() { repeatTesting(times: 7) { openVideoAndWait(title: videoRewardedTitle) - verifyPostEvents(expectClick: false) } } @@ -92,7 +95,7 @@ class PrebidRewardedVideoUITest: RepeatedUITestCase { done.tapFrameCenter() } else { let closeBtn = app.buttons["PBMCloseButton"] - waitForExists(element: closeBtn, waitSeconds: 5) + waitForExists(element: closeBtn, waitSeconds: 10) closeBtn.tap() } diff --git a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidServerUITests.swift b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidServerUITests.swift index 677070eb6..88600e32b 100644 --- a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidServerUITests.swift +++ b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/PrebidServerUITests.swift @@ -127,23 +127,4 @@ class PrebidServerUITests: AdsLoaderUITestCase { func testGAMInterstitial_Video_VanillaPrebidOrder() { checkInterstitialLoadResult(exampleName: "Video Interstitial 320x480 (GAM) [Vanilla Prebid Order]") } - - // MARK: - Rewarded Video - - func testRewardedVideo() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 (In-App)") - } - - func testInAppRewarded_noBids() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 (In-App) [noBids]", - expectFailure: true) - } - - func testGAMRewarded() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 (GAM) [OK, Metadata]") - } - - func testGAMRewarded_noBids_gamAd() { - checkRewardedLoadResult(exampleName: "Video Rewarded 320x480 (GAM) [noBids, GAM Ad]") - } } diff --git a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/XCTestCaseExt.swift b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/XCTestCaseExt.swift index dfe039c15..d1cc56f65 100644 --- a/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/XCTestCaseExt.swift +++ b/InternalTestApp/PrebidMobileDemoRenderingUITests/UITests/XCTestCaseExt.swift @@ -113,6 +113,9 @@ extension XCTestCase { // MARK: - Helper methods (navigation) fileprivate func navigateToExample(app: XCUIApplication, title: String, file: StaticString = #file, line: UInt = #line) { + app.searchFields.element.tap() + app.searchFields.element.typeText(title) + let listItem = app.tables.staticTexts[title] waitForExists(element: listItem, waitSeconds: 5, file: file, line: line) listItem.tap() @@ -211,8 +214,6 @@ extension BaseUITestCase { } func navigateToExample(_ title: String, file: StaticString = #file, line: UInt = #line) { - applyFilter(adServer: detect(from: title)) - applyFilter(tag: detect(from: title)) navigateToExample(app: app, title: title, file: file, line: line) } diff --git a/PrebidMobile.xcodeproj/project.pbxproj b/PrebidMobile.xcodeproj/project.pbxproj index b1906de9d..b0730e457 100644 --- a/PrebidMobile.xcodeproj/project.pbxproj +++ b/PrebidMobile.xcodeproj/project.pbxproj @@ -504,7 +504,6 @@ 5BC37A8E271F1D0000444D5E /* RewardedAdUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784B271F1CFF00444D5E /* RewardedAdUnit.swift */; }; 5BC37A90271F1D0000444D5E /* InterstitialAdUnitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784D271F1CFF00444D5E /* InterstitialAdUnitDelegate.swift */; }; 5BC37A91271F1D0000444D5E /* InterstitialEventLoadingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784E271F1CFF00444D5E /* InterstitialEventLoadingDelegate.swift */; }; - 5BC37A92271F1D0000444D5E /* RewardedEventLoadingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC3784F271F1CFF00444D5E /* RewardedEventLoadingDelegate.swift */; }; 5BC37A93271F1D0000444D5E /* PBMInterstitialEventHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BC37850271F1CFF00444D5E /* PBMInterstitialEventHandler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5BC37A94271F1D0000444D5E /* BannerEventHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC37851271F1CFF00444D5E /* BannerEventHandler.swift */; }; 5BC37A95271F1D0000444D5E /* PBMPrimaryAdRequesterProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BC37852271F1CFF00444D5E /* PBMPrimaryAdRequesterProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1392,7 +1391,6 @@ 5BC3784B271F1CFF00444D5E /* RewardedAdUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardedAdUnit.swift; sourceTree = ""; }; 5BC3784D271F1CFF00444D5E /* InterstitialAdUnitDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterstitialAdUnitDelegate.swift; sourceTree = ""; }; 5BC3784E271F1CFF00444D5E /* InterstitialEventLoadingDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterstitialEventLoadingDelegate.swift; sourceTree = ""; }; - 5BC3784F271F1CFF00444D5E /* RewardedEventLoadingDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewardedEventLoadingDelegate.swift; sourceTree = ""; }; 5BC37850271F1CFF00444D5E /* PBMInterstitialEventHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBMInterstitialEventHandler.h; sourceTree = ""; }; 5BC37851271F1CFF00444D5E /* BannerEventHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BannerEventHandler.swift; sourceTree = ""; }; 5BC37852271F1CFF00444D5E /* PBMPrimaryAdRequesterProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBMPrimaryAdRequesterProtocol.h; sourceTree = ""; }; @@ -2617,7 +2615,6 @@ 5BC37845271F1CFF00444D5E /* RewardedAdUnitDelegate.swift */, 5BC37853271F1CFF00444D5E /* RewardedEventHandlerProtocol.swift */, 5BC37846271F1CFF00444D5E /* RewardedEventInteractionDelegate.swift */, - 5BC3784F271F1CFF00444D5E /* RewardedEventLoadingDelegate.swift */, 534C613B2CB536F00026119A /* RewardedConfig.swift */, ); path = GAM; @@ -4236,7 +4233,6 @@ 5BC37969271F1D0000444D5E /* PBMVastIcon.m in Sources */, FAEE4D12262DC2B200AD9966 /* RewardedVideoAdUnit.swift in Sources */, 5BC3795B271F1D0000444D5E /* PBMVastCreativeCompanionAdsCompanion.m in Sources */, - 5BC37A92271F1D0000444D5E /* RewardedEventLoadingDelegate.swift in Sources */, 53A657B02A8B64C200AE0B4F /* PBMORTBSDKConfiguration.m in Sources */, 92C85D5C27A96C680080BAC5 /* NativeImage.swift in Sources */, 5BC37A86271F1D0000444D5E /* BannerView.swift in Sources */, diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.m b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.m index b15985412..730ce78f3 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/AdLoading/PBMInterstitialAdLoader.m @@ -28,7 +28,7 @@ #import #endif -@interface PBMInterstitialAdLoader () +@interface PBMInterstitialAdLoader () @property (nonatomic, weak, nullable, readonly) id delegate; @property (nonatomic, weak, nullable, readonly) id eventHandler; @@ -132,6 +132,4 @@ - (void)failedWithError:(nullable NSError *)error { [self.flowDelegate adLoader:self failedWithPrimarySDKError:error]; } -@synthesize reward; - @end diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift index f00d098f5..4d7f833db 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/BaseRewardedAdUnit.swift @@ -33,13 +33,21 @@ class BaseRewardedAdUnit: BaseInterstitialAdUnit, RewardedEventInteractionDelega adUnitConfig.adConfiguration.isRewarded = true } + // MARK: - InterstitialControllerInteractionDelegate + override func trackUserReward(_ interstitialController: InterstitialController, _ reward: PrebidReward) { DispatchQueue.main.async { self.delegate?.callDelegate_rewardedAdUserDidEarnReward?(reward: reward) } } - func userDidEarnReward(_ reward: NSObject?) { - /// ?????? + // MARK: - RewardedEventInteractionDelegate + + func userDidEarnReward(_ reward: PrebidReward?) { + if let reward { + DispatchQueue.main.async { + self.delegate?.callDelegate_rewardedAdUserDidEarnReward?(reward: reward) + } + } } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift index 284fca86b..ab9d5fec7 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/PrebidReward.swift @@ -22,7 +22,8 @@ public class PrebidReward: NSObject { public var count: NSNumber? public var ext: [String: Any]? - init(with ortbReward: PBMORTBRewardedReward? = nil) { + convenience init(with ortbReward: PBMORTBRewardedReward? = nil) { + self.init() self.type = ortbReward?.type self.count = ortbReward?.count self.ext = ortbReward?.ext diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift index 7c4265193..4c5c757c7 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedAdUnit.swift @@ -366,7 +366,7 @@ public class RewardedAdUnit: NSObject, BaseInterstitialAdUnitProtocol { func callEventHandler_setLoadingDelegate(_ loadingDelegate: NSObject?) { if let eventHandler = eventHandler as? RewardedEventHandlerProtocol { - eventHandler.loadingDelegate = loadingDelegate as? RewardedEventLoadingDelegate + eventHandler.loadingDelegate = loadingDelegate as? InterstitialEventLoadingDelegate } } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventHandlerProtocol.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventHandlerProtocol.swift index f44615211..e5590aedd 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventHandlerProtocol.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventHandlerProtocol.swift @@ -21,7 +21,7 @@ import Foundation @objc public protocol RewardedEventHandlerProtocol: PBMInterstitialAd { /// Delegate for custom event handler to inform the PBM SDK about the events related to the ad server communication. - weak var loadingDelegate: RewardedEventLoadingDelegate? { get set } + weak var loadingDelegate: InterstitialEventLoadingDelegate? { get set } /// Delegate for custom event handler to inform the PBM SDK about the events related to the user's interaction with the ad. weak var interactionDelegate: RewardedEventInteractionDelegate? { get set } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift index 2f0771e17..a930e6633 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/GAM/RewardedEventInteractionDelegate.swift @@ -17,6 +17,6 @@ import Foundation @objc public protocol RewardedEventInteractionDelegate: InterstitialEventInteractionDelegate { - /// Call this when the ad server SDK decides the use has earned reward - func userDidEarnReward(_ reward: NSObject?) + /// Call this when the ad server SDK decides the user has earned reward + func userDidEarnReward(_ reward: PrebidReward?) } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/PBMStandaloneSDK/EventHandlers/RewardedEventHandlerStandalone.swift b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/PBMStandaloneSDK/EventHandlers/RewardedEventHandlerStandalone.swift index 54927562b..a1ba781cf 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/PBMStandaloneSDK/EventHandlers/RewardedEventHandlerStandalone.swift +++ b/PrebidMobile/PrebidMobileRendering/Prebid/Integrations/PBMStandaloneSDK/EventHandlers/RewardedEventHandlerStandalone.swift @@ -18,7 +18,7 @@ import UIKit public class RewardedEventHandlerStandalone: NSObject, RewardedEventHandlerProtocol { - public weak var loadingDelegate: RewardedEventLoadingDelegate? + public weak var loadingDelegate: InterstitialEventLoadingDelegate? public weak var interactionDelegate: RewardedEventInteractionDelegate? public var isReady: Bool { From 1fdab7933a8036fe15667ca667af2413826021c0 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Mon, 14 Oct 2024 10:31:18 +0300 Subject: [PATCH 13/18] clean: remove unneeded --- .build/workspace-state.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 .build/workspace-state.json diff --git a/.build/workspace-state.json b/.build/workspace-state.json deleted file mode 100644 index 71deae90f..000000000 --- a/.build/workspace-state.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "object" : { - "artifacts" : [ - - ], - "dependencies" : [ - - ] - }, - "version" : 6 -} \ No newline at end of file From 46918bc0ca5d69cf7b4b424ed96b5ba453474cb7 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Mon, 14 Oct 2024 11:17:59 +0300 Subject: [PATCH 14/18] feat: minor enhancement in demo apps --- .../Examples/AdMob/AdMobDisplayRewardedViewController.m | 1 + .../Examples/AdMob/AdMobVideoRewardedViewController.m | 1 + .../Examples/MAX/MAXDisplayRewardedViewController.m | 1 + .../Examples/MAX/MAXVideoRewardedViewController.m | 1 + .../Examples/AdMob/AdMobDisplayRewardedViewController.swift | 4 +++- .../Examples/AdMob/AdMobVideoRewardedViewController.swift | 4 +++- .../Examples/MAX/MAXDisplayRewardedViewController.swift | 4 +++- .../Examples/MAX/MAXVideoRewardedViewController.swift | 4 +++- 8 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m index bc87cdb09..7031294ba 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobDisplayRewardedViewController.m @@ -73,6 +73,7 @@ - (void)createAd { self.gadRewardedAd.fullScreenContentDelegate = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.gadRewardedAd presentFromRootViewController:self userDidEarnRewardHandler:^{ + NSLog(@"User did earn reward."); }]; }); } diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m index 5fe84d289..0b4aac480 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/AdMob/AdMobVideoRewardedViewController.m @@ -72,6 +72,7 @@ - (void)createAd { self.gadRewardedAd.fullScreenContentDelegate = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self.gadRewardedAd presentFromRootViewController:self userDidEarnRewardHandler:^{ + NSLog(@"User did earn reward."); }]; }); } diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m index 7f7b64ab6..2b3650ddb 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m @@ -87,6 +87,7 @@ - (void)didClickAd:(MAAd *)ad { } - (void)didRewardUserForAd:(MAAd *)ad withReward:(MAReward *)reward { + NSLog(@"User did earn reward: label - %@, amount - %ld", reward.label, reward.amount); } @end diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXVideoRewardedViewController.m index 7391b9f4e..eb5ca7daa 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXVideoRewardedViewController.m @@ -86,6 +86,7 @@ - (void)didClickAd:(MAAd *)ad { } - (void)didRewardUserForAd:(MAAd *)ad withReward:(MAReward *)reward { + NSLog(@"User did earn reward: label - %@, amount - %ld", reward.label, reward.amount); } @end diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift index 7b3607a38..7094d5245 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobDisplayRewardedViewController.swift @@ -67,7 +67,9 @@ class AdMobDisplayRewardedViewController: InterstitialBaseViewController, GADFul self.gadRewardedAd = ad self.gadRewardedAd?.fullScreenContentDelegate = self DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { - self.gadRewardedAd?.present(fromRootViewController: self, userDidEarnRewardHandler: {}) + self.gadRewardedAd?.present(fromRootViewController: self, userDidEarnRewardHandler: { + print("User did earn reward.") + }) } } } diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift index bfb1086e6..9c513665e 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/AdMob/AdMobVideoRewardedViewController.swift @@ -66,7 +66,9 @@ class AdMobVideoRewardedViewController: InterstitialBaseViewController, GADFullS DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { self.gadRewardedAd?.present( fromRootViewController: self, - userDidEarnRewardHandler: {} + userDidEarnRewardHandler: { + print("User did earn reward.") + } ) } } diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXDisplayRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXDisplayRewardedViewController.swift index b2a0ff2f5..3e0c4bcae 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXDisplayRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXDisplayRewardedViewController.swift @@ -79,5 +79,7 @@ class MAXDisplayRewardedViewController: InterstitialBaseViewController, MAReward func didClick(_ ad: MAAd) {} - func didRewardUser(for ad: MAAd, with reward: MAReward) {} + func didRewardUser(for ad: MAAd, with reward: MAReward) { + print("User did earn reward: label - \(reward.label), amount - \(reward.amount)") + } } diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXVideoRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXVideoRewardedViewController.swift index 618c50456..57d8e2025 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXVideoRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/MAX/MAXVideoRewardedViewController.swift @@ -79,5 +79,7 @@ class MAXVideoRewardedViewController: InterstitialBaseViewController, MARewarded func didClick(_ ad: MAAd) {} - func didRewardUser(for ad: MAAd, with reward: MAReward) {} + func didRewardUser(for ad: MAAd, with reward: MAReward) { + print("User did earn reward: label - \(reward.label), amount - \(reward.amount)") + } } From b17ae3bc5c335bb22446ed0d87450d62f4677fd0 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Mon, 14 Oct 2024 12:37:12 +0300 Subject: [PATCH 15/18] feat: minor changes --- .../GAMDisplayRewardedViewController.m | 4 ++ .../GAMVideoRewardedViewController.m | 4 ++ .../MAX/MAXDisplayRewardedViewController.m | 2 +- .../MAX/MAXVideoRewardedViewController.m | 2 +- .../InAppBannerRewardedViewController.swift | 54 ------------------- .../ConfigurationAndTargeting/Prebid.swift | 2 +- .../AdView/Modals/PBMModalViewController.m | 2 +- .../AdTypes/AdView/PBMWebView.m | 2 +- 8 files changed, 13 insertions(+), 59 deletions(-) delete mode 100644 Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppBannerRewardedViewController.swift diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m index ce8dd10c2..beaa27101 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m @@ -55,4 +55,8 @@ - (void)rewardedAd:(RewardedAdUnit *)rewardedAd didFailToReceiveAdWithError:(NSE PBMLogError(@"%@", error.localizedDescription); } +- (void)rewardedAdUserDidEarnReward:(RewardedAdUnit *)rewardedAd reward:(PrebidReward *)reward { + NSLog(@"User did earn reward - type: %@, count: %f", reward.type, [reward.count doubleValue]); +} + @end diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m index 7056dbb62..b5a04b2b6 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m @@ -55,4 +55,8 @@ - (void)rewardedAd:(RewardedAdUnit *)rewardedAd didFailToReceiveAdWithError:(NSE PBMLogError(@"%@", error.localizedDescription); } +- (void)rewardedAdUserDidEarnReward:(RewardedAdUnit *)rewardedAd reward:(PrebidReward *)reward { + NSLog(@"User did earn reward - type: %@, count: %f", reward.type, [reward.count doubleValue]); +} + @end diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m index 2b3650ddb..c43f765fa 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXDisplayRewardedViewController.m @@ -16,7 +16,7 @@ #import "MAXDisplayRewardedViewController.h" #import "PrebidDemoMacros.h" -NSString * const storedImpDisplayRewardedMAX = @"prebid-demo-video-rewarded-320-480"; +NSString * const storedImpDisplayRewardedMAX = @"prebid-demo-banner-rewarded-time"; NSString * const maxAdUnitDisplayRewardedId = @"75edc39e22574a9d"; @interface MAXDisplayRewardedViewController () diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXVideoRewardedViewController.m index eb5ca7daa..be2328b3d 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/MAX/MAXVideoRewardedViewController.m @@ -16,7 +16,7 @@ #import "MAXVideoRewardedViewController.h" #import "PrebidDemoMacros.h" -NSString * const storedImpVideoRewardedMAX = @"prebid-demo-video-rewarded-320-480"; +NSString * const storedImpVideoRewardedMAX = @"prebid-demo-video-rewarded-endcard-time"; NSString * const maxAdUnitRewardedId = @"75edc39e22574a9d"; @interface MAXVideoRewardedViewController () diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppBannerRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppBannerRewardedViewController.swift deleted file mode 100644 index a5f612eb3..000000000 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppBannerRewardedViewController.swift +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright 2019-2024 Prebid.org, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -import UIKit -import PrebidMobile - -fileprivate let storedImpBannerRewarded = "prebid-demo-banner-rewarded-time" - -class InAppDisplayRewardedViewController: InterstitialBaseViewController, RewardedAdUnitDelegate { - - // Prebid - private var rewardedAdUnit: RewardedAdUnit! - - override func loadView() { - super.loadView() - - createAd() - } - - func createAd() { - // 1. Create a RewardedAdUnit - rewardedAdUnit = RewardedAdUnit(configID: storedImpBannerRewarded) - rewardedAdUnit.delegate = self - - // 2. Load the rewarded ad - rewardedAdUnit.loadAd() - } - - // MARK: - RewardedAdUnitDelegate - - func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { - rewardedAdUnit.show(from: self) - } - - func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { - PrebidDemoLogger.shared.error("Rewarded ad unit did fail to receive ad: \(error?.localizedDescription ?? "")") - } - - func rewardedAdUserDidEarnReward(_ rewardedAd: RewardedAdUnit, reward: PrebidReward) { - PrebidDemoLogger.shared.info("User did earn reward: type - \(reward.type ?? ""), count - \(reward.count ?? 0)") - } -} diff --git a/PrebidMobile/ConfigurationAndTargeting/Prebid.swift b/PrebidMobile/ConfigurationAndTargeting/Prebid.swift index de2ec6461..db6438197 100644 --- a/PrebidMobile/ConfigurationAndTargeting/Prebid.swift +++ b/PrebidMobile/ConfigurationAndTargeting/Prebid.swift @@ -267,6 +267,6 @@ public class Prebid: NSObject { } public static func containsPluginRenderer(_ prebidMobilePluginRenderer: PrebidMobilePluginRenderer) { - _ = PrebidMobilePluginRegister.shared.containsPlugin(prebidMobilePluginRenderer); + PrebidMobilePluginRegister.shared.containsPlugin(prebidMobilePluginRenderer); } } diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m index 568759b7f..9b5cde61b 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/Modals/PBMModalViewController.m @@ -267,7 +267,7 @@ - (void)creativeDisplayCompleted:(PBMAbstractCreative *)creative { PBMCloseAction action = [PBMCloseActionManager getActionWithDescription:ortbAction]; - switch(action){ + switch(action) { case PBMCloseActionCloseButton: self.closeButtonDecorator.button.hidden = NO; break; diff --git a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.m b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.m index 586e1fad2..b5be2fd19 100644 --- a/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.m +++ b/PrebidMobile/PrebidMobileRendering/AdTypes/AdView/PBMWebView.m @@ -311,7 +311,7 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati return; } - //Identify and process Rewarded events + // Identify and process rewarded events if (self.rewardedAdURL) { if ([url.absoluteString isEqualToString:self.rewardedAdURL]) { @weakify(self); From 94761d8c75508cd71fec0550974c61a5d288354e Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Wed, 16 Oct 2024 13:38:26 +0300 Subject: [PATCH 16/18] feat: minor changes in demo apps --- .../PrebidDemo/PrebidDemo.xcodeproj/project.pbxproj | 12 ++++++------ .../RenderingAPI/GAMDisplayRewardedViewController.m | 4 +++- .../RenderingAPI/GAMVideoRewardedViewController.m | 4 +++- ...roller.h => InAppDisplayRewardedViewController.h} | 2 +- ...roller.m => InAppDisplayRewardedViewController.m} | 10 ++++++---- .../InApp/InAppVideoRewardedViewController.m | 4 +++- .../IntegrationCase/IntegrationCaseManager.m | 4 ++-- .../GAMDisplayRewardedViewController.swift | 4 +++- .../GAMVideoRewardedViewController.swift | 4 +++- .../In-App/InAppDisplayRewardedViewController.swift | 4 +++- .../In-App/InAppVideoRewardedViewController.swift | 4 +++- 11 files changed, 36 insertions(+), 20 deletions(-) rename Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/{InAppBannerRewardedViewController.h => InAppDisplayRewardedViewController.h} (87%) rename Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/{InAppBannerRewardedViewController.m => InAppDisplayRewardedViewController.m} (87%) diff --git a/Example/PrebidDemo/PrebidDemo.xcodeproj/project.pbxproj b/Example/PrebidDemo/PrebidDemo.xcodeproj/project.pbxproj index b5ced847a..31472ff3a 100644 --- a/Example/PrebidDemo/PrebidDemo.xcodeproj/project.pbxproj +++ b/Example/PrebidDemo/PrebidDemo.xcodeproj/project.pbxproj @@ -71,7 +71,7 @@ 534C614F2CB7F20A0026119A /* GAMDisplayRewardedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C614E2CB7F20A0026119A /* GAMDisplayRewardedViewController.swift */; }; 534C61552CB7F32D0026119A /* MAXDisplayRewardedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61542CB7F32D0026119A /* MAXDisplayRewardedViewController.swift */; }; 534C61572CB7F4780026119A /* AdMobDisplayRewardedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61562CB7F4780026119A /* AdMobDisplayRewardedViewController.swift */; }; - 534C615B2CB809F70026119A /* InAppBannerRewardedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C615A2CB809F70026119A /* InAppBannerRewardedViewController.m */; }; + 534C615B2CB809F70026119A /* InAppDisplayRewardedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C615A2CB809F70026119A /* InAppDisplayRewardedViewController.m */; }; 534C615E2CB84DCB0026119A /* AdMobDisplayRewardedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C615D2CB84DCB0026119A /* AdMobDisplayRewardedViewController.m */; }; 534C61612CB850FD0026119A /* GAMDisplayRewardedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61602CB850FD0026119A /* GAMDisplayRewardedViewController.m */; }; 534C61642CB851C10026119A /* MAXDisplayRewardedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 534C61632CB851C10026119A /* MAXDisplayRewardedViewController.m */; }; @@ -285,8 +285,8 @@ 534C614E2CB7F20A0026119A /* GAMDisplayRewardedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GAMDisplayRewardedViewController.swift; sourceTree = ""; }; 534C61542CB7F32D0026119A /* MAXDisplayRewardedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MAXDisplayRewardedViewController.swift; sourceTree = ""; }; 534C61562CB7F4780026119A /* AdMobDisplayRewardedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdMobDisplayRewardedViewController.swift; sourceTree = ""; }; - 534C61592CB809F70026119A /* InAppBannerRewardedViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InAppBannerRewardedViewController.h; sourceTree = ""; }; - 534C615A2CB809F70026119A /* InAppBannerRewardedViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InAppBannerRewardedViewController.m; sourceTree = ""; }; + 534C61592CB809F70026119A /* InAppDisplayRewardedViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InAppDisplayRewardedViewController.h; sourceTree = ""; }; + 534C615A2CB809F70026119A /* InAppDisplayRewardedViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InAppDisplayRewardedViewController.m; sourceTree = ""; }; 534C615C2CB84DCB0026119A /* AdMobDisplayRewardedViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AdMobDisplayRewardedViewController.h; sourceTree = ""; }; 534C615D2CB84DCB0026119A /* AdMobDisplayRewardedViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AdMobDisplayRewardedViewController.m; sourceTree = ""; }; 534C615F2CB850FD0026119A /* GAMDisplayRewardedViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GAMDisplayRewardedViewController.h; sourceTree = ""; }; @@ -883,8 +883,8 @@ 53F35F332926BAFE001C1183 /* InAppVideoInterstitialVerticalViewController.m */, 53F35F352926BCAF001C1183 /* InAppVideoInterstitialLandscapeViewController.h */, 53F35F362926BCAF001C1183 /* InAppVideoInterstitialLandscapeViewController.m */, - 534C61592CB809F70026119A /* InAppBannerRewardedViewController.h */, - 534C615A2CB809F70026119A /* InAppBannerRewardedViewController.m */, + 534C61592CB809F70026119A /* InAppDisplayRewardedViewController.h */, + 534C615A2CB809F70026119A /* InAppDisplayRewardedViewController.m */, 53F35F382926BDB7001C1183 /* InAppVideoRewardedViewController.h */, 53F35F392926BDB7001C1183 /* InAppVideoRewardedViewController.m */, 53F35F3B2926BF39001C1183 /* InAppNativeViewController.h */, @@ -1587,7 +1587,7 @@ 539F960629DEEA0A0061E7A5 /* GAMOriginalAPIMultiformatBannerViewController.m in Sources */, 53BA02B4292531D000BE6015 /* AppDelegate.m in Sources */, 539929072926580B0078053C /* GAMOriginalAPINativeBannerViewController.m in Sources */, - 534C615B2CB809F70026119A /* InAppBannerRewardedViewController.m in Sources */, + 534C615B2CB809F70026119A /* InAppDisplayRewardedViewController.m in Sources */, 53F35F492926CFE3001C1183 /* MAXVideoInterstitialViewController.m in Sources */, 53F35F03292671E7001C1183 /* GAMDisplayBannerViewController.m in Sources */, 533784CC2AC2CFF5009A8650 /* GAMOriginalAPIMultiformatNativeStylesViewController.m in Sources */, diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m index beaa27101..cbde008df 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.m @@ -48,7 +48,9 @@ - (void)createAd { // MARK: - RewardedAdUnitDelegate - (void)rewardedAdDidReceiveAd:(RewardedAdUnit *)rewardedAd { - [self.rewardedAdUnit showFrom:self]; + if (rewardedAd.isReady) { + [rewardedAd showFrom:self]; + } } - (void)rewardedAd:(RewardedAdUnit *)rewardedAd didFailToReceiveAdWithError:(NSError *)error { diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m index b5a04b2b6..e457dbdc9 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.m @@ -48,7 +48,9 @@ - (void)createAd { // MARK: - RewardedAdUnitDelegate - (void)rewardedAdDidReceiveAd:(RewardedAdUnit *)rewardedAd { - [self.rewardedAdUnit showFrom:self]; + if (rewardedAd.isReady) { + [rewardedAd showFrom:self]; + } } - (void)rewardedAd:(RewardedAdUnit *)rewardedAd didFailToReceiveAdWithError:(NSError *)error { diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.h b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppDisplayRewardedViewController.h similarity index 87% rename from Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.h rename to Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppDisplayRewardedViewController.h index 8e154366d..1bf2222d3 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.h +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppDisplayRewardedViewController.h @@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN -@interface InAppBannerRewardedViewController : InterstitialBaseViewController +@interface InAppDisplayRewardedViewController : InterstitialBaseViewController @end diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppDisplayRewardedViewController.m similarity index 87% rename from Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.m rename to Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppDisplayRewardedViewController.m index c271c8adc..a2df4fadc 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppBannerRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppDisplayRewardedViewController.m @@ -13,19 +13,19 @@ limitations under the License. */ -#import "InAppBannerRewardedViewController.h" +#import "InAppDisplayRewardedViewController.h" #import "PrebidDemoMacros.h" NSString * const storedImpBannerRewardedInApp = @"prebid-demo-banner-rewarded-time"; -@interface InAppBannerRewardedViewController () +@interface InAppDisplayRewardedViewController () // Prebid @property (nonatomic) RewardedAdUnit * rewardedAdUnit; @end -@implementation InAppBannerRewardedViewController +@implementation InAppDisplayRewardedViewController - (void)loadView { [super loadView]; @@ -45,7 +45,9 @@ - (void)createAd { // MARK: - RewardedAdUnitDelegate - (void)rewardedAdDidReceiveAd:(RewardedAdUnit *)rewardedAd { - [self.rewardedAdUnit showFrom:self]; + if (rewardedAd.isReady) { + [rewardedAd showFrom:self]; + } } - (void)rewardedAd:(RewardedAdUnit *)rewardedAd didFailToReceiveAdWithError:(NSError *)error { diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppVideoRewardedViewController.m b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppVideoRewardedViewController.m index 8f8e5c389..ab468ea73 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppVideoRewardedViewController.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/Examples/InApp/InAppVideoRewardedViewController.m @@ -45,7 +45,9 @@ - (void)createAd { // MARK: - RewardedAdUnitDelegate - (void)rewardedAdDidReceiveAd:(RewardedAdUnit *)rewardedAd { - [self.rewardedAdUnit showFrom:self]; + if (rewardedAd.isReady) { + [rewardedAd showFrom:self]; + } } - (void)rewardedAd:(RewardedAdUnit *)rewardedAd didFailToReceiveAdWithError:(NSError *)error { diff --git a/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/IntegrationCaseManager.m b/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/IntegrationCaseManager.m index 17cdc1b2c..b2f5959f5 100644 --- a/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/IntegrationCaseManager.m +++ b/Example/PrebidDemo/PrebidDemoObjectiveC/IntegrationCase/IntegrationCaseManager.m @@ -35,7 +35,7 @@ #import "InAppVideoInterstitialViewController.h" #import "InAppVideoInterstitialVerticalViewController.h" #import "InAppVideoInterstitialLandscapeViewController.h" -#import "InAppBannerRewardedViewController.h" +#import "InAppDisplayRewardedViewController.h" #import "InAppVideoRewardedViewController.h" #import "InAppNativeViewController.h" @@ -256,7 +256,7 @@ @implementation IntegrationCaseManager integrationKind:IntegrationKindInApp adFormat:AdFormatVideoRewarded configurationClosure:^UIViewController *{ - return [[InAppBannerRewardedViewController alloc] init]; + return [[InAppDisplayRewardedViewController alloc] init]; } ], diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.swift index 398b24941..9d9f4022d 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMDisplayRewardedViewController.swift @@ -51,7 +51,9 @@ class GAMDisplayRewardedViewController: InterstitialBaseViewController, Rewarded // MARK: - RewardedAdUnitDelegate func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { - rewardedAdUnit.show(from: self) + if rewardedAd.isReady { + rewardedAd.show(from: self) + } } func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.swift index 6645321e1..d65795608 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/GAM/RenderingAPI/GAMVideoRewardedViewController.swift @@ -51,7 +51,9 @@ class GAMVideoRewardedViewController: InterstitialBaseViewController, RewardedAd // MARK: - RewardedAdUnitDelegate func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { - rewardedAdUnit.show(from: self) + if rewardedAd.isReady { + rewardedAd.show(from: self) + } } func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppDisplayRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppDisplayRewardedViewController.swift index d7eff816a..8b80d702e 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppDisplayRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppDisplayRewardedViewController.swift @@ -41,7 +41,9 @@ class InAppDisplayRewardedViewController: InterstitialBaseViewController, Reward // MARK: - RewardedAdUnitDelegate func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { - rewardedAdUnit.show(from: self) + if rewardedAd.isReady { + rewardedAd.show(from: self) + } } func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { diff --git a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoRewardedViewController.swift b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoRewardedViewController.swift index 9f530158e..69d5b642a 100644 --- a/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoRewardedViewController.swift +++ b/Example/PrebidDemo/PrebidDemoSwift/Examples/In-App/InAppVideoRewardedViewController.swift @@ -41,7 +41,9 @@ class InAppVideoRewardedViewController: InterstitialBaseViewController, Rewarded // MARK: - RewardedAdUnitDelegate func rewardedAdDidReceiveAd(_ rewardedAd: RewardedAdUnit) { - rewardedAdUnit.show(from: self) + if rewardedAd.isReady { + rewardedAd.show(from: self) + } } func rewardedAd(_ rewardedAd: RewardedAdUnit, didFailToReceiveAdWithError error: Error?) { From 2cdae11b2dc3f3ba747607bd0657854ed023d20d Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Fri, 25 Oct 2024 09:54:15 +0300 Subject: [PATCH 17/18] fix: avoid probable crash by converting nsnull to nil --- PrebidMobile.xcodeproj/project.pbxproj | 8 +++++++ .../NSObject+PBMExtensions.h | 22 +++++++++++++++++ .../NSObject+PBMExtensions.m | 24 +++++++++++++++++++ .../ORTB/PBMORTBAbstract+Protected.h | 1 + .../ORTB/Prebid/PBMORTBRewardedClose.m | 4 ++-- .../ORTB/Prebid/PBMORTBRewardedCompletion.m | 4 ++-- .../Prebid/PBMORTBRewardedCompletionBanner.m | 4 ++-- .../Prebid/PBMORTBRewardedCompletionVideo.m | 6 ++--- .../PBMORTBRewardedCompletionVideoEndcard.m | 4 ++-- .../Prebid/PBMORTBRewardedConfiguration.m | 6 ++--- .../ORTB/Prebid/PBMORTBRewardedReward.m | 6 ++--- 11 files changed, 72 insertions(+), 17 deletions(-) create mode 100644 PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/NSObject+PBMExtensions.h create mode 100644 PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/NSObject+PBMExtensions.m diff --git a/PrebidMobile.xcodeproj/project.pbxproj b/PrebidMobile.xcodeproj/project.pbxproj index b0730e457..1fe7c0b11 100644 --- a/PrebidMobile.xcodeproj/project.pbxproj +++ b/PrebidMobile.xcodeproj/project.pbxproj @@ -98,6 +98,8 @@ 534C61422CB55D980026119A /* BackgroundAwareTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61412CB55D980026119A /* BackgroundAwareTimer.swift */; }; 534C61442CB5619B0026119A /* MockVideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61432CB5619B0026119A /* MockVideoView.swift */; }; 534C61462CB562E40026119A /* CloseActionManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 534C61452CB562E40026119A /* CloseActionManagerTests.swift */; }; + 535145E02CCB758800D40B19 /* NSObject+PBMExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 535145DF2CCB758800D40B19 /* NSObject+PBMExtensions.m */; }; + 535145E12CCB758800D40B19 /* NSObject+PBMExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 535145DE2CCB758800D40B19 /* NSObject+PBMExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5355ACA929C454070014F16E /* VAST_with_empty_companion.xml in Resources */ = {isa = PBXBuildFile; fileRef = 5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */; }; 5355ACAB29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */; }; 536A39262A84C50F00B1CCEA /* StringExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */; }; @@ -981,6 +983,8 @@ 534C61412CB55D980026119A /* BackgroundAwareTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundAwareTimer.swift; sourceTree = ""; }; 534C61432CB5619B0026119A /* MockVideoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockVideoView.swift; sourceTree = ""; }; 534C61452CB562E40026119A /* CloseActionManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseActionManagerTests.swift; sourceTree = ""; }; + 535145DE2CCB758800D40B19 /* NSObject+PBMExtensions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+PBMExtensions.h"; sourceTree = ""; }; + 535145DF2CCB758800D40B19 /* NSObject+PBMExtensions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+PBMExtensions.m"; sourceTree = ""; }; 5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = VAST_with_empty_companion.xml; sourceTree = ""; }; 5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreativeModelCollectionMakerVASTTests.swift; sourceTree = ""; }; 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensionsTest.swift; sourceTree = ""; }; @@ -2030,6 +2034,8 @@ 53C925012990FB30009E6F94 /* String+Extensions.swift */, 53D3C38B2C2BEF9B0074D99B /* NSURL+PBMExtensions.h */, 53D3C38C2C2BEF9B0074D99B /* NSURL+PBMExtensions.m */, + 535145DE2CCB758800D40B19 /* NSObject+PBMExtensions.h */, + 535145DF2CCB758800D40B19 /* NSObject+PBMExtensions.m */, ); path = ExtensionsAndWrappers; sourceTree = ""; @@ -3457,6 +3463,7 @@ 5BC3796F271F1D0000444D5E /* PBMVastCreativeCompanionAdsCompanion.h in Headers */, 5BC378CA271F1CFF00444D5E /* PBMWeakTimerTargetBox.h in Headers */, 5BC37AC0271F1D0100444D5E /* PBMURLComponents.h in Headers */, + 535145E12CCB758800D40B19 /* NSObject+PBMExtensions.h in Headers */, 5BC37A08271F1D0000444D5E /* PBMExternalURLOpenCallbacks.h in Headers */, 5BC37ACC271F1D0100444D5E /* PBMORTBParameterBuilder.h in Headers */, 5BC37A70271F1D0000444D5E /* PBMORTBAbstractResponse+Protected.h in Headers */, @@ -4176,6 +4183,7 @@ 5BC378F9271F1CFF00444D5E /* PBMORTBPublisher.m in Sources */, 534C61362CB529240026119A /* PBMORTBRewardedClose.m in Sources */, 5BC379D6271F1D0000444D5E /* PBMWebView.m in Sources */, + 535145E02CCB758800D40B19 /* NSObject+PBMExtensions.m in Sources */, 92AFE57F274FCD9900B0430C /* PBMORTBAppContent.m in Sources */, 92664569272AB9120064F7BD /* SkadnEventTracker.swift in Sources */, 5BC37A62271F1D0000444D5E /* PBMORTBBidExtPrebidCacheBids.m in Sources */, diff --git a/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/NSObject+PBMExtensions.h b/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/NSObject+PBMExtensions.h new file mode 100644 index 000000000..61a37639d --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/NSObject+PBMExtensions.h @@ -0,0 +1,22 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ + +#import + +@interface NSObject (Prebid) + +- (id)nullToNil; + +@end diff --git a/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/NSObject+PBMExtensions.m b/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/NSObject+PBMExtensions.m new file mode 100644 index 000000000..16f78bb4e --- /dev/null +++ b/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/NSObject+PBMExtensions.m @@ -0,0 +1,24 @@ +/*   Copyright 2018-2024 Prebid.org, Inc. + +  Licensed under the Apache License, Version 2.0 (the "License"); +  you may not use this file except in compliance with the License. +  You may obtain a copy of the License at + +  http://www.apache.org/licenses/LICENSE-2.0 + +  Unless required by applicable law or agreed to in writing, software +  distributed under the License is distributed on an "AS IS" BASIS, +  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  See the License for the specific language governing permissions and +  limitations under the License. +  */ + +#import "NSObject+PBMExtensions.h" + +@implementation NSObject (Prebid) + +- (id)nullToNil { + return [self isKindOfClass:[NSNull class]] ? nil : self; +} + +@end diff --git a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBAbstract+Protected.h b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBAbstract+Protected.h index 59716f0f8..cb945dd86 100644 --- a/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBAbstract+Protected.h +++ b/PrebidMobile/PrebidMobileRendering/ORTB/PBMORTBAbstract+Protected.h @@ -19,6 +19,7 @@ #import "NSMutableDictionary+PBMExtensions.h" #import "PBMConstants.h" #import "PBMFunctions.h" +#import "NSObject+PBMExtensions.h" @interface PBMORTBAbstract () diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.m index 232728ee2..e319e875d 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedClose.m @@ -22,8 +22,8 @@ - (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { return nil; } - _postrewardtime = jsonDictionary[@"postrewardtime"]; - _action = jsonDictionary[@"action"]; + _postrewardtime = [jsonDictionary[@"postrewardtime"] nullToNil]; + _action = [jsonDictionary[@"action"] nullToNil]; return self; } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m index 2e0103927..2cbe95e79 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletion.m @@ -24,8 +24,8 @@ - (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { return nil; } - _banner = [[PBMORTBRewardedCompletionBanner alloc] initWithJsonDictionary:jsonDictionary[@"banner"]]; - _video = [[PBMORTBRewardedCompletionVideo alloc] initWithJsonDictionary:jsonDictionary[@"video"]]; + _banner = [[PBMORTBRewardedCompletionBanner alloc] initWithJsonDictionary:[jsonDictionary[@"banner"] nullToNil]]; + _video = [[PBMORTBRewardedCompletionVideo alloc] initWithJsonDictionary:[jsonDictionary[@"video"] nullToNil]]; return self; } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.m index 1b5d8469c..0bdf15557 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionBanner.m @@ -22,8 +22,8 @@ - (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { return nil; } - _time = jsonDictionary[@"time"]; - _event = jsonDictionary[@"event"]; + _time = [jsonDictionary[@"time"] nullToNil]; + _event = [jsonDictionary[@"event"] nullToNil]; return self; } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.m index f82272304..d8b21a1d9 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideo.m @@ -22,9 +22,9 @@ - (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { return nil; } - _time = jsonDictionary[@"time"]; - _playbackevent = jsonDictionary[@"playbackevent"]; - _endcard = [[PBMORTBRewardedCompletionVideoEndcard alloc] initWithJsonDictionary:jsonDictionary[@"endcard"]]; + _time = [jsonDictionary[@"time"] nullToNil]; + _playbackevent = [jsonDictionary[@"playbackevent"] nullToNil]; + _endcard = [[PBMORTBRewardedCompletionVideoEndcard alloc] initWithJsonDictionary:[jsonDictionary[@"endcard"] nullToNil]]; return self; } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.m index 9ed18305f..bfdd6740f 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedCompletionVideoEndcard.m @@ -22,8 +22,8 @@ - (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { return nil; } - _time = jsonDictionary[@"time"]; - _event = jsonDictionary[@"event"]; + _time = [jsonDictionary[@"time"] nullToNil]; + _event = [jsonDictionary[@"event"] nullToNil]; return self; } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.m index 359d306ca..cd7ce4721 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedConfiguration.m @@ -26,9 +26,9 @@ - (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { return nil; } - _reward = [[PBMORTBRewardedReward alloc] initWithJsonDictionary:jsonDictionary[@"reward"]]; - _completion = [[PBMORTBRewardedCompletion alloc] initWithJsonDictionary:jsonDictionary[@"completion"]]; - _close = [[PBMORTBRewardedClose alloc] initWithJsonDictionary:jsonDictionary[@"close"]]; + _reward = [[PBMORTBRewardedReward alloc] initWithJsonDictionary:[jsonDictionary[@"reward"] nullToNil]]; + _completion = [[PBMORTBRewardedCompletion alloc] initWithJsonDictionary:[jsonDictionary[@"completion"] nullToNil]]; + _close = [[PBMORTBRewardedClose alloc] initWithJsonDictionary:[jsonDictionary[@"close"] nullToNil]]; return self; } diff --git a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.m b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.m index 29176a679..8fb46ef99 100644 --- a/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.m +++ b/PrebidMobile/PrebidMobileRendering/Prebid/PBMCore/ORTB/Prebid/PBMORTBRewardedReward.m @@ -22,9 +22,9 @@ - (instancetype)initWithJsonDictionary:(PBMJsonDictionary *)jsonDictionary { return nil; } - _type = jsonDictionary[@"type"]; - _count = jsonDictionary[@"count"]; - _ext = jsonDictionary[@"ext"]; + _type = [jsonDictionary[@"type"] nullToNil]; + _count = [jsonDictionary[@"count"] nullToNil]; + _ext = [jsonDictionary[@"ext"] nullToNil]; return self; } From e2f65202a9de62958a01f634da517920d9d85620 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Fri, 25 Oct 2024 10:54:40 +0300 Subject: [PATCH 18/18] feat: update modulemap --- PrebidMobile/BuildFiles/PrebidMobile.modulemap | 1 + 1 file changed, 1 insertion(+) diff --git a/PrebidMobile/BuildFiles/PrebidMobile.modulemap b/PrebidMobile/BuildFiles/PrebidMobile.modulemap index 464cb6231..24d74803c 100644 --- a/PrebidMobile/BuildFiles/PrebidMobile.modulemap +++ b/PrebidMobile/BuildFiles/PrebidMobile.modulemap @@ -174,4 +174,5 @@ framework module PrebidMobile { header "PBMInterstitialAdLoaderDelegate.h" header "OMSDKVersionProvider.h" + header "NSObject+PBMExtensions.h" }