From 0e57dc0fc34864ec773404c7bc0323d55e4bc5eb Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Mon, 29 Sep 2025 15:02:45 +0300 Subject: [PATCH 01/11] fix: crash in demo apps --- .../demo-ios-objc/GAMBannerViewController.m | 21 ++---- .../GAMBannerViewController.swift | 72 ++++++++----------- 2 files changed, 35 insertions(+), 58 deletions(-) diff --git a/demo-ios-objc/demo-ios-objc/GAMBannerViewController.m b/demo-ios-objc/demo-ios-objc/GAMBannerViewController.m index 443439e..cb28e54 100644 --- a/demo-ios-objc/demo-ios-objc/GAMBannerViewController.m +++ b/demo-ios-objc/demo-ios-objc/GAMBannerViewController.m @@ -72,22 +72,11 @@ - (IBAction)clearTargetingCache:(id)sender { - (void)addBannerViewToView:(UIView *)bannerView { bannerView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:bannerView]; - [self.view addConstraints:@[ - [NSLayoutConstraint constraintWithItem:bannerView - attribute:NSLayoutAttributeBottom - relatedBy:NSLayoutRelationEqual - toItem:self.view.safeAreaLayoutGuide.bottomAnchor - attribute:NSLayoutAttributeTop - multiplier:1 - constant:0], - [NSLayoutConstraint constraintWithItem:bannerView - attribute:NSLayoutAttributeCenterX - relatedBy:NSLayoutRelationEqual - toItem:self.view - attribute:NSLayoutAttributeCenterX - multiplier:1 - constant:0] - ]]; + + [NSLayoutConstraint activateConstraints:@[ + [bannerView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], + [bannerView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] + ]]; } @end diff --git a/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift b/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift index 94bb730..2b993dd 100644 --- a/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift +++ b/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift @@ -10,61 +10,61 @@ import UIKit import GoogleMobileAds class GAMBannerViewController: UIViewController { - + var bannerView: GADBannerView! - + //MARK: Properties @IBOutlet weak var loadBannerButton: UIButton! @IBOutlet weak var loadBannerFromCacheButton: UIButton! @IBOutlet weak var clearTargetingCacheButton: UIButton! @IBOutlet weak var targetingOutput: UITextView! - + override func viewDidLoad() { super.viewDidLoad() - + bannerView = GADBannerView(adSize: GADAdSizeBanner) addBannerViewToView(bannerView) bannerView.rootViewController = self } - + //MARK: Actions - + @IBAction func loadBannerWithTargeting(_ sender: UIButton) { do { targetingOutput.text = "Calling /targeting API...\n\n" - + try OPTABLE!.targeting() { result in var tdata: NSDictionary = [:] - + switch result { case .success(let keyvalues): print("[OptableSDK] Success on /targeting API call: \(keyvalues)") - + tdata = keyvalues - + DispatchQueue.main.async { self.targetingOutput.text += "Data: \(keyvalues)\n" } - + case .failure(let error): print("[OptableSDK] Error on /targeting API call: \(error)") DispatchQueue.main.async { self.targetingOutput.text += "Error: \(error)\n" } } - + self.loadBanner(adUnitID: "/22081946781/ios-sdk-demo/mobile-leaderboard", keyvalues: tdata) } } catch { print("[OptableSDK] Exception: \(error)") } } - + @IBAction func loadBannerWithTargetingFromCache(_ sender: UIButton) { var tdata: NSDictionary = [:] - + targetingOutput.text = "Checking local targeting cache...\n\n" - + let cachedValues = OPTABLE!.targetingFromCache() if (cachedValues != nil) { print("[OptableSDK] Cached targeting values found: \(cachedValues!)") @@ -73,26 +73,26 @@ class GAMBannerViewController: UIViewController { } else { targetingOutput.text += "Cache empty.\n" } - + self.loadBanner(adUnitID: "/22081946781/ios-sdk-demo/mobile-leaderboard", keyvalues: tdata) } - + @IBAction func clearTargetingCache(_ sender: UIButton) { targetingOutput.text = "Clearing local targeting cache.\n" OPTABLE!.targetingClearCache() } - + private func loadBanner(adUnitID: String, keyvalues: NSDictionary) { bannerView.adUnitID = adUnitID - + let req = GAMRequest() req.customTargeting = keyvalues as? [String: String] bannerView.load(req) - + witness() profile() } - + private func witness() { do { try OPTABLE!.witness(event: "GAMBannerViewController.loadBannerClicked", properties: ["example": "value"]) { result in @@ -102,7 +102,7 @@ class GAMBannerViewController: UIViewController { DispatchQueue.main.async { self.targetingOutput.text += "\nSuccess calling witness API to log loadBannerClicked event.\n" } - + case .failure(let error): print("[OptableSDK] Error on /witness API call: \(error)") DispatchQueue.main.async { @@ -114,7 +114,7 @@ class GAMBannerViewController: UIViewController { print("[OptableSDK] Exception: \(error)") } } - + private func profile() { do { try OPTABLE!.profile(traits: ["example": "value", "anotherExample": 123, "thirdExample": true ]) { result in @@ -124,7 +124,7 @@ class GAMBannerViewController: UIViewController { DispatchQueue.main.async { self.targetingOutput.text += "\nSuccess calling profile API to set example traits.\n" } - + case .failure(let error): print("[OptableSDK] Error on /profile API call: \(error)") DispatchQueue.main.async { @@ -136,26 +136,14 @@ class GAMBannerViewController: UIViewController { print("[OptableSDK] Exception: \(error)") } } - + private func addBannerViewToView(_ bannerView: GADBannerView) { bannerView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(bannerView) - view.addConstraints([ - NSLayoutConstraint(item: bannerView, - attribute: .bottom, - relatedBy: .equal, - toItem: view.safeAreaLayoutGuide.bottomAnchor, - attribute: .top, - multiplier: 1, - constant: 0), - NSLayoutConstraint(item: bannerView, - attribute: .centerX, - relatedBy: .equal, - toItem: view, - attribute: .centerX, - multiplier: 1, - constant: 0) + + NSLayoutConstraint.activate([ + bannerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), + bannerView.centerXAnchor.constraint(equalTo: view.centerXAnchor) ]) - } - + } } From a2d71a3f42b7f8cecfa8b5f9bb3304ebb1cdcd14 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Mon, 29 Sep 2025 15:13:10 +0300 Subject: [PATCH 02/11] feat: update to recommended settings --- OptableSDK.xcodeproj/project.pbxproj | 29 ++++++++++++------- .../xcschemes/OptableSDK.xcscheme | 2 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/OptableSDK.xcodeproj/project.pbxproj b/OptableSDK.xcodeproj/project.pbxproj index 2a92bce..d452c27 100644 --- a/OptableSDK.xcodeproj/project.pbxproj +++ b/OptableSDK.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -182,8 +182,9 @@ 6352AAF224EAD403002E66EB /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1160; - LastUpgradeCheck = 1200; + LastUpgradeCheck = 2600; ORGANIZATIONNAME = "Optable Technologies, Inc."; TargetAttributes = { 6352AAFA24EAD403002E66EB = { @@ -302,8 +303,10 @@ COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = QQ5D7M7URA; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -318,11 +321,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.2; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; VERSIONING_SYSTEM = "apple-generic"; @@ -366,8 +370,10 @@ COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = QQ5D7M7URA; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -376,10 +382,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.2; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; @@ -392,20 +399,23 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = QQ5D7M7URA; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Source/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); MARKETING_VERSION = 0.10.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = co.optable.OptableSDK; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -420,20 +430,23 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = QQ5D7M7URA; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Source/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); MARKETING_VERSION = 0.10.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = co.optable.OptableSDK; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -446,9 +459,7 @@ 6352AB1324EAD403002E66EB /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = QQ5D7M7URA; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -465,9 +476,7 @@ 6352AB1424EAD403002E66EB /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = QQ5D7M7URA; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/OptableSDK.xcodeproj/xcshareddata/xcschemes/OptableSDK.xcscheme b/OptableSDK.xcodeproj/xcshareddata/xcschemes/OptableSDK.xcscheme index df2a6e5..7a915cb 100644 --- a/OptableSDK.xcodeproj/xcshareddata/xcschemes/OptableSDK.xcscheme +++ b/OptableSDK.xcodeproj/xcshareddata/xcschemes/OptableSDK.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 29 Sep 2025 21:10:17 +0300 Subject: [PATCH 03/11] fix: warnings in demo apps --- demo-ios-objc/Podfile.lock | 2 +- .../demo-ios-objc.xcodeproj/project.pbxproj | 12 +++++++++- .../demo-ios-objc/Base.lproj/Main.storyboard | 23 ++++++++++--------- demo-ios-swift/Podfile.lock | 2 +- .../demo-ios-swift.xcodeproj/project.pbxproj | 12 +++++++++- .../demo-ios-swift/Base.lproj/Main.storyboard | 23 ++++++++++--------- 6 files changed, 48 insertions(+), 26 deletions(-) diff --git a/demo-ios-objc/Podfile.lock b/demo-ios-objc/Podfile.lock index f9ee963..f2a5ed5 100644 --- a/demo-ios-objc/Podfile.lock +++ b/demo-ios-objc/Podfile.lock @@ -76,4 +76,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 48d927338b39550c29272b694f6c18710f33f913 -COCOAPODS: 1.12.0 +COCOAPODS: 1.16.2 diff --git a/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj b/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj index 18443de..7ac60d3 100644 --- a/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj +++ b/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -350,10 +350,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-frameworks.sh\"\n"; @@ -411,10 +415,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-frameworks.sh\"\n"; @@ -611,6 +619,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "demo-ios-objc/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -634,6 +643,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "demo-ios-objc/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/demo-ios-objc/demo-ios-objc/Base.lproj/Main.storyboard b/demo-ios-objc/demo-ios-objc/Base.lproj/Main.storyboard index 25bcc98..ffaa446 100644 --- a/demo-ios-objc/demo-ios-objc/Base.lproj/Main.storyboard +++ b/demo-ios-objc/demo-ios-objc/Base.lproj/Main.storyboard @@ -1,8 +1,9 @@ - + - + + @@ -17,7 +18,7 @@ - + - + + + + + + + + + + - - - - + + + @@ -66,86 +76,120 @@ + + + + + + + + + - + - - - - + + + + - + - + - - - - + + + + + + + + + + - - + + + + + + + + - - - - - - - - - + + + + + + + + + - + - - - - + + + + + - + @@ -158,13 +202,51 @@ - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -176,5 +258,8 @@ + + + diff --git a/demo-ios-objc/demo-ios-objc/GAMBannerViewController.h b/demo-ios-objc/demo-ios-objc/GAMBannerViewController.h index d09a0a8..4b7e5d2 100644 --- a/demo-ios-objc/demo-ios-objc/GAMBannerViewController.h +++ b/demo-ios-objc/demo-ios-objc/GAMBannerViewController.h @@ -9,10 +9,14 @@ #import @interface GAMBannerViewController : UIViewController + +@property (weak, nonatomic) IBOutlet UIView *adPlaceholder; + @property (weak, nonatomic) IBOutlet UIButton *loadBannerButton; @property (weak, nonatomic) IBOutlet UIButton *cachedBannerButton; @property (weak, nonatomic) IBOutlet UIButton *clearTargetingCacheButton; @property (weak, nonatomic) IBOutlet UITextView *targetingOutput; - (IBAction)loadBannerWithTargeting:(id)sender; + @end diff --git a/demo-ios-objc/demo-ios-objc/GAMBannerViewController.m b/demo-ios-objc/demo-ios-objc/GAMBannerViewController.m index cb28e54..fd27a96 100644 --- a/demo-ios-objc/demo-ios-objc/GAMBannerViewController.m +++ b/demo-ios-objc/demo-ios-objc/GAMBannerViewController.m @@ -13,7 +13,9 @@ @import GoogleMobileAds; @interface GAMBannerViewController () + @property(nonatomic, strong) GADBannerView *bannerView; + @end @implementation GAMBannerViewController @@ -34,7 +36,7 @@ - (void)viewDidLoad { - (IBAction)loadBannerWithTargeting:(id)sender { NSError *error = nil; - [_targetingOutput setText:@"Calling /targeting API...\n\n"]; + [_targetingOutput setText:@"Calling /targeting API...\n"]; [OPTABLE targetingAndReturnError:&error]; [OPTABLE witness:@"GAMBannerViewController.loadBannerClicked" properties:@{ @"example": @"value" } error:&error]; @@ -65,17 +67,17 @@ - (IBAction)loadBannerWithTargetingFromCache:(id)sender { } - (IBAction)clearTargetingCache:(id)sender { - [_targetingOutput setText:@"Clearing local targeting cache.\n\n"]; + [_targetingOutput setText:@"🧹 Clearing local targeting cache.\n"]; [OPTABLE targetingClearCache]; } - (void)addBannerViewToView:(UIView *)bannerView { bannerView.translatesAutoresizingMaskIntoConstraints = NO; - [self.view addSubview:bannerView]; + [self.adPlaceholder addSubview:bannerView]; [NSLayoutConstraint activateConstraints:@[ - [bannerView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], - [bannerView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] + [bannerView.centerXAnchor constraintEqualToAnchor:self.adPlaceholder.centerXAnchor], + [bannerView.centerYAnchor constraintEqualToAnchor:self.adPlaceholder.centerYAnchor] ]]; } diff --git a/demo-ios-objc/demo-ios-objc/Info.plist b/demo-ios-objc/demo-ios-objc/Info.plist index 4c4eaca..d11a8fa 100644 --- a/demo-ios-objc/demo-ios-objc/Info.plist +++ b/demo-ios-objc/demo-ios-objc/Info.plist @@ -2,11 +2,6 @@ - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -27,6 +22,11 @@ LSRequiresIPhoneOS + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSUserTrackingUsageDescription To showcase the usage of IDFA to Optable customers and their partners SKAdNetworkItems @@ -68,15 +68,6 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight diff --git a/demo-ios-objc/demo-ios-objc/OptableSDKDelegate.h b/demo-ios-objc/demo-ios-objc/OptableSDKDelegate.h index c384e12..ae1a2f1 100644 --- a/demo-ios-objc/demo-ios-objc/OptableSDKDelegate.h +++ b/demo-ios-objc/demo-ios-objc/OptableSDKDelegate.h @@ -10,7 +10,9 @@ @import GoogleMobileAds; @interface OptableSDKDelegate: NSObject + @property(atomic, readwrite, strong) GADBannerView *bannerView; @property(atomic, readwrite, strong) UITextView *identifyOutput; @property(atomic, readwrite, strong) UITextView *targetingOutput; + @end diff --git a/demo-ios-objc/demo-ios-objc/OptableSDKDelegate.m b/demo-ios-objc/demo-ios-objc/OptableSDKDelegate.m index 700283e..67e0774 100644 --- a/demo-ios-objc/demo-ios-objc/OptableSDKDelegate.m +++ b/demo-ios-objc/demo-ios-objc/OptableSDKDelegate.m @@ -17,20 +17,28 @@ @implementation OptableSDKDelegate - (void)identifyOk:(NSHTTPURLResponse *)result { NSLog(@"[OptableSDK] Success on /identify API call. HTTP Status Code: %ld", result.statusCode); dispatch_async(dispatch_get_main_queue(), ^{ - [self.identifyOutput setText:[NSString stringWithFormat:@"%@\nSuccess", [self.identifyOutput text]]]; + [self.identifyOutput setText:[NSString stringWithFormat:@"%@\nāœ… Success", [self.identifyOutput text]]]; }); } - (void)identifyErr:(NSError *)error { NSLog(@"[OptableSDK] Error on /identify API call: %@", [error localizedDescription]); dispatch_async(dispatch_get_main_queue(), ^{ - [self.identifyOutput setText:[NSString stringWithFormat:@"Error: %@\n", [error localizedDescription]]]; + [self.identifyOutput setText:[NSString stringWithFormat:@"%@\n🚫 Error: %@\n", [self.identifyOutput text], [error localizedDescription]]]; }); } - (void)profileOk:(NSHTTPURLResponse *)result { NSLog(@"[OptableSDK] Success on /profile API call. HTTP Status Code: %ld", result.statusCode); + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.targetingOutput setText:[NSString stringWithFormat:@"%@\nāœ… Success calling profile API to set example traits.\n", [self.targetingOutput text]]]; + }); } - (void)profileErr:(NSError *)error { NSLog(@"[OptableSDK] Error on /profile API call: %@", [error localizedDescription]); + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.targetingOutput setText:[NSString stringWithFormat:@"%@\n🚫 Error: %@\n", [self.targetingOutput text], [error localizedDescription]]]; + }); } - (void)targetingOk:(NSDictionary *)result { // Update the GAM banner view with result targeting keyvalues: @@ -50,13 +58,21 @@ - (void)targetingErr:(NSError *)error { NSLog(@"[OptableSDK] Error on /targeting API call: %@", [error localizedDescription]); dispatch_async(dispatch_get_main_queue(), ^{ - [self.targetingOutput setText:[NSString stringWithFormat:@"Error: %@\n", [error localizedDescription]]]; + [self.targetingOutput setText:[NSString stringWithFormat:@"%@\n🚫 Error: %@\n", [self.targetingOutput text], [error localizedDescription]]]; }); } - (void)witnessOk:(NSHTTPURLResponse *)result { NSLog(@"[OptableSDK] Success on /witness API call. HTTP Status Code: %ld", result.statusCode); + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.targetingOutput setText:[NSString stringWithFormat:@"%@\nāœ… Success calling witness API to log loadBannerClicked event.\n", [self.targetingOutput text]]]; + }); } - (void)witnessErr:(NSError *)error { NSLog(@"[OptableSDK] Error on /witness API call: %@", [error localizedDescription]); + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.targetingOutput setText:[NSString stringWithFormat:@"%@\n🚫 Error: %@\n", [self.targetingOutput text], [error localizedDescription]]]; + }); } @end diff --git a/demo-ios-objc/demo-ios-objc/SceneDelegate.m b/demo-ios-objc/demo-ios-objc/SceneDelegate.m index ca6825e..12dd287 100644 --- a/demo-ios-objc/demo-ios-objc/SceneDelegate.m +++ b/demo-ios-objc/demo-ios-objc/SceneDelegate.m @@ -9,50 +9,7 @@ #import "SceneDelegate.h" @interface SceneDelegate () - @end @implementation SceneDelegate - - -- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)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). -} - - -- (void)sceneDidDisconnect:(UIScene *)scene { - // 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). -} - - -- (void)sceneDidBecomeActive:(UIScene *)scene { - // 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. -} - - -- (void)sceneWillResignActive:(UIScene *)scene { - // 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). -} - - -- (void)sceneWillEnterForeground:(UIScene *)scene { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. -} - - -- (void)sceneDidEnterBackground:(UIScene *)scene { - // 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. -} - - @end diff --git a/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj b/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj index 0d162b4..7994ab6 100644 --- a/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj +++ b/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj @@ -133,8 +133,8 @@ children = ( 6352AA5A24DC7AE9002E66EB /* AppDelegate.swift */, 6352AA5C24DC7AE9002E66EB /* SceneDelegate.swift */, - 6352AA5E24DC7AE9002E66EB /* IdentifyViewController.swift */, 631466EC24F7F555007DCA5D /* GAMBannerViewController.swift */, + 6352AA5E24DC7AE9002E66EB /* IdentifyViewController.swift */, 6352AA6024DC7AE9002E66EB /* Main.storyboard */, 6352AA6324DC7AEC002E66EB /* Assets.xcassets */, 6352AA6524DC7AEC002E66EB /* LaunchScreen.storyboard */, diff --git a/demo-ios-swift/demo-ios-swift/Base.lproj/Main.storyboard b/demo-ios-swift/demo-ios-swift/Base.lproj/Main.storyboard index 9ae0625..1bf46bf 100644 --- a/demo-ios-swift/demo-ios-swift/Base.lproj/Main.storyboard +++ b/demo-ios-swift/demo-ios-swift/Base.lproj/Main.storyboard @@ -1,6 +1,6 @@ - + @@ -14,49 +14,59 @@ - + - - + + - - - - + + + + + + + + + - - - - - + + + + + + + + + - - - - + + + @@ -66,12 +76,21 @@ + + + + + + + + + - + @@ -81,62 +100,87 @@ - + - + - - - - - + + + + + + + + + + - + + + + + + + + - - - - - - - - - + + + + + + + + + - + + @@ -145,7 +189,7 @@ - + @@ -158,13 +202,51 @@ - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -176,5 +258,8 @@ + + + diff --git a/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift b/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift index 2b993dd..0977f45 100644 --- a/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift +++ b/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift @@ -13,7 +13,9 @@ class GAMBannerViewController: UIViewController { var bannerView: GADBannerView! - //MARK: Properties + // MARK: Properties + + @IBOutlet weak var adPlaceholder: UIView! @IBOutlet weak var loadBannerButton: UIButton! @IBOutlet weak var loadBannerFromCacheButton: UIButton! @IBOutlet weak var clearTargetingCacheButton: UIButton! @@ -49,7 +51,7 @@ class GAMBannerViewController: UIViewController { case .failure(let error): print("[OptableSDK] Error on /targeting API call: \(error)") DispatchQueue.main.async { - self.targetingOutput.text += "Error: \(error)\n" + self.targetingOutput.text += "🚫 Error: \(error)\n" } } @@ -68,17 +70,17 @@ class GAMBannerViewController: UIViewController { let cachedValues = OPTABLE!.targetingFromCache() if (cachedValues != nil) { print("[OptableSDK] Cached targeting values found: \(cachedValues!)") - targetingOutput.text += "Found cached data: \(cachedValues!)\n" + targetingOutput.text += "\nFound cached data: \(cachedValues!)\n" tdata = cachedValues! } else { - targetingOutput.text += "Cache empty.\n" + targetingOutput.text += "\nCache empty.\n" } self.loadBanner(adUnitID: "/22081946781/ios-sdk-demo/mobile-leaderboard", keyvalues: tdata) } @IBAction func clearTargetingCache(_ sender: UIButton) { - targetingOutput.text = "Clearing local targeting cache.\n" + targetingOutput.text = "🧹 Clearing local targeting cache.\n" OPTABLE!.targetingClearCache() } @@ -100,13 +102,13 @@ class GAMBannerViewController: UIViewController { case .success(let response): print("[OptableSDK] Success on /witness API call: response.statusCode = \(response.statusCode)") DispatchQueue.main.async { - self.targetingOutput.text += "\nSuccess calling witness API to log loadBannerClicked event.\n" + self.targetingOutput.text += "\nāœ… Success calling witness API to log loadBannerClicked event.\n" } case .failure(let error): print("[OptableSDK] Error on /witness API call: \(error)") DispatchQueue.main.async { - self.targetingOutput.text += "\nError: \(error)" + self.targetingOutput.text += "\n🚫 Error: \(error)" } } } @@ -122,13 +124,13 @@ class GAMBannerViewController: UIViewController { case .success(let response): print("[OptableSDK] Success on /profile API call: response.statusCode = \(response.statusCode)") DispatchQueue.main.async { - self.targetingOutput.text += "\nSuccess calling profile API to set example traits.\n" + self.targetingOutput.text += "\nāœ… Success calling profile API to set example traits.\n" } case .failure(let error): print("[OptableSDK] Error on /profile API call: \(error)") DispatchQueue.main.async { - self.targetingOutput.text += "\nError: \(error)" + self.targetingOutput.text += "\n🚫 Error: \(error)" } } } @@ -139,11 +141,11 @@ class GAMBannerViewController: UIViewController { private func addBannerViewToView(_ bannerView: GADBannerView) { bannerView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(bannerView) + adPlaceholder.addSubview(bannerView) NSLayoutConstraint.activate([ - bannerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), - bannerView.centerXAnchor.constraint(equalTo: view.centerXAnchor) + bannerView.centerXAnchor.constraint(equalTo: adPlaceholder.centerXAnchor), + bannerView.centerYAnchor.constraint(equalTo: adPlaceholder.centerYAnchor) ]) } } diff --git a/demo-ios-swift/demo-ios-swift/IdentifyViewController.swift b/demo-ios-swift/demo-ios-swift/IdentifyViewController.swift index d01f28d..cd11738 100644 --- a/demo-ios-swift/demo-ios-swift/IdentifyViewController.swift +++ b/demo-ios-swift/demo-ios-swift/IdentifyViewController.swift @@ -10,17 +10,13 @@ import UIKit class IdentifyViewController: UIViewController { - //MARK: Properties + // MARK: Properties @IBOutlet weak var identifyInput: UITextField! @IBOutlet weak var identifyButton: UIButton! @IBOutlet weak var identifyIDFA: UISwitch! @IBOutlet weak var identifyOutput: UITextView! - override func viewDidLoad() { - super.viewDidLoad() - } - - //MARK: Actions + // MARK: Actions // dispatchIdentify() is the action invoked on a click on the "Identify" UIButton in our demo app. It initiates // a call to the OptableSDK.identify() API and prints debugging information to the UI and debug console. @@ -40,13 +36,13 @@ class IdentifyViewController: UIViewController { case .success(let response): print("[OptableSDK] Success on /identify API call: response.statusCode = \(response.statusCode)") DispatchQueue.main.async { - self.identifyOutput.text += "\nSuccess." + self.identifyOutput.text += "\nāœ… Success." } case .failure(let error): print("[OptableSDK] Error on /identify API call: \(error)") DispatchQueue.main.async { - self.identifyOutput.text += "\nError: \(error)" + self.identifyOutput.text += "\n🚫 Error: \(error)" } } } diff --git a/demo-ios-swift/demo-ios-swift/Info.plist b/demo-ios-swift/demo-ios-swift/Info.plist index a145cd5..1aac2df 100644 --- a/demo-ios-swift/demo-ios-swift/Info.plist +++ b/demo-ios-swift/demo-ios-swift/Info.plist @@ -2,22 +2,6 @@ - NSUserTrackingUsageDescription - To showcase the usage of IDFA to Optable customers and their partners - SKAdNetworkItems - - - SKAdNetworkIdentifier - cstr6suwn9.skadnetwork - - - GADIsAdManagerApp - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -34,8 +18,24 @@ 1.0 CFBundleVersion 1 + GADIsAdManagerApp + LSRequiresIPhoneOS + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSUserTrackingUsageDescription + To showcase the usage of IDFA to Optable customers and their partners + SKAdNetworkItems + + + SKAdNetworkIdentifier + cstr6suwn9.skadnetwork + + UIApplicationSceneManifest UIApplicationSupportsMultipleScenes @@ -66,15 +66,6 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight diff --git a/demo-ios-swift/demo-ios-swift/SceneDelegate.swift b/demo-ios-swift/demo-ios-swift/SceneDelegate.swift index 97b720e..f5e48c6 100644 --- a/demo-ios-swift/demo-ios-swift/SceneDelegate.swift +++ b/demo-ios-swift/demo-ios-swift/SceneDelegate.swift @@ -11,43 +11,4 @@ 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 neccessarily 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. - } - - } - From 1989612bc6176ba749bc05b17070f0b29f7a39eb Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Tue, 30 Sep 2025 11:54:50 +0300 Subject: [PATCH 05/11] feat: update docs formating --- Source/OptableSDK.swift | 274 ++++++++++++++++++++-------------------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/Source/OptableSDK.swift b/Source/OptableSDK.swift index 491baac..be2ec69 100644 --- a/Source/OptableSDK.swift +++ b/Source/OptableSDK.swift @@ -14,19 +14,19 @@ import CryptoKit import AppTrackingTransparency import AdSupport -// -// OptableDelegate is a delegate protocol that the caller may optionally use. Swift applications can choose to integrate using -// callbacks or the delegator pattern, whereas Objective-C apps must use the delegator pattern. -// -// The OptableDelegate protocol consists of implementing *Ok() and *Err() event handlers. The *Ok() handler will -// receive an NSDictionary when the delegate variant of the targeting() API is called, and an HTTPURLResponse in all other -// SDK APIs that do not return actual data on success (e.g., identify(), witness(), etc.) -// -// The *Err() handlers will be called with an NSError instance on SDK API errors. -// -// Finally note that for the delegate variant of SDK API methods, internal exceptions will result in setting the NSError -// object passed which is passed by reference to the method, and not calling the delegate. -// +/// +/// OptableDelegate is a delegate protocol that the caller may optionally use. Swift applications can choose to integrate using +/// callbacks or the delegator pattern, whereas Objective-C apps must use the delegator pattern. +/// +/// The OptableDelegate protocol consists of implementing *Ok() and *Err() event handlers. The *Ok() handler will +/// receive an NSDictionary when the delegate variant of the targeting() API is called, and an HTTPURLResponse in all other +/// SDK APIs that do not return actual data on success (e.g., identify(), witness(), etc.) +/// +/// The *Err() handlers will be called with an NSError instance on SDK API errors. +/// +/// Finally note that for the delegate variant of SDK API methods, internal exceptions will result in setting the NSError +/// object passed which is passed by reference to the method, and not calling the delegate. +/// @objc public protocol OptableDelegate { func identifyOk(_ result: HTTPURLResponse) @@ -39,16 +39,16 @@ public protocol OptableDelegate { func witnessErr(_ error: NSError) } -// -// OptableSDK exposes an API that is used by an iOS app developer integrating with an Optable Sandbox. -// -// An instance of OptableSDK refers to an Optable Sandbox specified by the caller via `host` and `app` arguments provided to the constructor. -// -// It is possible to create multiple instances of OptableSDK, should the developer want to integrate with multiple Sandboxes. -// -// The OptableSDK keeps some state in UserDefaults (https://developer.apple.com/documentation/foundation/userdefaults), a key/value store persisted -// across launches of the app. The state is therefore unique to the app+device, and not globally unique to the app across devices. -// +/// +/// OptableSDK exposes an API that is used by an iOS app developer integrating with an Optable Sandbox. +/// +/// An instance of OptableSDK refers to an Optable Sandbox specified by the caller via `host` and `app` arguments provided to the constructor. +/// +/// It is possible to create multiple instances of OptableSDK, should the developer want to integrate with multiple Sandboxes. +/// +/// The OptableSDK keeps some state in UserDefaults (https:///developer.apple.com/documentation/foundation/userdefaults), a key/value store persisted +/// across launches of the app. The state is therefore unique to the app+device, and not globally unique to the app across devices. +/// @objc public class OptableSDK: NSObject { @objc public var delegate: OptableDelegate? @@ -63,20 +63,20 @@ public class OptableSDK: NSObject { var config: Config var client: Client - // - // OptableSDK(host, app) returns an instance of the SDK configured to talk to the sandbox specified by host & app: - // + /// + /// OptableSDK(host, app) returns an instance of the SDK configured to talk to the sandbox specified by host & app: + /// @objc public init(host: String, app: String, insecure: Bool = false, useragent: String? = nil) { self.config = Config(host: host, app: app, insecure: insecure, useragent: useragent) self.client = Client(self.config) } - // - // identify(ids, completion) issues a call to the Optable Sandbox "identify" API, passing the specified - // list of type-prefixed IDs. It is asynchronous, and on completion it will call the specified completion handler, passing - // it either the HTTPURLResponse on success, or an OptableError on failure. - // + /// + /// identify(ids, completion) issues a call to the Optable Sandbox "identify" API, passing the specified + /// list of type-prefixed IDs. It is asynchronous, and on completion it will call the specified completion handler, passing + /// it either the HTTPURLResponse on success, or an OptableError on failure. + /// public func identify(ids: [String], _ completion: @escaping (Result) -> Void) throws -> Void { try Identify(config: self.config, client: self.client, ids: ids) { (data, response, error) in guard let response = response as? HTTPURLResponse, error == nil, data != nil else { @@ -100,12 +100,12 @@ public class OptableSDK: NSObject { }?.resume() } - // - // identify(ids) is the "delegate variant" of the identify(ids, completion) method. It wraps the latter with - // a delegator callback. - // - // This is the Objective-C compatible version of the identify(ids, completion) API. - // + /// + /// identify(ids) is the "delegate variant" of the identify(ids, completion) method. It wraps the latter with + /// a delegator callback. + /// + /// This is the Objective-C compatible version of the identify(ids, completion) API. + /// @objc public func identify(_ ids: [String]) throws -> Void { try self.identify(ids: ids) { result in @@ -118,14 +118,14 @@ public class OptableSDK: NSObject { } } - // - // identify(email, aaid, ppid, completion) issues a call to the Optable Sandbox "identify" API, passing it the SHA-256 - // of the caller-provided 'email' and, when specified via the 'aaid' Boolean, the Apple ID For Advertising (IDFA) - // associated with the device. When 'ppid' is provided as a string, it is also sent for identity resolution. - // - // The identify method is asynchronous, and on completion it will call the specified completion handler, passing - // it either the HTTPURLResponse on success, or an OptableError on failure. - // + /// + /// identify(email, aaid, ppid, completion) issues a call to the Optable Sandbox "identify" API, passing it the SHA-256 + /// of the caller-provided 'email' and, when specified via the 'aaid' Boolean, the Apple ID For Advertising (IDFA) + /// associated with the device. When 'ppid' is provided as a string, it is also sent for identity resolution. + /// + /// The identify method is asynchronous, and on completion it will call the specified completion handler, passing + /// it either the HTTPURLResponse on success, or an OptableError on failure. + /// public func identify(email: String, aaid: Bool = false, ppid: String = "", _ completion: @escaping (Result) -> Void) throws -> Void { var ids = [String]() @@ -154,12 +154,12 @@ public class OptableSDK: NSObject { try self.identify(ids: ids, completion) } - // - // identify(email, aaid, ppid) is the "delegate variant" of the identify(email, aaid, ppid, completion) method. - // It wraps the latter with a delegator callback. - // - // This is the Objective-C compatible version of the identify(email, aaid, ppid, completion) API. - // + /// + /// identify(email, aaid, ppid) is the "delegate variant" of the identify(email, aaid, ppid, completion) method. + /// It wraps the latter with a delegator callback. + /// + /// This is the Objective-C compatible version of the identify(email, aaid, ppid, completion) API. + /// @objc public func identify(_ email: String, aaid: Bool = false, ppid: String = "") throws -> Void { try self.identify(email: email, aaid: aaid, ppid: ppid) { result in @@ -172,16 +172,16 @@ public class OptableSDK: NSObject { } } - // - // targeting(completion) calls the Optable Sandbox "targeting" API, which returns the key-value targeting - // data matching the user/device/app. - // - // The targeting method is asynchronous, and on completion it will call the specified completion handler, - // passing it either the NSDictionary targeting data on success, or an OptableError on failure. - // - // On success, this method will also cache the resulting targeting data in client storage, which can - // be access using targetingFromCache(), and cleared using targetingClearCache(). - // + /// + /// targeting(completion) calls the Optable Sandbox "targeting" API, which returns the key-value targeting + /// data matching the user/device/app. + /// + /// The targeting method is asynchronous, and on completion it will call the specified completion handler, + /// passing it either the NSDictionary targeting data on success, or an OptableError on failure. + /// + /// On success, this method will also cache the resulting targeting data in client storage, which can + /// be access using targetingFromCache(), and cleared using targetingClearCache(). + /// public func targeting(_ completion: @escaping (Result) -> Void) throws -> Void { try Targeting(config: self.config, client: self.client) { (data, response, error) in guard let response = response as? HTTPURLResponse, error == nil, data != nil else { @@ -206,7 +206,7 @@ public class OptableSDK: NSObject { let keyvalues = try JSONSerialization.jsonObject(with: data ?? Data(), options: []) let result = keyvalues as? NSDictionary ?? NSDictionary() - // We cache the latest targeting result in client storage for targetingFromCache() users: + /// We cache the latest targeting result in client storage for targetingFromCache() users: self.client.storage.setTargeting(keyvalues as? [String: Any] ?? [String: Any]()) completion(.success(result)) @@ -216,12 +216,12 @@ public class OptableSDK: NSObject { }?.resume() } - // - // targeting() is the "delegate variant" of the targeting(completion) method. It wraps the latter with - // a delegator callback. - // - // This is the Objective-C compatible version of the targeting(completion) API. - // + /// + /// targeting() is the "delegate variant" of the targeting(completion) method. It wraps the latter with + /// a delegator callback. + /// + /// This is the Objective-C compatible version of the targeting(completion) API. + /// @objc public func targeting() throws -> Void { try self.targeting() { result in @@ -234,9 +234,9 @@ public class OptableSDK: NSObject { } } - // - // targetingFromCache() returns the previously cached targeting data, if any. - // + /// + /// targetingFromCache() returns the previously cached targeting data, if any. + /// @objc public func targetingFromCache() -> NSDictionary? { guard let keyvalues = self.client.storage.getTargeting() as NSDictionary? else { @@ -245,22 +245,22 @@ public class OptableSDK: NSObject { return keyvalues } - // - // targetingClearCache() clears any previously cached targeting data. - // + /// + /// targetingClearCache() clears any previously cached targeting data. + /// @objc public func targetingClearCache() -> Void { self.client.storage.clearTargeting() } - // - // witness(event, properties, completion) calls the Optable Sandbox "witness" API in order to log - // a specified 'event' (e.g., "app.screenView", "ui.buttonPressed"), with the specified keyvalue - // NSDictionary 'properties', which can be subsequently used for audience assembly. - // - // The witness method is asynchronous, and on completion it will call the specified completion handler, - // passing it either the HTTPURLResponse on success, or an OptableError on failure. - // + /// + /// witness(event, properties, completion) calls the Optable Sandbox "witness" API in order to log + /// a specified 'event' (e.g., "app.screenView", "ui.buttonPressed"), with the specified keyvalue + /// NSDictionary 'properties', which can be subsequently used for audience assembly. + /// + /// The witness method is asynchronous, and on completion it will call the specified completion handler, + /// passing it either the HTTPURLResponse on success, or an OptableError on failure. + /// public func witness(event: String, properties: NSDictionary, _ completion: @escaping (Result) -> Void) throws -> Void { try Witness(config: self.config, client: self.client, event: event, properties: properties) { (data, response, error) in guard let response = response as? HTTPURLResponse, error == nil else { @@ -284,12 +284,12 @@ public class OptableSDK: NSObject { }?.resume() } - // - // witness(event, properties) is the "delegate variant" of the witness(event, properties, completion) method. - // It wraps the latter with a delegator callback. - // - // This is the Objective-C compatible version of the witness(event, properties, completion) API. - // + /// + /// witness(event, properties) is the "delegate variant" of the witness(event, properties, completion) method. + /// It wraps the latter with a delegator callback. + /// + /// This is the Objective-C compatible version of the witness(event, properties, completion) API. + /// @objc public func witness(_ event: String, properties: NSDictionary) throws -> Void { try self.witness(event: event, properties: properties) { result in @@ -302,14 +302,14 @@ public class OptableSDK: NSObject { } } - // - // profile(traits, completion) calls the Optable Sandbox "profile" API in order to associate - // specified 'traits' (i.e., key-value pairs) with the user's device. The specified - // NSDictionary 'traits' can be subsequently used for audience assembly. - // - // The profile method is asynchronous, and on completion it will call the specified completion handler, - // passing it either the HTTPURLResponse on success, or an OptableError on failure. - // + /// + /// profile(traits, completion) calls the Optable Sandbox "profile" API in order to associate + /// specified 'traits' (i.e., key-value pairs) with the user's device. The specified + /// NSDictionary 'traits' can be subsequently used for audience assembly. + /// + /// The profile method is asynchronous, and on completion it will call the specified completion handler, + /// passing it either the HTTPURLResponse on success, or an OptableError on failure. + /// public func profile(traits: NSDictionary, _ completion: @escaping (Result) -> Void) throws -> Void { try Profile(config: self.config, client: self.client, traits: traits) { (data, response, error) in guard let response = response as? HTTPURLResponse, error == nil else { @@ -333,12 +333,12 @@ public class OptableSDK: NSObject { }?.resume() } - // - // profile(traits) is the "delegate variant" of the profile(traits, completion) method. - // It wraps the latter with a delegator callback. - // - // This is the Objective-C compatible version of the profile(traits, completion) API. - // + /// + /// profile(traits) is the "delegate variant" of the profile(traits, completion) method. + /// It wraps the latter with a delegator callback. + /// + /// This is the Objective-C compatible version of the profile(traits, completion) API. + /// @objc public func profile(traits: NSDictionary) throws -> Void { try self.profile(traits: traits) { result in @@ -351,9 +351,9 @@ public class OptableSDK: NSObject { } } - // - // eid(email) is a helper that returns type-prefixed SHA256(downcase(email)) - // + /// + /// eid(email) is a helper that returns type-prefixed SHA256(downcase(email)) + /// @objc public func eid(_ email: String) -> String { let pfx = "e:" @@ -383,39 +383,39 @@ public class OptableSDK: NSObject { }.joined() } - // - // aaid(idfa) is a helper that returns the type-prefixed Apple ID For Advertising - // + /// + /// aaid(idfa) is a helper that returns the type-prefixed Apple ID For Advertising + /// @objc public func aaid(_ idfa: String) -> String { return "a:" + idfa.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) } - // - // cid(ppid) is a helper that returns custom type-prefixed origin-provided PPID - // + /// + /// cid(ppid) is a helper that returns custom type-prefixed origin-provided PPID + /// @objc public func cid(_ ppid: String) -> String { return "c:" + ppid.trimmingCharacters(in: .whitespacesAndNewlines) } - // - // eidFromURL(urlString) is a helper that returns a type-prefixed ID based on - // the query string oeid=sha256value parameter in the specified urlString, if - // one is found. Otherwise, it returns an empty string. - // - // The use for this is when handling incoming universal links which might - // contain an "oeid" value with the SHA256(downcase(email)) of a user, such as - // encoded links in newsletter Emails sent by the application developer. Such - // hashed Email values can be used in calls to identify() - // + /// + /// eidFromURL(urlString) is a helper that returns a type-prefixed ID based on + /// the query string oeid=sha256value parameter in the specified urlString, if + /// one is found. Otherwise, it returns an empty string. + /// + /// The use for this is when handling incoming universal links which might + /// contain an "oeid" value with the SHA256(downcase(email)) of a user, such as + /// encoded links in newsletter Emails sent by the application developer. Such + /// hashed Email values can be used in calls to identify() + /// @objc public func eidFromURL(_ urlString: String) -> String { guard let url = URL(string: urlString) else { return "" } guard let urlc = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return "" } guard let urlqis = urlc.queryItems else { return "" } - // Look for an oeid parameter in the urlString: + /// Look for an oeid parameter in the urlString: var oeid = "" for qi: URLQueryItem in urlqis { guard let val = qi.value else { @@ -427,7 +427,7 @@ public class OptableSDK: NSObject { } } - // Check that oeid looks like a valid SHA256: + /// Check that oeid looks like a valid SHA256: let range = NSRange(location: 0, length: oeid.utf16.count) guard let regex = try? NSRegularExpression(pattern: "[a-f0-9]{64}", options: .caseInsensitive) else { return "" } if (oeid.count != 64) || (regex.firstMatch(in: oeid, options: [], range: range) == nil) { @@ -437,15 +437,15 @@ public class OptableSDK: NSObject { return "e:" + oeid.lowercased() } - // - // tryIdentifyFromURL(urlString) is a helper that attempts to find a valid-looking - // "oeid" parameter in the specified urlString's query string parameters and, if found, - // calls self.identify([oeid]). - // - // The use for this is when handling incoming universal links which might contain an - // "oeid" value with the SHA256(downcase(email)) of an incoming user, such as encoded - // links in newsletter Emails sent by the application developer. - // + /// + /// tryIdentifyFromURL(urlString) is a helper that attempts to find a valid-looking + /// "oeid" parameter in the specified urlString's query string parameters and, if found, + /// calls self.identify([oeid]). + /// + /// The use for this is when handling incoming universal links which might contain an + /// "oeid" value with the SHA256(downcase(email)) of an incoming user, such as encoded + /// links in newsletter Emails sent by the application developer. + /// @objc public func tryIdentifyFromURL(_ urlString: String) throws -> Void { let oeid = self.eidFromURL(urlString) @@ -455,11 +455,11 @@ public class OptableSDK: NSObject { } } - // - // OptableSDK.version returns the SDK version as a String. The version is based on the short - // version string set in the SDK project CFBundleShortVersionString. When the SDK is included via - // Cocoapods, it will be set automatically on `pod install` according to the podspec version. - // + /// + /// OptableSDK.version returns the SDK version as a String. The version is based on the short + /// version string set in the SDK project CFBundleShortVersionString. When the SDK is included via + /// Cocoapods, it will be set automatically on `pod install` according to the podspec version. + /// public static var version: String { guard let version = Bundle(for: OptableSDK.self).infoDictionary?["CFBundleShortVersionString"] as? String else { return "ios-unknown" From 11f002d023cbb4bd09d9c51295a0d3a722aa477b Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Thu, 9 Oct 2025 15:53:57 +0300 Subject: [PATCH 06/11] feat: update GMA SDK to 12.12.0 --- demo-ios-objc/Podfile.lock | 60 ++----------------- .../demo-ios-objc.xcodeproj/project.pbxproj | 44 +++++++++++--- demo-ios-objc/demo-ios-objc/Info.plist | 2 + demo-ios-swift/Podfile.lock | 60 ++----------------- .../demo-ios-swift.xcodeproj/project.pbxproj | 44 +++++++++++--- .../demo-ios-swift/AppDelegate.swift | 24 ++++---- .../GAMBannerViewController.swift | 8 +-- demo-ios-swift/demo-ios-swift/Info.plist | 2 + 8 files changed, 101 insertions(+), 143 deletions(-) diff --git a/demo-ios-objc/Podfile.lock b/demo-ios-objc/Podfile.lock index f2a5ed5..2fb5c4b 100644 --- a/demo-ios-objc/Podfile.lock +++ b/demo-ios-objc/Podfile.lock @@ -1,52 +1,8 @@ PODS: - - Google-Mobile-Ads-SDK (8.13.0): - - GoogleAppMeasurement (< 9.0, >= 7.0) + - Google-Mobile-Ads-SDK (12.12.0): - GoogleUserMessagingPlatform (>= 1.1) - - GoogleAppMeasurement (8.10.0): - - GoogleAppMeasurement/AdIdSupport (= 8.10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - - GoogleUtilities/MethodSwizzler (~> 7.6) - - GoogleUtilities/Network (~> 7.6) - - "GoogleUtilities/NSData+zlib (~> 7.6)" - - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (8.10.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 8.10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - - GoogleUtilities/MethodSwizzler (~> 7.6) - - GoogleUtilities/Network (~> 7.6) - - "GoogleUtilities/NSData+zlib (~> 7.6)" - - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (8.10.0): - - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - - GoogleUtilities/MethodSwizzler (~> 7.6) - - GoogleUtilities/Network (~> 7.6) - - "GoogleUtilities/NSData+zlib (~> 7.6)" - - nanopb (~> 2.30908.0) - - GoogleUserMessagingPlatform (2.0.0) - - GoogleUtilities/AppDelegateSwizzler (7.6.0): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Environment (7.6.0): - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.6.0): - - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (7.6.0): - - GoogleUtilities/Logger - - GoogleUtilities/Network (7.6.0): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.6.0)" - - GoogleUtilities/Reachability (7.6.0): - - GoogleUtilities/Logger - - nanopb (2.30908.0): - - nanopb/decode (= 2.30908.0) - - nanopb/encode (= 2.30908.0) - - nanopb/decode (2.30908.0) - - nanopb/encode (2.30908.0) + - GoogleUserMessagingPlatform (3.0.0) - OptableSDK (0.10.0) - - PromisesObjC (2.0.0) DEPENDENCIES: - Google-Mobile-Ads-SDK @@ -55,24 +11,16 @@ DEPENDENCIES: SPEC REPOS: trunk: - Google-Mobile-Ads-SDK - - GoogleAppMeasurement - GoogleUserMessagingPlatform - - GoogleUtilities - - nanopb - - PromisesObjC EXTERNAL SOURCES: OptableSDK: :path: "../" SPEC CHECKSUMS: - Google-Mobile-Ads-SDK: 05e5d68bb42a61b2e5bef336a52789785605aa22 - GoogleAppMeasurement: a3311dbcf3ea651e5a070fe8559b57c174ada081 - GoogleUserMessagingPlatform: ab890ce5f6620f293a21b6bdd82e416a2c73aeca - GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 - nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + Google-Mobile-Ads-SDK: 4dde70a8c18d96b14f9548759b8cec6ecb0bc3e6 + GoogleUserMessagingPlatform: f8d0cdad3ca835406755d0a69aa634f00e76d576 OptableSDK: fc5d3852c29fac1881b1d3ab6ea397de71c8cbf1 - PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 PODFILE CHECKSUM: 48d927338b39550c29272b694f6c18710f33f913 diff --git a/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj b/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj index 7ac60d3..28c87e2 100644 --- a/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj +++ b/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj @@ -201,6 +201,7 @@ 6320EEF62535F92300F76877 /* Frameworks */, 6320EEF72535F92300F76877 /* Resources */, 488A3D0FB1FEC17C93145EF4 /* [CP] Embed Pods Frameworks */, + A3A695A26763A7F969BB5E1A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -239,6 +240,7 @@ 6320EF1C2535F92600F76877 /* Frameworks */, 6320EF1D2535F92600F76877 /* Resources */, AB4697C1A666D79358A1D434 /* [CP] Embed Pods Frameworks */, + BBD55B57C4C9D1BE96E25EA6 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -350,14 +352,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-frameworks.sh\"\n"; @@ -407,6 +405,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + A3A695A26763A7F969BB5E1A /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; AB4697C1A666D79358A1D434 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -415,19 +430,32 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + BBD55B57C4C9D1BE96E25EA6 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/demo-ios-objc/demo-ios-objc/Info.plist b/demo-ios-objc/demo-ios-objc/Info.plist index d11a8fa..c85b0db 100644 --- a/demo-ios-objc/demo-ios-objc/Info.plist +++ b/demo-ios-objc/demo-ios-objc/Info.plist @@ -69,5 +69,7 @@ UIInterfaceOrientationPortrait + GADApplicationIdentifier + ca-app-pub-6766188723152719~7079124913 diff --git a/demo-ios-swift/Podfile.lock b/demo-ios-swift/Podfile.lock index 6e8e67b..e77c5d6 100644 --- a/demo-ios-swift/Podfile.lock +++ b/demo-ios-swift/Podfile.lock @@ -1,52 +1,8 @@ PODS: - - Google-Mobile-Ads-SDK (8.13.0): - - GoogleAppMeasurement (< 9.0, >= 7.0) + - Google-Mobile-Ads-SDK (12.11.0): - GoogleUserMessagingPlatform (>= 1.1) - - GoogleAppMeasurement (8.10.0): - - GoogleAppMeasurement/AdIdSupport (= 8.10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - - GoogleUtilities/MethodSwizzler (~> 7.6) - - GoogleUtilities/Network (~> 7.6) - - "GoogleUtilities/NSData+zlib (~> 7.6)" - - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (8.10.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 8.10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - - GoogleUtilities/MethodSwizzler (~> 7.6) - - GoogleUtilities/Network (~> 7.6) - - "GoogleUtilities/NSData+zlib (~> 7.6)" - - nanopb (~> 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (8.10.0): - - GoogleUtilities/AppDelegateSwizzler (~> 7.6) - - GoogleUtilities/MethodSwizzler (~> 7.6) - - GoogleUtilities/Network (~> 7.6) - - "GoogleUtilities/NSData+zlib (~> 7.6)" - - nanopb (~> 2.30908.0) - - GoogleUserMessagingPlatform (2.0.0) - - GoogleUtilities/AppDelegateSwizzler (7.6.0): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Environment (7.6.0): - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.6.0): - - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (7.6.0): - - GoogleUtilities/Logger - - GoogleUtilities/Network (7.6.0): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.6.0)" - - GoogleUtilities/Reachability (7.6.0): - - GoogleUtilities/Logger - - nanopb (2.30908.0): - - nanopb/decode (= 2.30908.0) - - nanopb/encode (= 2.30908.0) - - nanopb/decode (2.30908.0) - - nanopb/encode (2.30908.0) + - GoogleUserMessagingPlatform (3.0.0) - OptableSDK (0.10.0) - - PromisesObjC (2.0.0) DEPENDENCIES: - Google-Mobile-Ads-SDK @@ -55,24 +11,16 @@ DEPENDENCIES: SPEC REPOS: trunk: - Google-Mobile-Ads-SDK - - GoogleAppMeasurement - GoogleUserMessagingPlatform - - GoogleUtilities - - nanopb - - PromisesObjC EXTERNAL SOURCES: OptableSDK: :path: "../" SPEC CHECKSUMS: - Google-Mobile-Ads-SDK: 05e5d68bb42a61b2e5bef336a52789785605aa22 - GoogleAppMeasurement: a3311dbcf3ea651e5a070fe8559b57c174ada081 - GoogleUserMessagingPlatform: ab890ce5f6620f293a21b6bdd82e416a2c73aeca - GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 - nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + Google-Mobile-Ads-SDK: b833c723759e32bbaf06edaaf2293f08ed898232 + GoogleUserMessagingPlatform: f8d0cdad3ca835406755d0a69aa634f00e76d576 OptableSDK: fc5d3852c29fac1881b1d3ab6ea397de71c8cbf1 - PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 PODFILE CHECKSUM: a7bf67fad0ec61ca3a95f0f8a9aadf2c4fd2cd76 diff --git a/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj b/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj index 7994ab6..f4e17c3 100644 --- a/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj +++ b/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj @@ -197,6 +197,7 @@ 6352AA5524DC7AE9002E66EB /* Resources */, 63C1E32924EAD80B00C4FE51 /* Embed Frameworks */, CB6C39DB30FCBD8A10020CE8 /* [CP] Embed Pods Frameworks */, + E4BF60F1588582695FC58696 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -235,6 +236,7 @@ 6352AA7524DC7AEC002E66EB /* Frameworks */, 6352AA7624DC7AEC002E66EB /* Resources */, A4AD3035FC184EEC8114DE25 /* [CP] Embed Pods Frameworks */, + D947CAD4B818D4D20E781F9D /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -391,14 +393,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift-demo-ios-swiftUITests/Pods-demo-ios-swift-demo-ios-swiftUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift-demo-ios-swiftUITests/Pods-demo-ios-swift-demo-ios-swiftUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift-demo-ios-swiftUITests/Pods-demo-ios-swift-demo-ios-swiftUITests-frameworks.sh\"\n"; @@ -412,19 +410,49 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift/Pods-demo-ios-swift-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift/Pods-demo-ios-swift-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift/Pods-demo-ios-swift-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + D947CAD4B818D4D20E781F9D /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift-demo-ios-swiftUITests/Pods-demo-ios-swift-demo-ios-swiftUITests-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift-demo-ios-swiftUITests/Pods-demo-ios-swift-demo-ios-swiftUITests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift-demo-ios-swiftUITests/Pods-demo-ios-swift-demo-ios-swiftUITests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + E4BF60F1588582695FC58696 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift/Pods-demo-ios-swift-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift/Pods-demo-ios-swift-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-swift/Pods-demo-ios-swift-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/demo-ios-swift/demo-ios-swift/AppDelegate.swift b/demo-ios-swift/demo-ios-swift/AppDelegate.swift index 6474439..907de8b 100644 --- a/demo-ios-swift/demo-ios-swift/AppDelegate.swift +++ b/demo-ios-swift/demo-ios-swift/AppDelegate.swift @@ -30,17 +30,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // 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. + func application( + _ application: UIApplication, + configurationForConnecting connectingSceneSession: UISceneSession, + options: UIScene.ConnectionOptions + ) -> UISceneConfiguration { + return UISceneConfiguration( + name: "Default Configuration", + sessionRole: connectingSceneSession.role + ) } + func application( + _ application: UIApplication, + didDiscardSceneSessions sceneSessions: Set + ) {} } - diff --git a/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift b/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift index 0977f45..4a8fa0d 100644 --- a/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift +++ b/demo-ios-swift/demo-ios-swift/GAMBannerViewController.swift @@ -11,7 +11,7 @@ import GoogleMobileAds class GAMBannerViewController: UIViewController { - var bannerView: GADBannerView! + var bannerView: BannerView! // MARK: Properties @@ -24,7 +24,7 @@ class GAMBannerViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - bannerView = GADBannerView(adSize: GADAdSizeBanner) + bannerView = BannerView(adSize: AdSizeBanner) addBannerViewToView(bannerView) bannerView.rootViewController = self } @@ -87,7 +87,7 @@ class GAMBannerViewController: UIViewController { private func loadBanner(adUnitID: String, keyvalues: NSDictionary) { bannerView.adUnitID = adUnitID - let req = GAMRequest() + let req = AdManagerRequest() req.customTargeting = keyvalues as? [String: String] bannerView.load(req) @@ -139,7 +139,7 @@ class GAMBannerViewController: UIViewController { } } - private func addBannerViewToView(_ bannerView: GADBannerView) { + private func addBannerViewToView(_ bannerView: BannerView) { bannerView.translatesAutoresizingMaskIntoConstraints = false adPlaceholder.addSubview(bannerView) diff --git a/demo-ios-swift/demo-ios-swift/Info.plist b/demo-ios-swift/demo-ios-swift/Info.plist index 1aac2df..b4f6e77 100644 --- a/demo-ios-swift/demo-ios-swift/Info.plist +++ b/demo-ios-swift/demo-ios-swift/Info.plist @@ -2,6 +2,8 @@ + GADApplicationIdentifier + ca-app-pub-6766188723152719~7079124913 CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable From c706cf633ae58416dc14308b4f1784b76d14492c Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Fri, 10 Oct 2025 14:25:34 +0300 Subject: [PATCH 07/11] feat: set development team to none --- OptableSDK.xcodeproj/project.pbxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OptableSDK.xcodeproj/project.pbxproj b/OptableSDK.xcodeproj/project.pbxproj index d452c27..c9ea60b 100644 --- a/OptableSDK.xcodeproj/project.pbxproj +++ b/OptableSDK.xcodeproj/project.pbxproj @@ -402,6 +402,7 @@ CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -433,6 +434,7 @@ CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -477,6 +479,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", From 1edae9f968b1b76d4d0ce06f1c7fd5768a66a628 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Wed, 15 Oct 2025 11:03:02 +0300 Subject: [PATCH 08/11] feat: set dev team to none --- OptableSDK.xcodeproj/project.pbxproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OptableSDK.xcodeproj/project.pbxproj b/OptableSDK.xcodeproj/project.pbxproj index c9ea60b..d87aede 100644 --- a/OptableSDK.xcodeproj/project.pbxproj +++ b/OptableSDK.xcodeproj/project.pbxproj @@ -461,7 +461,9 @@ 6352AB1324EAD403002E66EB /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -470,6 +472,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = co.optable.OptableSDKTests; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -478,6 +481,7 @@ 6352AB1424EAD403002E66EB /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Tests/Info.plist; @@ -488,6 +492,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = co.optable.OptableSDKTests; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; From ca496eaa2c7c96edc7e86a96676b601af9644c6d Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Wed, 15 Oct 2025 11:03:59 +0300 Subject: [PATCH 09/11] feat: uncomment build demo swift on CI --- .github/workflows/ios-sdk-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ios-sdk-ci.yml b/.github/workflows/ios-sdk-ci.yml index cfcad67..251beb7 100644 --- a/.github/workflows/ios-sdk-ci.yml +++ b/.github/workflows/ios-sdk-ci.yml @@ -42,7 +42,7 @@ jobs: bundler-cache: true - name: Build Demo Swift id: build-demo-swift - run: echo TODO UNCOMMENT # bundle exec fastlane demo_swift + run: bundle exec fastlane demo_swift - name: Store Artifacts uses: actions/upload-artifact@v4 with: From 7140c84b39ff5ab904859d1036e52f5ddba51f23 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Wed, 15 Oct 2025 11:10:58 +0300 Subject: [PATCH 10/11] feat: set dev team to none --- OptableSDK.xcodeproj/project.pbxproj | 4 ++-- .../demo-ios-objc.xcodeproj/project.pbxproj | 24 +++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/OptableSDK.xcodeproj/project.pbxproj b/OptableSDK.xcodeproj/project.pbxproj index d87aede..2d3c3cc 100644 --- a/OptableSDK.xcodeproj/project.pbxproj +++ b/OptableSDK.xcodeproj/project.pbxproj @@ -303,7 +303,7 @@ COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = QQ5D7M7URA; + DEVELOPMENT_TEAM = ""; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -370,7 +370,7 @@ COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = QQ5D7M7URA; + DEVELOPMENT_TEAM = ""; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; diff --git a/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj b/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj index 28c87e2..c53bf04 100644 --- a/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj +++ b/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj @@ -352,10 +352,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-frameworks.sh\"\n"; @@ -413,10 +417,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-resources-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-resources-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc/Pods-demo-ios-objc-resources.sh\"\n"; @@ -430,10 +438,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-frameworks.sh\"\n"; @@ -447,10 +459,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-resources-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-resources-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-demo-ios-objc-demo-ios-objcUITests/Pods-demo-ios-objc-demo-ios-objcUITests-resources.sh\"\n"; @@ -690,7 +706,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = QQ5D7M7URA; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "demo-ios-objcTests/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -711,7 +727,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = QQ5D7M7URA; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "demo-ios-objcTests/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -732,7 +748,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = QQ5D7M7URA; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "demo-ios-objcUITests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -752,7 +768,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = QQ5D7M7URA; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "demo-ios-objcUITests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", From 4c84a4f3d77115c9282017bb6c328300522810b5 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk Date: Wed, 15 Oct 2025 11:18:11 +0300 Subject: [PATCH 11/11] feat: set CODE_SIGN_IDENTITY to NONE --- OptableSDK.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OptableSDK.xcodeproj/project.pbxproj b/OptableSDK.xcodeproj/project.pbxproj index 2d3c3cc..05287e6 100644 --- a/OptableSDK.xcodeproj/project.pbxproj +++ b/OptableSDK.xcodeproj/project.pbxproj @@ -461,7 +461,7 @@ 6352AB1324EAD403002E66EB /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Tests/Info.plist; @@ -481,7 +481,7 @@ 6352AB1424EAD403002E66EB /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Tests/Info.plist;