diff --git a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp.xcodeproj/project.pbxproj b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp.xcodeproj/project.pbxproj index 7241ba6..15f720d 100644 --- a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp.xcodeproj/project.pbxproj +++ b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp.xcodeproj/project.pbxproj @@ -8,8 +8,7 @@ /* Begin PBXBuildFile section */ A217470F29E79B5600EC20DF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217470E29E79B5600EC20DF /* AppDelegate.swift */; }; - A217471129E79B5600EC20DF /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217471029E79B5600EC20DF /* SceneDelegate.swift */; }; - A217471329E79B5600EC20DF /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217471229E79B5600EC20DF /* ViewController.swift */; }; + A217471329E79B5600EC20DF /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A217471229E79B5600EC20DF /* GameViewController.swift */; }; A217471629E79B5600EC20DF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A217471429E79B5600EC20DF /* Main.storyboard */; }; A217471829E79B5600EC20DF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A217471729E79B5600EC20DF /* Assets.xcassets */; }; A217471B29E79B5600EC20DF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A217471929E79B5600EC20DF /* LaunchScreen.storyboard */; }; @@ -18,13 +17,13 @@ E23A114D29E84C4800FAE364 /* uid2identity.json in Resources */ = {isa = PBXBuildFile; fileRef = E23A114929E84C4700FAE364 /* uid2identity.json */; }; E23A114E29E84C4800FAE364 /* String+AppExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E23A114A29E84C4800FAE364 /* String+AppExtensions.swift */; }; E23A114F29E84C4800FAE364 /* AppDataLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E23A114B29E84C4800FAE364 /* AppDataLoader.swift */; }; + E269E12D2A4F518500574FEF /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E269E12C2A4F518500574FEF /* StoreKit.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ A217470B29E79B5600EC20DF /* UID2GoogleGMADevelopmentApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UID2GoogleGMADevelopmentApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; A217470E29E79B5600EC20DF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - A217471029E79B5600EC20DF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - A217471229E79B5600EC20DF /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + A217471229E79B5600EC20DF /* GameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; A217471529E79B5600EC20DF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; A217471729E79B5600EC20DF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; A217471A29E79B5600EC20DF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -34,6 +33,7 @@ E23A114929E84C4700FAE364 /* uid2identity.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = uid2identity.json; sourceTree = ""; }; E23A114A29E84C4800FAE364 /* String+AppExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+AppExtensions.swift"; sourceTree = ""; }; E23A114B29E84C4800FAE364 /* AppDataLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDataLoader.swift; sourceTree = ""; }; + E269E12C2A4F518500574FEF /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -42,6 +42,7 @@ buildActionMask = 2147483647; files = ( A2E7019029E7A5DA00B9DFA1 /* UID2GMAPlugin in Frameworks */, + E269E12D2A4F518500574FEF /* StoreKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -71,8 +72,7 @@ children = ( E23A114729E84C2800FAE364 /* AppData */, A217470E29E79B5600EC20DF /* AppDelegate.swift */, - A217471029E79B5600EC20DF /* SceneDelegate.swift */, - A217471229E79B5600EC20DF /* ViewController.swift */, + A217471229E79B5600EC20DF /* GameViewController.swift */, A217471429E79B5600EC20DF /* Main.storyboard */, A217471729E79B5600EC20DF /* Assets.xcassets */, A217471929E79B5600EC20DF /* LaunchScreen.storyboard */, @@ -92,6 +92,7 @@ A2E7018E29E7A5DA00B9DFA1 /* Frameworks */ = { isa = PBXGroup; children = ( + E269E12C2A4F518500574FEF /* StoreKit.framework */, ); name = Frameworks; sourceTree = ""; @@ -203,12 +204,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A217471329E79B5600EC20DF /* ViewController.swift in Sources */, + A217471329E79B5600EC20DF /* GameViewController.swift in Sources */, E23A114E29E84C4800FAE364 /* String+AppExtensions.swift in Sources */, E23A114F29E84C4800FAE364 /* AppDataLoader.swift in Sources */, E23A114C29E84C4800FAE364 /* Date+AppExtensions.swift in Sources */, A217470F29E79B5600EC20DF /* AppDelegate.swift in Sources */, - A217471129E79B5600EC20DF /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -361,7 +361,7 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = UID2GoogleGMADevelopmentApp/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen.storyboard; INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; @@ -392,7 +392,7 @@ GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = UID2GoogleGMADevelopmentApp/Info.plist; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen.storyboard; INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; diff --git a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 6faf36d..b7509be 100644 --- a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", "state" : { - "revision" : "886501bfff8bd8cc22899de2c1779e479c96f9ff", - "version" : "10.3.0" + "revision" : "a6e24f2167295d95371bfc3049e47381a73a9e43", + "version" : "10.7.0" } }, { @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/IABTechLab/uid2-ios-sdk.git", "state" : { - "revision" : "9706cbc8959593a81e5aea82926bc41ac9bbb9d3", - "version" : "0.1.0" + "revision" : "6204cbc27ef3bd48065e1fbd355958a6f03e248c", + "version" : "0.2.0" } } ], diff --git a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/AppDelegate.swift b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/AppDelegate.swift index 8882c3e..1e949f6 100644 --- a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/AppDelegate.swift +++ b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/AppDelegate.swift @@ -11,27 +11,15 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. // Initialize Google Mobile Ads SDK - GADMobileAds.sharedInstance().start(completionHandler: nil) + GADMobileAds.sharedInstance().start() return true } - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - } diff --git a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/Base.lproj/Main.storyboard b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/Base.lproj/Main.storyboard index a3995d3..9055a38 100644 --- a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/Base.lproj/Main.storyboard +++ b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/Base.lproj/Main.storyboard @@ -1,48 +1,74 @@ - - - - + - - + - + - + - - + + - + - - - - - - - - + + + + - - + + + + + + + + + + - + + + - + - \ No newline at end of file + diff --git a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/GameViewController.swift b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/GameViewController.swift new file mode 100644 index 0000000..b3b3ac8 --- /dev/null +++ b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/GameViewController.swift @@ -0,0 +1,279 @@ +// +// GameViewController.swift +// UID2GoogleGMADevelopmentApp +// +// From: https://github.com/googleads/googleads-mobile-ios-examples/tree/main/Swift/admanager/AdManagerRewardedInterstitialExample +// +// Copyright (C) 2023 Google LLC +// +// 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 +import UID2 +import UIKit + +class GameViewController: UIViewController, GADFullScreenContentDelegate { + + private enum GameState: Int { + case notStarted + case playing + case paused + case ended + } + + /// The game length. + private static let gameLength = 5 + + /// The time length before an ad shows. + private static let adIntroLength = 3.0 + + /// The rewarded interstitial ad. + private var rewardedInterstitialAd: GADRewardedInterstitialAd? + + /// The countdown timer. + private var timer: Timer? + + /// The amount of time left in the game. + private var timeLeft = gameLength + + /// Number of coins the user has earned. + private var coinCount = 0 + + /// The state of the game. + private var gameState = GameState.notStarted + + /// The countdown timer label. + @IBOutlet weak var gameText: UILabel! + + /// The play again button. + @IBOutlet weak var playAgainButton: UIButton! + + /// Text that indicates current coin count. + @IBOutlet weak var coinCountLabel: UILabel! + + override func viewDidLoad() { + super.viewDidLoad() + + Task { + await loadUID2Identity() + let versionNumber = GADMobileAds.sharedInstance().versionNumber + print("Google Mobile Ads SDK version: \(versionNumber.majorVersion).\(versionNumber.minorVersion).\(versionNumber.patchVersion)") + } + + // Pause game when application enters background. + NotificationCenter.default.addObserver( + self, + selector: #selector(GameViewController.pauseGame), + name: UIApplication.didEnterBackgroundNotification, object: nil) + + // Resume game when application becomes active. + NotificationCenter.default.addObserver( + self, + selector: #selector(GameViewController.resumeGame), + name: UIApplication.didBecomeActiveNotification, object: nil) + + startNewGame() + } + + // MARK: - UID2 + + private func loadUID2Identity() async { + do { + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + + // Sample UID2Identity data + let uid2IdentityData = try AppDataLoader.load(fileName: "uid2identity", fileExtension: "json") + let uid2IdentityFromFile = try decoder.decode(UID2Identity.self, from: uid2IdentityData) + + // Emulate A UID2Identity With Valid Times + let identityExpires = Date(timeIntervalSinceNow: 60 * 60).millisecondsSince1970 + let refreshFrom = Date(timeIntervalSinceNow: 60 * 40).millisecondsSince1970 + let refreshExpires = Date(timeIntervalSinceNow: 60 * 50).millisecondsSince1970 + + let uid2Identity = UID2Identity(advertisingToken: uid2IdentityFromFile.advertisingToken, + refreshToken: uid2IdentityFromFile.refreshToken, + identityExpires: identityExpires, + refreshFrom: refreshFrom, + refreshExpires: refreshExpires, + refreshResponseKey: uid2IdentityFromFile.refreshResponseKey) + + await UID2Manager.shared.setIdentity(uid2Identity) + } catch { + print("Error loading UID2Identity") + } + } + + // MARK: - Game Logic + + private func startNewGame() { + if rewardedInterstitialAd == nil { + loadRewardedInterstitialAd() + } + + gameState = .playing + timeLeft = GameViewController.gameLength + playAgainButton.isHidden = true + updateTimeLeft() + timer = Timer.scheduledTimer( + timeInterval: 1.0, + target: self, + selector: #selector(GameViewController.decrementTimeLeft(_:)), + userInfo: nil, + repeats: true) + } + + private func loadRewardedInterstitialAd() { + let request = GAMRequest() + GADRewardedInterstitialAd.load( + withAdUnitID: "/21775744923/example/rewarded_interstitial", request: request + ) { (ad, error) in + if let error = error { + print("Failed to load rewarded interstitial ad with error: \(error.localizedDescription)") + self.playAgainButton.isHidden = false + return + } + self.rewardedInterstitialAd = ad + self.rewardedInterstitialAd?.fullScreenContentDelegate = self + } + } + + private func updateTimeLeft() { + gameText.text = "\(timeLeft) seconds left!" + } + + @objc private func decrementTimeLeft(_ timer: Timer) { + timeLeft -= 1 + updateTimeLeft() + if timeLeft == 0 { + endGame() + } + } + + private func earnCoins(_ coins: NSInteger) { + coinCount += coins + coinCountLabel.text = "Coins: \(self.coinCount)" + } + + @objc private func pauseGame() { + guard gameState == .playing else { + return + } + gameState = .paused + + // Prevent the timer from firing while app is in background. + timer?.invalidate() + timer = nil + } + + @objc private func resumeGame() { + guard gameState == .paused else { + return + } + gameState = .playing + + updateTimeLeft() + // Set the timer to start firing again. + timer = Timer.scheduledTimer( + timeInterval: 1.0, + target: self, + selector: #selector(GameViewController.decrementTimeLeft(_:)), + userInfo: nil, + repeats: true) + } + + private func endGame() { + gameState = .ended + self.earnCoins(1) + timer?.invalidate() + timer = nil + + var adCanceled = false + + let alert = UIAlertController( + title: "Game Over!", + message: + "Watch an ad for 10 more coins. Video starting in \(Int(GameViewController.adIntroLength)) seconds", + preferredStyle: .alert) + let alertAction = UIAlertAction( + title: "No, thanks", + style: .cancel + ) { action in + adCanceled = true + self.playAgainButton.isHidden = false + } + alert.addAction(alertAction) + self.present(alert, animated: true) { + DispatchQueue.main.asyncAfter(deadline: .now() + GameViewController.adIntroLength) { + self.dismiss(animated: true) { + if !adCanceled { + self.showRewardedInterstitialAd() + } + } + } + } + } + + private func showRewardedInterstitialAd() { + guard let ad = self.rewardedInterstitialAd else { + print("Ad wasn't ready") + return + } + ad.present(fromRootViewController: self) { + let reward = ad.adReward + print( + "Reward received with currency \(reward.amount), amount \(reward.amount.doubleValue)" + ) + self.earnCoins(reward.amount.intValue) + } + } + + // MARK: - Interstitial Button Actions + + @IBAction func playAgain(_ sender: AnyObject) { + startNewGame() + } + + // MARK: - GADFullScreenContentDelegate + + func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) { + print("Ad did present full screen content.") + } + + func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) + { + print("Ad failed to present full screen content with error \(error.localizedDescription).") + self.rewardedInterstitialAd = nil + self.playAgainButton.isHidden = false + } + + func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) { + print("Ad did dismiss full screen content.") + self.rewardedInterstitialAd = nil + self.playAgainButton.isHidden = false + } + + // MARK: - deinit + + deinit { + NotificationCenter.default.removeObserver( + self, + name: UIApplication.didEnterBackgroundNotification, object: nil) + NotificationCenter.default.removeObserver( + self, + name: UIApplication.didBecomeActiveNotification, object: nil) + } + +} diff --git a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/Info.plist b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/Info.plist index 9848495..9f87ee0 100644 --- a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/Info.plist +++ b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/Info.plist @@ -2,161 +2,142 @@ - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - - - GADApplicationIdentifier - ca-app-pub-3940256099942544~1458002511 - SKAdNetworkItems - - - SKAdNetworkIdentifier - cstr6suwn9.skadnetwork - - - SKAdNetworkIdentifier - 4fzdc2evr5.skadnetwork - - - SKAdNetworkIdentifier - 2fnua5tdw4.skadnetwork - - - SKAdNetworkIdentifier - ydx93a7ass.skadnetwork - - - SKAdNetworkIdentifier - 5a6flpkh64.skadnetwork - - - SKAdNetworkIdentifier - p78axxw29g.skadnetwork - - - SKAdNetworkIdentifier - v72qych5uu.skadnetwork - - - SKAdNetworkIdentifier - c6k4g5qg8m.skadnetwork - - - SKAdNetworkIdentifier - s39g8k73mm.skadnetwork - - - SKAdNetworkIdentifier - 3qy4746246.skadnetwork - - - SKAdNetworkIdentifier - 3sh42y64q3.skadnetwork - - - SKAdNetworkIdentifier - f38h382jlk.skadnetwork - - - SKAdNetworkIdentifier - hs6bdukanm.skadnetwork - - - SKAdNetworkIdentifier - prcb7njmu6.skadnetwork - - - SKAdNetworkIdentifier - wzmmz9fp6w.skadnetwork - - - SKAdNetworkIdentifier - yclnxrl5pm.skadnetwork - - - SKAdNetworkIdentifier - 4468km3ulz.skadnetwork - - - SKAdNetworkIdentifier - t38b2kh725.skadnetwork - - - SKAdNetworkIdentifier - 7ug5zh24hu.skadnetwork - - - SKAdNetworkIdentifier - 9rd848q2bz.skadnetwork - - - SKAdNetworkIdentifier - n6fk4nfna4.skadnetwork - - - SKAdNetworkIdentifier - kbd757ywx3.skadnetwork - - - SKAdNetworkIdentifier - 9t245vhmpl.skadnetwork - - - SKAdNetworkIdentifier - 2u9pt9hc89.skadnetwork - - - SKAdNetworkIdentifier - 8s468mfl3y.skadnetwork - - - SKAdNetworkIdentifier - av6w8kgt66.skadnetwork - - - SKAdNetworkIdentifier - klf5c3l5u5.skadnetwork - - - SKAdNetworkIdentifier - ppxm28t8ap.skadnetwork - - - SKAdNetworkIdentifier - 424m5254lk.skadnetwork - - - SKAdNetworkIdentifier - uw77j35x4d.skadnetwork - - - SKAdNetworkIdentifier - e5fvkxwrpn.skadnetwork - - - SKAdNetworkIdentifier - zq492l623r.skadnetwork - - - SKAdNetworkIdentifier - 3qcr597p9d.skadnetwork - - + GADApplicationIdentifier + ca-app-pub-3940256099942544~1458002511 + SKAdNetworkItems + + + SKAdNetworkIdentifier + cstr6suwn9.skadnetwork + + + SKAdNetworkIdentifier + 4fzdc2evr5.skadnetwork + + + SKAdNetworkIdentifier + 2fnua5tdw4.skadnetwork + + + SKAdNetworkIdentifier + ydx93a7ass.skadnetwork + + + SKAdNetworkIdentifier + 5a6flpkh64.skadnetwork + + + SKAdNetworkIdentifier + p78axxw29g.skadnetwork + + + SKAdNetworkIdentifier + v72qych5uu.skadnetwork + + + SKAdNetworkIdentifier + c6k4g5qg8m.skadnetwork + + + SKAdNetworkIdentifier + s39g8k73mm.skadnetwork + + + SKAdNetworkIdentifier + 3qy4746246.skadnetwork + + + SKAdNetworkIdentifier + 3sh42y64q3.skadnetwork + + + SKAdNetworkIdentifier + f38h382jlk.skadnetwork + + + SKAdNetworkIdentifier + hs6bdukanm.skadnetwork + + + SKAdNetworkIdentifier + prcb7njmu6.skadnetwork + + + SKAdNetworkIdentifier + wzmmz9fp6w.skadnetwork + + + SKAdNetworkIdentifier + yclnxrl5pm.skadnetwork + + + SKAdNetworkIdentifier + 4468km3ulz.skadnetwork + + + SKAdNetworkIdentifier + t38b2kh725.skadnetwork + + + SKAdNetworkIdentifier + 7ug5zh24hu.skadnetwork + + + SKAdNetworkIdentifier + 9rd848q2bz.skadnetwork + + + SKAdNetworkIdentifier + n6fk4nfna4.skadnetwork + + + SKAdNetworkIdentifier + kbd757ywx3.skadnetwork + + + SKAdNetworkIdentifier + 9t245vhmpl.skadnetwork + + + SKAdNetworkIdentifier + 2u9pt9hc89.skadnetwork + + + SKAdNetworkIdentifier + 8s468mfl3y.skadnetwork + + + SKAdNetworkIdentifier + av6w8kgt66.skadnetwork + + + SKAdNetworkIdentifier + klf5c3l5u5.skadnetwork + + + SKAdNetworkIdentifier + ppxm28t8ap.skadnetwork + + + SKAdNetworkIdentifier + 424m5254lk.skadnetwork + + + SKAdNetworkIdentifier + uw77j35x4d.skadnetwork + + + SKAdNetworkIdentifier + e5fvkxwrpn.skadnetwork + + + SKAdNetworkIdentifier + zq492l623r.skadnetwork + + + SKAdNetworkIdentifier + 3qcr597p9d.skadnetwork + + diff --git a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/SceneDelegate.swift b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/SceneDelegate.swift deleted file mode 100644 index 6016bb4..0000000 --- a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/SceneDelegate.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// SceneDelegate.swift -// UID2GoogleGMADevelopmentApp -// -// Created by Brad Leege on 4/12/23. -// - -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - guard let _ = (scene as? UIWindowScene) else { return } - } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - -} diff --git a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/ViewController.swift b/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/ViewController.swift deleted file mode 100644 index 827c0a6..0000000 --- a/Development/UID2GoogleGMADevelopmentApp/UID2GoogleGMADevelopmentApp/ViewController.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// ViewController.swift -// UID2GoogleGMADevelopmentApp -// -// See: https://github.com/googleads/googleads-mobile-ios-examples/tree/main/Swift/admob/BannerExample -// -// Created by Brad Leege on 4/12/23. -// - -import GoogleMobileAds -import UID2 -import UIKit - -class ViewController: UIViewController { - - /// The banner view. - @IBOutlet weak var bannerView: GADBannerView! - - override func viewDidLoad() { - super.viewDidLoad() - Task { - await loadUID2Identity() - print("Google Mobile Ads SDK version: \(GADMobileAds.sharedInstance().sdkVersion)") - bannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716" - bannerView.rootViewController = self - bannerView.load(GADRequest()) - } - } - - private func loadUID2Identity() async { - - do { - let decoder = JSONDecoder() - decoder.keyDecodingStrategy = .convertFromSnakeCase - - // Sample UID2Identity data - let uid2IdentityData = try AppDataLoader.load(fileName: "uid2identity", fileExtension: "json") - let uid2IdentityFromFile = try decoder.decode(UID2Identity.self, from: uid2IdentityData) - - // Emulate A UID2Identity With Valid Times - let identityExpires = Date(timeIntervalSinceNow: 60 * 60).millisecondsSince1970 - let refreshFrom = Date(timeIntervalSinceNow: 60 * 40).millisecondsSince1970 - let refreshExpires = Date(timeIntervalSinceNow: 60 * 50).millisecondsSince1970 - - let uid2Identity = UID2Identity(advertisingToken: uid2IdentityFromFile.advertisingToken, - refreshToken: uid2IdentityFromFile.refreshToken, - identityExpires: identityExpires, - refreshFrom: refreshFrom, - refreshExpires: refreshExpires, - refreshResponseKey: uid2IdentityFromFile.refreshResponseKey) - - await UID2Manager.shared.setIdentity(uid2Identity) - } catch { - print("Error loading UID2Identity") - } - - } - -} diff --git a/Package.swift b/Package.swift index 5f3d648..fb71898 100644 --- a/Package.swift +++ b/Package.swift @@ -16,7 +16,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/IABTechLab/uid2-ios-sdk.git", from: "0.2.0"), - .package(url: "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", "9.0.0"..<"11.0.0") + .package(url: "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", from: "10.7.0") ], targets: [ .target( diff --git a/Sources/UID2GMAPlugin/AdvertisingTokenNotFoundError.swift b/Sources/UID2GMAPlugin/AdvertisingTokenNotFoundError.swift new file mode 100644 index 0000000..9911c9a --- /dev/null +++ b/Sources/UID2GMAPlugin/AdvertisingTokenNotFoundError.swift @@ -0,0 +1,18 @@ +// +// AdvertisingTokenNotFoundError.swift +// +// +// Created by Brad Leege on 3/23/23. +// + +import Foundation + +/// Advertising Token Not Found for IMA Adapter +@objc(AdvertisingTokenNotFoundError) +public class AdvertisingTokenNotFoundError: NSError { + + convenience init() { + self.init(domain: "UID", code: 1) + } + +} diff --git a/Sources/UID2GMAPlugin/UID2GMAMediationAdapter.swift b/Sources/UID2GMAPlugin/UID2GMAMediationAdapter.swift index f19b6c1..888cb27 100644 --- a/Sources/UID2GMAPlugin/UID2GMAMediationAdapter.swift +++ b/Sources/UID2GMAPlugin/UID2GMAMediationAdapter.swift @@ -11,6 +11,7 @@ import UID2 /// Adapter to connect UID2 to Google Mobile Ads /// https://developers.google.com/admob/ios/open-bidding-adapter +@objc(UID2GMAMediationAdapter) class UID2GMAMediationAdapter: NSObject { required override init() { } @@ -30,7 +31,7 @@ extension UID2GMAMediationAdapter: GADRTBAdapter { func collectSignals(for params: GADRTBRequestParameters, completionHandler: @escaping GADRTBSignalCompletionHandler) { Task { guard let advertisingToken = await UID2Manager.shared.getAdvertisingToken() else { - completionHandler(nil, UID2GoogleAdapterErrors.advertisingTokenNotFoundForGMA) + completionHandler(nil, AdvertisingTokenNotFoundError()) return } completionHandler(advertisingToken, nil) diff --git a/Sources/UID2GMAPlugin/UID2GoogleAdapterErrors.swift b/Sources/UID2GMAPlugin/UID2GoogleAdapterErrors.swift deleted file mode 100644 index 83571fe..0000000 --- a/Sources/UID2GMAPlugin/UID2GoogleAdapterErrors.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// UID2GoogleAdapterErrors.swift -// -// -// Created by Brad Leege on 3/23/23. -// - -import Foundation - -/// Errors generated by UID2GooglePlugin -public enum UID2GoogleAdapterErrors: Error { - - /// Advertising Token Not Found for GMA Adapter - case advertisingTokenNotFoundForGMA - -} diff --git a/Tests/UID2GMAPluginTests/UID2GMAMediationAdapterTests.swift b/Tests/UID2GMAPluginTests/UID2GMAMediationAdapterTests.swift index e3f5175..022e082 100644 --- a/Tests/UID2GMAPluginTests/UID2GMAMediationAdapterTests.swift +++ b/Tests/UID2GMAPluginTests/UID2GMAMediationAdapterTests.swift @@ -94,12 +94,12 @@ final class UID2GMAMediationAdapterTests: XCTestCase { adapter.collectSignals(for: GADRTBRequestParameters(), completionHandler: { signal, error in - guard let error = error as? UID2GoogleAdapterErrors else { + guard let error = error as? AdvertisingTokenNotFoundError else { continuation.resume(throwing: "Error returned was not expected type.") return } - XCTAssertEqual(UID2GoogleAdapterErrors.advertisingTokenNotFoundForGMA, error) + XCTAssertEqual(AdvertisingTokenNotFoundError(), error) continuation.resume(returning: "Successful Test") @@ -110,11 +110,11 @@ final class UID2GMAMediationAdapterTests: XCTestCase { } + /// 🟩 - GMA Adapter Ad SDK Version Check Success func testAdSDKVersion() async throws { let adSDKVersion = UID2GMAMediationAdapter.adSDKVersion() let sdkVersion = await UID2Manager.shared.sdkVersion - XCTAssertEqual(sdkVersion.major, adSDKVersion.majorVersion) XCTAssertEqual(sdkVersion.minor, adSDKVersion.minorVersion)