diff --git a/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj b/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj index bae98f082..aa9b01b76 100644 --- a/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj +++ b/InternalTestApp/InternalTestApp.xcodeproj/project.pbxproj @@ -39,6 +39,10 @@ 53514CEC2D08416B00A480C0 /* SampleInterstitialController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53514CDA2D08416B00A480C0 /* SampleInterstitialController.swift */; }; 53514CED2D08416B00A480C0 /* SampleAdView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53514CD82D08416B00A480C0 /* SampleAdView.swift */; }; 53514CEE2D08416B00A480C0 /* CustomRendererBannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53514CDE2D08416B00A480C0 /* CustomRendererBannerController.swift */; }; + 535ADDFB2D19731000DB888F /* PrebidUniversalCreativeTestingGAMController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535ADDFA2D19731000DB888F /* PrebidUniversalCreativeTestingGAMController.swift */; }; + 535ADDFC2D19731000DB888F /* PrebidUniversalCreativeTestingGAMController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535ADDFA2D19731000DB888F /* PrebidUniversalCreativeTestingGAMController.swift */; }; + 535ADDFE2D19A62C00DB888F /* PrebidUniversalCreativeTestingWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535ADDFD2D19A62C00DB888F /* PrebidUniversalCreativeTestingWebViewController.swift */; }; + 535ADDFF2D19A62C00DB888F /* PrebidUniversalCreativeTestingWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535ADDFD2D19A62C00DB888F /* PrebidUniversalCreativeTestingWebViewController.swift */; }; 5397BD142936185400ABDA22 /* PrebidOriginalAPIDisplayBannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5397BD132936185400ABDA22 /* PrebidOriginalAPIDisplayBannerController.swift */; }; 5397BD26293760F500ABDA22 /* PrebidOriginalAPIDisplayInterstitialController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5397BD25293760F500ABDA22 /* PrebidOriginalAPIDisplayInterstitialController.swift */; }; 5397BD2A29376C9700ABDA22 /* PrebidOriginalAPIVideoRewardedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5397BD2929376C9700ABDA22 /* PrebidOriginalAPIVideoRewardedController.swift */; }; @@ -393,6 +397,8 @@ 53514CDC2D08416B00A480C0 /* SampleModalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleModalViewController.swift; sourceTree = ""; }; 53514CDE2D08416B00A480C0 /* CustomRendererBannerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomRendererBannerController.swift; sourceTree = ""; }; 53514CDF2D08416B00A480C0 /* CustomRendererInterstitialController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomRendererInterstitialController.swift; sourceTree = ""; }; + 535ADDFA2D19731000DB888F /* PrebidUniversalCreativeTestingGAMController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidUniversalCreativeTestingGAMController.swift; sourceTree = ""; }; + 535ADDFD2D19A62C00DB888F /* PrebidUniversalCreativeTestingWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidUniversalCreativeTestingWebViewController.swift; sourceTree = ""; }; 5397BD132936185400ABDA22 /* PrebidOriginalAPIDisplayBannerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidOriginalAPIDisplayBannerController.swift; sourceTree = ""; }; 5397BD25293760F500ABDA22 /* PrebidOriginalAPIDisplayInterstitialController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidOriginalAPIDisplayInterstitialController.swift; sourceTree = ""; }; 5397BD2929376C9700ABDA22 /* PrebidOriginalAPIVideoRewardedController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidOriginalAPIVideoRewardedController.swift; sourceTree = ""; }; @@ -746,6 +752,8 @@ 5397BD312937895700ABDA22 /* PrebidOriginalAPIVideoInstreamViewController.swift */, 539F961329DEF2670061E7A5 /* PrebidOriginalAPIVideoInterstitialController.swift */, 5397BD2929376C9700ABDA22 /* PrebidOriginalAPIVideoRewardedController.swift */, + 535ADDFA2D19731000DB888F /* PrebidUniversalCreativeTestingGAMController.swift */, + 535ADDFD2D19A62C00DB888F /* PrebidUniversalCreativeTestingWebViewController.swift */, ); path = OriginalAPI; sourceTree = ""; @@ -1610,6 +1618,7 @@ 53ED2FF629798104007D13EE /* BaseConfigurationController.swift in Sources */, 53ED2FF729798104007D13EE /* NativeAsset+Extensions.swift in Sources */, 53ED2FF829798104007D13EE /* PrebidGAMNativeAdController.swift in Sources */, + 535ADDFE2D19A62C00DB888F /* PrebidUniversalCreativeTestingWebViewController.swift in Sources */, 53ED2FF929798104007D13EE /* PrebidOriginalAPIVideoInstreamViewController.swift in Sources */, 53ED2FFA29798104007D13EE /* PrebidAdMobBannerViewController.swift in Sources */, 53ED2FFB29798104007D13EE /* ConfigurableViewController.swift in Sources */, @@ -1639,6 +1648,7 @@ 53514CE52D08416B00A480C0 /* SampleInterstitialController.swift in Sources */, 53514CE62D08416B00A480C0 /* SampleAdView.swift in Sources */, 53514CE72D08416B00A480C0 /* CustomRendererBannerController.swift in Sources */, + 535ADDFC2D19731000DB888F /* PrebidUniversalCreativeTestingGAMController.swift in Sources */, 53ED300E29798104007D13EE /* NativeAdViewBoxProtocol.swift in Sources */, 53ED300F29798104007D13EE /* FormViewController+RowBuildHelpers.swift in Sources */, 53ED301029798104007D13EE /* PrebidGAMBannerController.swift in Sources */, @@ -1710,6 +1720,7 @@ 5B209B4A21075E0A00C0F5CE /* BaseConfigurationController.swift in Sources */, 92C4E60B27A2F5D900738370 /* NativeAsset+Extensions.swift in Sources */, 92102C6127B0F2FE003F12B2 /* PrebidGAMNativeAdController.swift in Sources */, + 535ADDFF2D19A62C00DB888F /* PrebidUniversalCreativeTestingWebViewController.swift in Sources */, 5397BD322937895700ABDA22 /* PrebidOriginalAPIVideoInstreamViewController.swift in Sources */, 92E92502276B299F002B57F3 /* PrebidAdMobBannerViewController.swift in Sources */, 5BCCA3D62136D2E800DA3B5A /* ConfigurableViewController.swift in Sources */, @@ -1739,6 +1750,7 @@ 53514CEC2D08416B00A480C0 /* SampleInterstitialController.swift in Sources */, 53514CED2D08416B00A480C0 /* SampleAdView.swift in Sources */, 53514CEE2D08416B00A480C0 /* CustomRendererBannerController.swift in Sources */, + 535ADDFB2D19731000DB888F /* PrebidUniversalCreativeTestingGAMController.swift in Sources */, 92F9A5D127A15BD1007B0B17 /* NativeAdViewBoxProtocol.swift in Sources */, 341CC3142562C9D000186F29 /* FormViewController+RowBuildHelpers.swift in Sources */, 3493021C2473F408004A6086 /* PrebidGAMBannerController.swift in Sources */, diff --git a/InternalTestApp/PrebidMobileDemoRendering/AppDelegate.swift b/InternalTestApp/PrebidMobileDemoRendering/AppDelegate.swift index c4c076b6a..1b46f832e 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/AppDelegate.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/AppDelegate.swift @@ -183,4 +183,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } + + } diff --git a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift index 781ad0c1a..b360132c6 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift +++ b/InternalTestApp/PrebidMobileDemoRendering/Model/TestCasesManager.swift @@ -467,6 +467,30 @@ struct TestCaseManager { setupCustomParams(for: interstitialController.prebidConfigId) }), + + // MARK: ---- Prebid Universal Creative Tests + + TestCase(title: "Prebid Universal Creative (GAM)", + tags: [.banner, .originalAPI, .server], + exampleVCStoryboardID: "AdapterViewController", + configurationClosure: { vc in + guard let adapterVC = vc as? AdapterViewController else { + return + } + + let bannerController = PrebidUniversalCreativeTestingGAMController(rootController: adapterVC) + bannerController.adSize = CGSize(width: 300, height: 250) + bannerController.gamAdUnitID = "/21808260008/puc-testing-secure-banner-300x250" + + adapterVC.setup(adapter: bannerController) + setupCustomParams(for: bannerController.prebidConfigId) + }), + + TestCase(title: "Prebid Universal Creative (WebView)", + tags: [.banner, .originalAPI, .server], + exampleVCStoryboardID: "PrebidUniversalCreativeTestingWebViewController", + configurationClosure: { vc in }), + // MARK: ---- Native (Original API) TestCase(title: "Native Banner (GAM Original) [OK, PUC]", diff --git a/InternalTestApp/PrebidMobileDemoRendering/Resources/Base.lproj/Main.storyboard b/InternalTestApp/PrebidMobileDemoRendering/Resources/Base.lproj/Main.storyboard index 571f4d114..36d32fa6b 100644 --- a/InternalTestApp/PrebidMobileDemoRendering/Resources/Base.lproj/Main.storyboard +++ b/InternalTestApp/PrebidMobileDemoRendering/Resources/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -376,6 +376,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OriginalAPI/PrebidUniversalCreativeTestingGAMController.swift b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OriginalAPI/PrebidUniversalCreativeTestingGAMController.swift new file mode 100644 index 000000000..e4b47246f --- /dev/null +++ b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OriginalAPI/PrebidUniversalCreativeTestingGAMController.swift @@ -0,0 +1,137 @@ +/*   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 GoogleMobileAds + +final class PrebidUniversalCreativeTestingGAMController: + NSObject, + AdaptedController, + PrebidConfigurableBannerController { + + var refreshInterval: TimeInterval = 0 + var prebidConfigId: String = "" + var gamAdUnitID: String = "" + var adSize = CGSize.zero + + let rootController: AdapterViewController + + private var gamBanner: GAMBannerView! + + private let bannerViewDidReceiveAd = EventReportContainer() + private let bannerViewDidFailToReceiveAd = EventReportContainer() + + private let configIdLabel: UILabel = { + let label = UILabel() + label.font = UIFont.systemFont(ofSize: 12) + return label + }() + + private let reloadButton = ThreadCheckingButton() + + init(rootController: AdapterViewController) { + self.rootController = rootController + super.init() + + setupAdapterController() + } + + func configurationController() -> BaseConfigurationController? { + return PrebidBannerConfigurationController(controller: self) + } + + func loadAd() { + configIdLabel.isHidden = false + configIdLabel.text = "AdUnit ID: \(gamAdUnitID)" + + gamBanner = GAMBannerView(adSize: GADAdSizeFromCGSize(adSize)) + gamBanner.adUnitID = gamAdUnitID + gamBanner.rootViewController = rootController + gamBanner.delegate = self + + rootController.bannerView?.addSubview(gamBanner) + + let gamRequest = GAMRequest() + gamBanner.load(gamRequest) + } + + @objc private func reload() { + reloadButton.isEnabled = false + let gamRequest = GAMRequest() + gamBanner.load(gamRequest) + } + + private func setupAdapterController() { + rootController.showButton.isHidden = true + + configIdLabel.isHidden = true + rootController.actionsView.addArrangedSubview(configIdLabel) + + reloadButton.addTarget(self, action: #selector(reload), for: .touchUpInside) + + setupActions() + } + + private func setupActions() { + rootController.setupAction(bannerViewDidReceiveAd, "bannerViewDidReceiveAd called", accessibilityLabel: "bannerViewDidReceiveAd called") + rootController.setupAction(bannerViewDidFailToReceiveAd, "bannerViewDidFailToReceiveAd called") + rootController.setupAction(reloadButton, "[Reload]") + } + + private func resetEvents() { + bannerViewDidReceiveAd.isEnabled = false + bannerViewDidFailToReceiveAd.isEnabled = false + reloadButton.isEnabled = true + } +} + +// MARK: - GADBannerViewDelegate + +extension PrebidUniversalCreativeTestingGAMController: GADBannerViewDelegate { + + func bannerViewDidReceiveAd(_ bannerView: GADBannerView) { + rootController.bannerView.backgroundColor = .clear + bannerViewDidReceiveAd.isEnabled = true + reloadButton.isEnabled = true + rootController.bannerView.constraints.first { $0.firstAttribute == .width }?.constant = 300 + rootController.bannerView.constraints.first { $0.firstAttribute == .height }?.constant = 250 + + let targetWebView = bannerView.allSubViewsOf(type: WKWebView.self).first + targetWebView?.navigationDelegate = self + } + + func bannerView(_ bannerView: GADBannerView, didFailToReceiveAdWithError error: any Error) { + resetEvents() + bannerViewDidFailToReceiveAd.isEnabled = true + print(error.localizedDescription) + } +} + +// MARK: - WKNavigationDelegate + +extension PrebidUniversalCreativeTestingGAMController: WKNavigationDelegate { + + func webView( + _ webView: WKWebView, + didReceive challenge: URLAuthenticationChallenge, + completionHandler: @MainActor @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void + ) { + if let serverTrust = challenge.protectionSpace.serverTrust { + let credential = URLCredential(trust: serverTrust) + completionHandler(.useCredential, credential) + } else { + print("Error: failed to get server trust.") + } + } +} diff --git a/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OriginalAPI/PrebidUniversalCreativeTestingWebViewController.swift b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OriginalAPI/PrebidUniversalCreativeTestingWebViewController.swift new file mode 100644 index 000000000..6d32108db --- /dev/null +++ b/InternalTestApp/PrebidMobileDemoRendering/ViewControllers/Adapters/Prebid/OriginalAPI/PrebidUniversalCreativeTestingWebViewController.swift @@ -0,0 +1,56 @@ +/*   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 +import WebKit + +final class PrebidUniversalCreativeTestingWebViewController: UIViewController { + + @IBOutlet weak var webView: WKWebView! + @IBOutlet weak var textField: UITextField! + + override func viewDidLoad() { + super.viewDidLoad() + + webView.navigationDelegate = self + } + + @IBAction func onOpenURLPressed(_ sender: Any) { + guard let urlString = textField.text, let url = URL(string: "\(urlString)") else { + return + } + + let request = URLRequest(url: url) + webView.load(request) + } +} + +// MARK: - WKNavigationDelegate + +extension PrebidUniversalCreativeTestingWebViewController: WKNavigationDelegate { + + func webView( + _ webView: WKWebView, + didReceive challenge: URLAuthenticationChallenge, + completionHandler: @MainActor @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void + ) { + if let serverTrust = challenge.protectionSpace.serverTrust { + let credential = URLCredential(trust: serverTrust) + completionHandler(.useCredential, credential) + } else { + print("Error: failed to get server trust.") + } + } +}