diff --git a/.github/workflows/ios-sdk-ci.yml b/.github/workflows/ios-sdk-ci.yml index 251beb7..63a1baf 100644 --- a/.github/workflows/ios-sdk-ci.yml +++ b/.github/workflows/ios-sdk-ci.yml @@ -10,7 +10,7 @@ on: jobs: sdk-tests: name: "SDK Tests" - runs-on: macos-15 + runs-on: xcode-27 steps: - name: Checkout Code uses: actions/checkout@v5 @@ -30,7 +30,7 @@ jobs: build-demo-swift: name: "Build Demo Swift" - runs-on: macos-15 + runs-on: xcode-27 needs: [sdk-tests] steps: - name: Checkout Code @@ -58,13 +58,13 @@ jobs: build-demo-objc: name: "Build Demo Objective-C" - runs-on: macos-15 + runs-on: xcode-27 env: FL_OUTPUT_DIR: output needs: [sdk-tests] steps: - name: Checkout Code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Bundle install uses: ruby/setup-ruby@v1 with: @@ -92,7 +92,7 @@ jobs: steps: - name: Successful Release Post to Slack uses: slackapi/slack-github-action@v2.1.1 - if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && needs.build-demo-swift.result == 'success' && needs.build-demo-swift.result == 'success' }} + if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && needs.build-demo-swift.result == 'success' && needs.build-demo-objc.result == 'success' }} with: method: chat.postMessage token: "${{ secrets.SLACK_MESSENGER_APP_TOKEN }}" @@ -117,7 +117,7 @@ jobs: text: ":white_check_mark: *iOS SDK release:*\n${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - name: Build failure Post to Slack uses: slackapi/slack-github-action@v2.1.1 - if: ${{ github.event_name == 'pull_request' && (needs.build-demo-swift.result != 'success' || needs.build-demo-swift.result != 'success')}} + if: ${{ github.event_name == 'pull_request' && (needs.build-demo-swift.result != 'success' || needs.build-demo-objc.result != 'success')}} with: method: chat.postMessage token: "${{ secrets.SLACK_MESSENGER_APP_TOKEN }}" diff --git a/OptableSDK.podspec b/OptableSDK.podspec index 799808f..aa2b380 100644 --- a/OptableSDK.podspec +++ b/OptableSDK.podspec @@ -14,7 +14,7 @@ Pod::Spec.new do |spec| spec.author = { "Optable Technologies Inc" => "support@optable.co" } spec.platform = :ios - spec.ios.deployment_target = "12.0" + spec.ios.deployment_target = "15.0" spec.swift_version = "5.0" spec.source = { :git => "https://github.com/Optable/optable-ios-sdk.git", :tag => "#{spec.version}" } diff --git a/OptableSDK.xcodeproj/project.pbxproj b/OptableSDK.xcodeproj/project.pbxproj index 686c972..12615ab 100644 --- a/OptableSDK.xcodeproj/project.pbxproj +++ b/OptableSDK.xcodeproj/project.pbxproj @@ -286,7 +286,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -347,7 +347,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -374,7 +374,7 @@ ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Source/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -407,7 +407,7 @@ ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = Source/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -431,7 +431,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -452,7 +452,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/Package.swift b/Package.swift index 3491467..b51a145 100644 --- a/Package.swift +++ b/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "OptableSDK", - platforms: [.iOS(.v12)], + platforms: [.iOS(.v15)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( diff --git a/Source/Core/EdgeAPI.swift b/Source/Core/EdgeAPI.swift index 4d62e22..b0d5900 100644 --- a/Source/Core/EdgeAPI.swift +++ b/Source/Core/EdgeAPI.swift @@ -118,25 +118,8 @@ extension EdgeAPI { completionHandler(data, response, error) return } - if #available(iOS 13.0, *) { - if let passport = res.value(forHTTPHeaderField: self.kPassportHeader) { - self.storage.setPassport(passport) - } - } else { - // In older versions of iOS, we have to resort searching through headers via res.allHeaderFields - // Unlike res.value(forHTTPHeaderField:...) which was introduced in iOS 13.0, allHeaderFields is - // case-sensitive, so we need to take special care to perform a case-INsensitive search: - for (key, value) in res.allHeaderFields { - if let header = key as? String { - let result: ComparisonResult = header.compare(self.kPassportHeader, options: NSString.CompareOptions.caseInsensitive) - if result == .orderedSame { - if let pp = value as? String { - self.storage.setPassport(pp) - break - } - } - } - } + if let passport = res.value(forHTTPHeaderField: self.kPassportHeader) { + self.storage.setPassport(passport) } completionHandler(data, response, error) } @@ -148,7 +131,9 @@ extension EdgeAPI { private func resolveUserAgent(callback: @escaping (_ useragent: String) -> Void) { var wkUserAgent = "" let myGroup = DispatchGroup() - let window = UIApplication.shared.keyWindow + let window = UIApplication.shared.connectedScenes + .compactMap { ($0 as? UIWindowScene)?.keyWindow } + .first let webView = WKWebView(frame: UIScreen.main.bounds) webView.isHidden = true diff --git a/Source/Core/OptableIdentifierEncoder.swift b/Source/Core/OptableIdentifierEncoder.swift index 0590761..8a65694 100644 --- a/Source/Core/OptableIdentifierEncoder.swift +++ b/Source/Core/OptableIdentifierEncoder.swift @@ -5,11 +5,8 @@ // Copyright © 2026 Optable Technologies, Inc. All rights reserved. // -import CommonCrypto +import CryptoKit import Foundation -#if canImport(CryptoKit) - import CryptoKit -#endif // MARK: - OptableIdentifierEncoder enum OptableIdentifierEncoder { @@ -196,25 +193,9 @@ enum OptableIdentifierEncoder { } private static func sha256(data: Data) -> String { - #if canImport(CryptoKit) - if #available(iOS 13.0, *) { - return SHA256 - .hash(data: data) - .compactMap({ String(format: "%02x", $0) }) - .joined() - } - #endif - - return cchash(data) - } - - private static func cchash(_ input: Data) -> String { - var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH)) - input.withUnsafeBytes { bytes in - _ = CC_SHA256(bytes.baseAddress, CC_LONG(input.count), &digest) - } - return digest.makeIterator().compactMap { - String(format: "%02x", $0) - }.joined() + SHA256 + .hash(data: data) + .compactMap({ String(format: "%02x", $0) }) + .joined() } } diff --git a/Source/Misc/AppTrackingTransparency.swift b/Source/Misc/AppTrackingTransparency.swift index 5139c9d..433b73d 100644 --- a/Source/Misc/AppTrackingTransparency.swift +++ b/Source/Misc/AppTrackingTransparency.swift @@ -8,11 +8,7 @@ #if canImport(AdSupport) import AdSupport - - #if canImport(AppTrackingTransparency) - import AppTrackingTransparency - #endif - + import AppTrackingTransparency import Foundation enum ATT { @@ -29,21 +25,6 @@ } #endif - // MARK: isAdvertisingTrackingEnabled - - #if DEBUG - @available(iOS, introduced: 6, deprecated: 14, - message: "Replaced by ATTrackingManager in AppTrackingTransparency.") - static var isAdvertisingTrackingEnabled_DebugOverride: Bool? - static var isAdvertisingTrackingEnabled: Bool { - isAdvertisingTrackingEnabled_DebugOverride ?? ASIdentifierManager.shared().isAdvertisingTrackingEnabled - } - #else - static var isAdvertisingTrackingEnabled: Bool { - ASIdentifierManager.shared().isAdvertisingTrackingEnabled - } - #endif - // MARK: advertisingIdentifierAvailable #if DEBUG @@ -57,110 +38,22 @@ } #endif - #if canImport(AppTrackingTransparency) - if #available(iOS 14, *) { - return trackingStatus == .authorized - } else { - return isAdvertisingTrackingEnabled - } - #else - return isAdvertisingTrackingEnabled - #endif + return trackingStatus == .authorized } - // MARK: attAvailable + // MARK: trackingStatus #if DEBUG - static var attAvailable_DebugOverride: Bool? + static var trackingStatus_DebugOverride: ATTrackingManager.AuthorizationStatus? #endif - static var attAvailable: Bool { + static var trackingStatus: ATTrackingManager.AuthorizationStatus { #if DEBUG - if let override = attAvailable_DebugOverride { - return override - } + return trackingStatus_DebugOverride ?? ATTrackingManager.trackingAuthorizationStatus + #else + return ATTrackingManager.trackingAuthorizationStatus #endif - - if #available(iOS 14, *) { - return true - } else { - return false - } } - - #if canImport(AppTrackingTransparency) - - // MARK: canAuthorize - - #if DEBUG - @available(iOS 14, *) - static var canAuthorize_DebugOverride: Bool? - #endif - - static var canAuthorize: Bool { - if #available(iOS 14, *) { - #if DEBUG - if let override = canAuthorize_DebugOverride { - return override - } - #endif - - return ATTrackingManager.trackingAuthorizationStatus == .notDetermined - } else { - return false - } - } - - // MARK: trackingStatus - - #if DEBUG - @available(iOS 14, *) - static var trackingStatus_DebugOverride: ATTrackingManager.AuthorizationStatus? - #endif - - @available(iOS 14, *) - static var trackingStatus: ATTrackingManager.AuthorizationStatus { - #if DEBUG - return trackingStatus_DebugOverride ?? ATTrackingManager.trackingAuthorizationStatus - #else - return ATTrackingManager.trackingAuthorizationStatus - #endif - } - - // MARK: RequestAuthorization - - @available(iOS 14, *) - static func requestATTAuthorization(completion: ((Bool) -> Void)? = nil) { - #if DEBUG - if let override = trackingStatus_DebugOverride { - completion?(override == .authorized) - return - } - #endif - - ATTrackingManager.requestTrackingAuthorization { status in - switch status { - case .authorized: - completion?(true) - case .denied, .notDetermined, .restricted: - completion?(false) - @unknown default: - completion?(true) - } - } - } - - @available(iOS 14, *) - @discardableResult - static func requestATTAuthorization() async -> Bool { - await withCheckedContinuation { continuation in - requestATTAuthorization { isAuthorized in - continuation.resume(returning: isAuthorized) - } - } - } - - #endif } #endif diff --git a/Source/Misc/RangeReplaceableCollection+Compat.swift b/Source/Misc/RangeReplaceableCollection+Compat.swift deleted file mode 100644 index 329a242..0000000 --- a/Source/Misc/RangeReplaceableCollection+Compat.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// RangeReplaceableCollection+Compat.swift -// OptableSDK -// -// Copyright © 2026 Optable Technologies, Inc. All rights reserved. -// - -import Foundation -import SwiftUI - -extension RangeReplaceableCollection where Self: MutableCollection, Index == Int { - mutating func removeCompat(atOffsets offsets: IndexSet) { - if #available(iOS 13.0, *) { - remove(atOffsets: offsets) - } else { - // Remove from highest index to lowest to avoid shifting issues - for index in offsets.sorted(by: >) { - remove(at: index) - } - } - } -} diff --git a/Source/OptableSDK.swift b/Source/OptableSDK.swift index 308213f..23b315d 100644 --- a/Source/OptableSDK.swift +++ b/Source/OptableSDK.swift @@ -101,7 +101,6 @@ public extension OptableSDK { Instead of completion callbacks, results are returned via async/await. */ - @available(iOS 13.0, *) func identify(_ ids: [OptableIdentifier]) async throws -> HTTPURLResponse { return try await withCheckedThrowingContinuation({ [unowned self] continuation in do { @@ -164,7 +163,6 @@ public extension OptableSDK { Instead of completion callbacks, results are returned via async/await. */ - @available(iOS 13.0, *) func targeting(_ ids: [OptableIdentifier]? = nil, hids: [OptableIdentifier]? = nil) async throws -> OptableTargeting { return try await withCheckedThrowingContinuation({ [unowned self] continuation in do { @@ -197,7 +195,6 @@ public extension OptableSDK { Instead of completion callbacks, results are returned via async/await. */ - @available(iOS 13.0, *) func witness(event: String, properties: [String: Any]) async throws -> HTTPURLResponse { return try await withCheckedThrowingContinuation({ [unowned self] continuation in do { @@ -249,7 +246,6 @@ public extension OptableSDK { Instead of completion callbacks, results are returned via async/await. */ - @available(iOS 13.0, *) func profile(traits: [String: Any], id: String? = nil, neighbors: [String]? = nil) async throws -> OptableTargeting { return try await withCheckedThrowingContinuation({ [unowned self] continuation in do { @@ -432,18 +428,11 @@ extension OptableSDK { ATT.advertisingIdentifier != UUID(uuid: uuid_t(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) { let systemIDFA = ATT.advertisingIdentifier.uuidString - var idfaMatchingSystemIdxs: [Int] = [] - - for idx in ids.indices { - if case let .appleIDFA(value) = ids[idx] { - if value == systemIDFA { - idfaMatchingSystemIdxs.append(idx) - } - } - } - // Remove all matching systemIDFA (deduplicate) - ids.removeCompat(atOffsets: IndexSet(idfaMatchingSystemIdxs)) + ids.removeAll { id in + if case let .appleIDFA(value) = id { return value == systemIDFA } + return false + } // Prepend all identifiers with systemIDFA ids.insert(.appleIDFA(systemIDFA), at: ids.startIndex) diff --git a/Tests/Integration/OptableSDKTests.swift b/Tests/Integration/OptableSDKTests.swift index 6dcb627..fbcfce5 100644 --- a/Tests/Integration/OptableSDKTests.swift +++ b/Tests/Integration/OptableSDKTests.swift @@ -24,7 +24,6 @@ class OptableSDKTests: XCTestCase { } // MARK: Identify - @available(iOS 13.0, *) func test_identify_async() async throws { let response = try await sdk.identify([.emailAddress("test@test.com")]) XCTAssert(response.allHeaderFields.keys.contains("x-optable-visitor")) @@ -52,7 +51,6 @@ class OptableSDKTests: XCTestCase { } // MARK: Target - @available(iOS 13.0, *) func test_target_async() async throws { let response = try await sdk.targeting([.emailAddress("test@test.com")]) XCTAssert(response.targetingData.keys.isEmpty == false) @@ -102,7 +100,6 @@ class OptableSDKTests: XCTestCase { } // MARK: Witness - @available(iOS 13.0, *) func test_witness_async() async throws { let response: HTTPURLResponse = try await sdk.witness(event: "test", properties: ["integration-test-witness": "integration-test-witness-value"]) XCTAssert(response.allHeaderFields.keys.contains("x-optable-visitor")) @@ -130,7 +127,6 @@ class OptableSDKTests: XCTestCase { } // MARK: Profile - @available(iOS 13.0, *) func test_profile_async() async throws { let response = try await sdk.profile(traits: ["integration-test-profile": "integration-test-profile-value"]) XCTAssert(response.targetingData.keys.isEmpty == false) diff --git a/Tests/Unit/OptableSDKHelpersIdentifiersEnrichmentTests.swift b/Tests/Unit/OptableSDKHelpersIdentifiersEnrichmentTests.swift index 085cb4a..ea53d53 100644 --- a/Tests/Unit/OptableSDKHelpersIdentifiersEnrichmentTests.swift +++ b/Tests/Unit/OptableSDKHelpersIdentifiersEnrichmentTests.swift @@ -63,7 +63,6 @@ class OptableSDKHelpersIdentifiersEnrichmentTests: XCTestCase { } } - @available(iOS 14, *) func test_idfa_detection_enabled_enrich_system_idfa_same_as_user_idfa_prepend() { ATT.advertisingIdentifierAvailable_DebugOverride = true ATT.advertisingIdentifier_DebugOverride = UUID(uuidString: systemIDFA) @@ -94,7 +93,6 @@ class OptableSDKHelpersIdentifiersEnrichmentTests: XCTestCase { } } - @available(iOS 14, *) func test_idfa_detection_enabled_enrich_system_idfa_user_idfa_persist() { ATT.advertisingIdentifierAvailable_DebugOverride = true ATT.advertisingIdentifier_DebugOverride = UUID(uuidString: systemIDFA) diff --git a/demo-ios-objc/Podfile b/demo-ios-objc/Podfile index db4bb9b..72b1e52 100644 --- a/demo-ios-objc/Podfile +++ b/demo-ios-objc/Podfile @@ -11,3 +11,16 @@ target 'demo-ios-objc' do pod 'PrebidMobile' end + +# Xcode 27 refuses to build targets whose deployment target is below iOS 15. Some third-party pods +# (Google-Mobile-Ads-SDK, GoogleUserMessagingPlatform, PrebidMobile) still declare older minimums, +# so raise them to the platform version declared above. +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + if config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f < 15.0 + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0' + end + end + end +end diff --git a/demo-ios-objc/Podfile.lock b/demo-ios-objc/Podfile.lock index 8e0556a..44d9e11 100644 --- a/demo-ios-objc/Podfile.lock +++ b/demo-ios-objc/Podfile.lock @@ -1,11 +1,11 @@ PODS: - - Google-Mobile-Ads-SDK (13.7.0): + - Google-Mobile-Ads-SDK (13.11.0): - GoogleUserMessagingPlatform (>= 1.1) - GoogleUserMessagingPlatform (3.1.0) - OptableSDK (1.0.0) - - PrebidMobile (3.3.3): - - PrebidMobile/core (= 3.3.3) - - PrebidMobile/core (3.3.3) + - PrebidMobile (3.3.4): + - PrebidMobile/core (= 3.3.4) + - PrebidMobile/core (3.3.4) DEPENDENCIES: - Google-Mobile-Ads-SDK @@ -23,11 +23,11 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - Google-Mobile-Ads-SDK: dd0ded6717d122c6a32c69dc4afcace7d276e4e4 + Google-Mobile-Ads-SDK: 09d0868abe43b9f851b7b340a245679f0eafc96c GoogleUserMessagingPlatform: befe603da6501006420c206222acd449bba45a9c - OptableSDK: d7cb5f7a211f1bac2a0c25677f4c4b31ded8ed4e - PrebidMobile: 5ded0a10d6da41d4b140c1c8b86b42c7629133fa + OptableSDK: 127f749734ded99deff764f29bc1342b20153b2b + PrebidMobile: ce3afbb56904a5e8b3f5f5aa0696474d2786a96b -PODFILE CHECKSUM: 84321d4bbdf19f72ce3dfa6f4cb2f0a9869574ad +PODFILE CHECKSUM: 788f5abee95f41b7e281003e2cab30df58eb8547 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 67e4701..3af9d3b 100644 --- a/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj +++ b/demo-ios-objc/demo-ios-objc.xcodeproj/project.pbxproj @@ -360,7 +360,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -413,7 +413,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/demo-ios-swift/Podfile b/demo-ios-swift/Podfile index 5e9d12e..7dfa9a5 100644 --- a/demo-ios-swift/Podfile +++ b/demo-ios-swift/Podfile @@ -11,3 +11,16 @@ target 'demo-ios-swift' do pod 'PrebidMobile' end + +# Xcode 27 refuses to build targets whose deployment target is below iOS 15. Some third-party pods +# (Google-Mobile-Ads-SDK, GoogleUserMessagingPlatform, PrebidMobile) still declare older minimums, +# so raise them to the platform version declared above. +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + if config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f < 15.0 + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0' + end + end + end +end diff --git a/demo-ios-swift/Podfile.lock b/demo-ios-swift/Podfile.lock index 59ae941..cd81e9f 100644 --- a/demo-ios-swift/Podfile.lock +++ b/demo-ios-swift/Podfile.lock @@ -1,11 +1,11 @@ PODS: - - Google-Mobile-Ads-SDK (13.7.0): + - Google-Mobile-Ads-SDK (13.11.0): - GoogleUserMessagingPlatform (>= 1.1) - GoogleUserMessagingPlatform (3.1.0) - OptableSDK (1.0.0) - - PrebidMobile (3.3.3): - - PrebidMobile/core (= 3.3.3) - - PrebidMobile/core (3.3.3) + - PrebidMobile (3.3.4): + - PrebidMobile/core (= 3.3.4) + - PrebidMobile/core (3.3.4) DEPENDENCIES: - Google-Mobile-Ads-SDK @@ -23,11 +23,11 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - Google-Mobile-Ads-SDK: dd0ded6717d122c6a32c69dc4afcace7d276e4e4 + Google-Mobile-Ads-SDK: 09d0868abe43b9f851b7b340a245679f0eafc96c GoogleUserMessagingPlatform: befe603da6501006420c206222acd449bba45a9c - OptableSDK: d7cb5f7a211f1bac2a0c25677f4c4b31ded8ed4e - PrebidMobile: 5ded0a10d6da41d4b140c1c8b86b42c7629133fa + OptableSDK: 127f749734ded99deff764f29bc1342b20153b2b + PrebidMobile: ce3afbb56904a5e8b3f5f5aa0696474d2786a96b -PODFILE CHECKSUM: aca8225c99e7af1a76b3862a46118652667f5944 +PODFILE CHECKSUM: ae16575987318eda44e4e135cd54cad3debe5193 COCOAPODS: 1.16.2 diff --git a/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj b/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj index cf29466..e5a10f0 100644 --- a/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj +++ b/demo-ios-swift/demo-ios-swift.xcodeproj/project.pbxproj @@ -348,7 +348,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -402,7 +402,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/docs/usage-objc.md b/docs/usage-objc.md index 4262d33..8b94b82 100644 --- a/docs/usage-objc.md +++ b/docs/usage-objc.md @@ -99,7 +99,7 @@ NSArray *ids = @[ Note that `error` will be set only in case of an internal SDK exception. Otherwise, any configured delegate `identifyOk` or `identifyErr` will be invoked to signal success or failure, respectively. Providing an empty `ppid` as in the above example simply will not send any `ppid`. -> :warning: **As of iOS 14.0**, Apple has introduced [additional restrictions on IDFA](https://developer.apple.com/app-store/user-privacy-and-data-use/) which will require prompting users to request permission to use IDFA. Therefore, if you intend to set `aaid` to `YES` in calls to `identify` on iOS 14.0 or above, you should expect that the SDK will automatically trigger a user prompt via the `AppTrackingTransparency` framework before it is permitted to send the IDFA value to your DCN. Additionally, we recommend that you ensure to configure the _Privacy - Tracking Usage Description_ attribute string in your application's `Info.plist`, as it enables you to customize some elements of the resulting user prompt. +> :warning: **IDFA requires user authorization**: Apple requires permission to use IDFA via the [AppTrackingTransparency](https://developer.apple.com/app-store/user-privacy-and-data-use/) framework. If you intend to set `aaid` to `YES` in calls to `identify`, the SDK will automatically trigger the ATT user prompt before sending the IDFA value to your DCN. We recommend configuring the _Privacy - Tracking Usage Description_ attribute string in your application's `Info.plist` to customize the prompt. ### Profile API diff --git a/docs/usage-swift.md b/docs/usage-swift.md index 2a66bbe..d2f1e1c 100644 --- a/docs/usage-swift.md +++ b/docs/usage-swift.md @@ -89,7 +89,7 @@ The SDK `identify()` method will asynchronously connect to the configured DCN an Since the `sendIDFA` value provided to `identify()` via the `aaid` (Apple Advertising ID or IDFA) boolean parameter is `true`, the SDK will attempt to fetch and send the Apple IDFA in the call to `identify` too, unless the user has turned on "Limit ad tracking" in their iOS device privacy settings. -> :warning: **As of iOS 14.0**, Apple has introduced [additional restrictions on IDFA](https://developer.apple.com/app-store/user-privacy-and-data-use/) which will require prompting users to request permission to use IDFA. Therefore, if you intend to set `aaid` to `true` in calls to `identify()` on iOS 14.0 or above, you should expect that the SDK will automatically trigger a user prompt via the `AppTrackingTransparency` framework before it is permitted to send the IDFA value to your DCN. Additionally, we recommend that you ensure to configure the _Privacy - Tracking Usage Description_ attribute string in your application's `Info.plist`, as it enables you to customize some elements of the resulting user prompt. +> :warning: **IDFA requires user authorization**: Apple requires permission to use IDFA via the [AppTrackingTransparency](https://developer.apple.com/app-store/user-privacy-and-data-use/) framework. If you intend to set `aaid` to `true` in calls to `identify()`, the SDK will automatically trigger the ATT user prompt before sending the IDFA value to your DCN. We recommend configuring the _Privacy - Tracking Usage Description_ attribute string in your application's `Info.plist` to customize the prompt. The frequency of invocation of `identify` is up to you, however for optimal identity resolution we recommended to call the `identify()` method on your SDK instance every time you authenticate a user, as well as periodically, such as for example once every 15 to 60 minutes while the application is being actively used and an internet connection is available.