From 85dbd8d11bda7594fa5650fc758b2b9c88a83760 Mon Sep 17 00:00:00 2001 From: Rodrigo Reis Date: Thu, 7 May 2026 20:57:56 -0700 Subject: [PATCH] =?UTF-8?q?SDKS-4916=20Fix=20swift=20build=20failures=20?= =?UTF-8?q?=E2=80=94=20platform=20bump=20and=20iOS-only=20guards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DeviceBindingAuthenticationType.swift | 4 +- Browser/Browser/BrowserLauncher.swift | 4 + .../Collectors/HardwareCollector.swift | 18 ++- .../Collectors/PlatformCollector.swift | 15 ++- .../Collectors/TelephonyCollector.swift | 7 +- .../DeviceProfile/LocationManager.swift | 31 ++++-- .../ExternalIdP/Handlers/BrowserHandler.swift | 2 + ExternalIdP/ExternalIdP/IdpClient.swift | 4 + ExternalIdP/ExternalIdP/IdpCollector.swift | 4 + .../ExternalIdP/IdpValidationUtils.swift | 4 +- .../Handlers/AppleHandler.swift | 2 + .../Handlers/AppleRequestHandler.swift | 2 + .../Helpers/SIWAHelpers.swift | 103 ++++++++++-------- .../Handlers/FacebookHandler.swift | 2 + .../Handlers/FacebookHandlerUtils.swift | 2 + .../Handlers/FacebookRequestHandler.swift | 2 + .../Handlers/GoogleHandler.swift | 8 +- .../Handlers/GoogleHandlerUtils.swift | 6 +- .../Handlers/GoogleRequestHandler.swift | 6 +- .../Davinci/FidoAuthenticationCollector.swift | 2 + .../Davinci/FidoRegistrationCollector.swift | 2 + Fido/Fido/Fido.swift | 10 +- .../JourneyPlugin/ContinueNode.swift | 4 +- Oidc/Oidc/Module/Web.swift | 3 +- Oidc/Oidc/OidcWebClient.swift | 2 + Package.swift | 11 +- .../PingOneProtectEvaluationCallback.swift | 2 + .../PingOneProtectInitializeCallback.swift | 2 + .../Protect/Journey/ProtectCallbacks.swift | 2 + Protect/Protect/Protect.swift | 2 + Protect/Protect/ProtectCollector.swift | 2 + Protect/Protect/ProtectLifecycleModule.swift | 2 + Push/Push/Utilities/PushUriParser.swift | 2 +- .../ReCaptchaEnterprise.swift | 2 + .../ReCaptchaEnterpriseCallback.swift | 4 +- .../TamperDetector/TamperDetector.swift | 9 +- .../TamperDetector/URLSchemeDetector.swift | 5 +- 37 files changed, 199 insertions(+), 95 deletions(-) diff --git a/Binding/Binding/Model/DeviceBindingAuthenticationType.swift b/Binding/Binding/Model/DeviceBindingAuthenticationType.swift index 11f8ee88..bf16ab2d 100644 --- a/Binding/Binding/Model/DeviceBindingAuthenticationType.swift +++ b/Binding/Binding/Model/DeviceBindingAuthenticationType.swift @@ -41,9 +41,9 @@ public enum DeviceBindingAuthenticationType: String, Codable, Sendable { func getAuthType(pinCollector: PinCollector? = nil) -> DeviceAuthenticator { switch self { case .biometricOnly: - return BiometricOnlyAuthenticator() + return BiometricOnlyAuthenticator(config: BiometricAuthenticatorConfig()) case .biometricAllowFallback: - return BiometricDeviceCredentialAuthenticator() + return BiometricDeviceCredentialAuthenticator(config: BiometricAuthenticatorConfig()) case .applicationPin: fatalError("Application PIN is not supported on this platform.") case .none: diff --git a/Browser/Browser/BrowserLauncher.swift b/Browser/Browser/BrowserLauncher.swift index 39a5ff7e..5c176584 100644 --- a/Browser/Browser/BrowserLauncher.swift +++ b/Browser/Browser/BrowserLauncher.swift @@ -11,9 +11,11 @@ import Foundation import AuthenticationServices import PingLogger +#if canImport(UIKit) import SafariServices import Combine import UIKit +#endif // MARK: - Enums /// BrowserType enum to specify the type of external user-agent; @@ -65,6 +67,7 @@ public protocol BrowserLauncherProtocol: Sendable { // MARK: - BrowserLauncher +#if canImport(UIKit) /// BrowserLauncher class to launch external user-agent for web requests @MainActor public final class BrowserLauncher: NSObject, BrowserLauncherProtocol { @@ -443,3 +446,4 @@ public final class OpenURLMonitor: NSObject { return true } } +#endif diff --git a/DeviceProfile/DeviceProfile/Collectors/HardwareCollector.swift b/DeviceProfile/DeviceProfile/Collectors/HardwareCollector.swift index f9e3faf5..d5962de3 100644 --- a/DeviceProfile/DeviceProfile/Collectors/HardwareCollector.swift +++ b/DeviceProfile/DeviceProfile/Collectors/HardwareCollector.swift @@ -2,15 +2,17 @@ // HardwareCollector.swift // DeviceProfile // -// Copyright (c) 2025 Ping Identity Corporation. All rights reserved. +// Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved. // // This software may be modified and distributed under the terms // of the MIT license. See the LICENSE file for details. // import Foundation -import UIKit import AVFoundation +#if canImport(UIKit) +import UIKit +#endif // MARK: - HardwareCollector @@ -93,14 +95,18 @@ public struct HardwareInfo: Codable, Sendable { /// - Values represent logical screen dimensions @MainActor private static func getDisplayInfo() -> [String: Int] { + #if canImport(UIKit) let screenBounds = UIScreen.main.bounds let isPortrait = UIDevice.current.orientation.isPortrait - + return [ "width": Int(screenBounds.width), "height": Int(screenBounds.height), "orientation": isPortrait ? 1 : 0 ] + #else + return [:] + #endif } /// Retrieves camera system information @@ -119,6 +125,7 @@ public struct HardwareInfo: Codable, Sendable { /// - May return 0 if camera access is restricted /// - Includes specialty cameras (telephoto, ultra-wide, etc.) private static func getCameraInfo() -> [String: Int] { + #if canImport(UIKit) let discoverySession = AVCaptureDevice.DiscoverySession( deviceTypes: [ .builtInTelephotoCamera, @@ -128,8 +135,11 @@ public struct HardwareInfo: Codable, Sendable { mediaType: .video, position: .unspecified ) - + let cameraCount = discoverySession.devices.count return ["numberOfCameras": cameraCount] + #else + return [:] + #endif } } diff --git a/DeviceProfile/DeviceProfile/Collectors/PlatformCollector.swift b/DeviceProfile/DeviceProfile/Collectors/PlatformCollector.swift index 25e8b588..b76bb9dc 100644 --- a/DeviceProfile/DeviceProfile/Collectors/PlatformCollector.swift +++ b/DeviceProfile/DeviceProfile/Collectors/PlatformCollector.swift @@ -2,15 +2,17 @@ // PlatformCollector.swift // DeviceProfile // -// Copyright (c) 2025 Ping Identity Corporation. All rights reserved. +// Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved. // // This software may be modified and distributed under the terms // of the MIT license. See the LICENSE file for details. // import Foundation -import UIKit import PingTamperDetector +#if canImport(UIKit) +import UIKit +#endif // MARK: - PlatformCollector @@ -72,15 +74,22 @@ public struct PlatformInfo: Codable, Sendable { /// Initializes platform information by collecting system details init() async { + #if canImport(UIKit) self.platform = await UIDevice.current.systemName self.version = await UIDevice.current.systemVersion self.device = await UIDevice.current.model self.deviceName = await UIDevice.current.name + #else + self.platform = "macOS" + self.version = ProcessInfo.processInfo.operatingSystemVersionString + self.device = "Mac" + self.deviceName = Host.current().localizedName ?? "Mac" + #endif self.model = Self.getDeviceModel() self.brand = "Apple" self.locale = Locale.current.language.languageCode?.identifier self.timeZone = TimeZone.current.identifier - + self.jailBreakScore = await TamperDetector().analyze() } diff --git a/DeviceProfile/DeviceProfile/Collectors/TelephonyCollector.swift b/DeviceProfile/DeviceProfile/Collectors/TelephonyCollector.swift index 95886be5..1dbcbc71 100644 --- a/DeviceProfile/DeviceProfile/Collectors/TelephonyCollector.swift +++ b/DeviceProfile/DeviceProfile/Collectors/TelephonyCollector.swift @@ -2,7 +2,7 @@ // TelephonyCollector.swift // DeviceProfile // -// Copyright (c) 2025 Ping Identity Corporation. All rights reserved. +// Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved. // // This software may be modified and distributed under the terms // of the MIT license. See the LICENSE file for details. @@ -61,6 +61,7 @@ public struct TelephonyInfo: Codable, Sendable { /// - Selects the primary or most complete carrier information /// - Prioritizes carriers with complete information init() { + #if canImport(UIKit) let networkInfo = CTTelephonyNetworkInfo() var selectedCarrier: (carrierName: String?, isoCountryCode: String?)? @@ -86,6 +87,10 @@ public struct TelephonyInfo: Codable, Sendable { self.carrierName = DeviceProfileConstants.unknown self.networkCountryIso = DeviceProfileConstants.unknown } + #else + self.carrierName = DeviceProfileConstants.unknown + self.networkCountryIso = DeviceProfileConstants.unknown + #endif } } diff --git a/DeviceProfile/DeviceProfile/LocationManager.swift b/DeviceProfile/DeviceProfile/LocationManager.swift index 81eebc48..525641da 100644 --- a/DeviceProfile/DeviceProfile/LocationManager.swift +++ b/DeviceProfile/DeviceProfile/LocationManager.swift @@ -249,27 +249,40 @@ public class LocationManager: NSObject, ObservableObject, @unchecked Sendable { } // Handle different authorization states - switch await authorizationStatus { - case .authorizedAlways, .authorizedWhenInUse: - // Already authorized, fetch location + let currentStatus = await authorizationStatus + let isAuthorized: Bool + #if canImport(UIKit) + isAuthorized = (currentStatus == .authorizedAlways || currentStatus == .authorizedWhenInUse) + #else + isAuthorized = (currentStatus == .authorizedAlways) + #endif + if isAuthorized { return try await fetchLocationWithAuthorization() - + } + + switch currentStatus { case .notDetermined: // Need to request authorization first let status = try await requestAuthorizationIfNeeded() - if status == .authorizedAlways || status == .authorizedWhenInUse { + let statusAuthorized: Bool + #if canImport(UIKit) + statusAuthorized = (status == .authorizedAlways || status == .authorizedWhenInUse) + #else + statusAuthorized = (status == .authorizedAlways) + #endif + if statusAuthorized { return try await fetchLocationWithAuthorization() } else { throw authorizationErrorForStatus(status) } - + case .denied: throw LocationError.authorizationDenied - + case .restricted: throw LocationError.authorizationRestricted - - @unknown default: + + default: throw LocationError.authorizationDenied } } diff --git a/ExternalIdP/ExternalIdP/Handlers/BrowserHandler.swift b/ExternalIdP/ExternalIdP/Handlers/BrowserHandler.swift index e4fadb1a..0e7bd6f1 100644 --- a/ExternalIdP/ExternalIdP/Handlers/BrowserHandler.swift +++ b/ExternalIdP/ExternalIdP/Handlers/BrowserHandler.swift @@ -14,6 +14,7 @@ import PingOrchestrate import PingNetwork import PingLogger +#if canImport(UIKit) /// A handler class for managing browser-based Identity Provider (IdP) authorization. @MainActor public class BrowserHandler: IdpRequestHandler { @@ -68,3 +69,4 @@ public class BrowserHandler: IdpRequestHandler { } } } +#endif diff --git a/ExternalIdP/ExternalIdP/IdpClient.swift b/ExternalIdP/ExternalIdP/IdpClient.swift index 1549fdf4..95872fae 100644 --- a/ExternalIdP/ExternalIdP/IdpClient.swift +++ b/ExternalIdP/ExternalIdP/IdpClient.swift @@ -9,7 +9,9 @@ // import Foundation +#if canImport(UIKit) import UIKit +#endif /// Represents the IdpClient struct. The IdpClient struct represents the client configuration for the IDP. /// - property clientId: The client ID. @@ -26,6 +28,7 @@ public struct IdpClient: Sendable { public var continueUrl: String? = nil } +#if canImport(UIKit) extension IdpClient { @MainActor public static func getTopViewController() -> UIViewController? { @@ -47,3 +50,4 @@ extension IdpClient { return topController } } +#endif diff --git a/ExternalIdP/ExternalIdP/IdpCollector.swift b/ExternalIdP/ExternalIdP/IdpCollector.swift index f3f1ec79..e6676630 100644 --- a/ExternalIdP/ExternalIdP/IdpCollector.swift +++ b/ExternalIdP/ExternalIdP/IdpCollector.swift @@ -181,6 +181,7 @@ open class IdpCollector: NSObject, Collector, ContinueNodeAware, RequestIntercep /// - url: The URL for the IdP authentication. /// - Returns: A Result of type Bool or An IdpExceptions error. public func fallbackToBrowserHandler(callbackURLScheme: String? = nil, url: URL) async -> Result { + #if canImport(UIKit) let urlScheme: String if let customScheme = callbackURLScheme { urlScheme = customScheme @@ -200,6 +201,9 @@ open class IdpCollector: NSObject, Collector, ContinueNodeAware, RequestIntercep } catch { return .failure(.idpCanceledException(message: error.localizedDescription)) } + #else + return .failure(.illegalStateException(message: "Browser authentication is not supported on this platform")) + #endif } /// Authorizes the IdP diff --git a/ExternalIdP/ExternalIdP/IdpValidationUtils.swift b/ExternalIdP/ExternalIdP/IdpValidationUtils.swift index 64204e9f..59548c45 100644 --- a/ExternalIdP/ExternalIdP/IdpValidationUtils.swift +++ b/ExternalIdP/ExternalIdP/IdpValidationUtils.swift @@ -2,13 +2,14 @@ // IdpValidationUtils.swift // ExternalIdP // -// Copyright (c) 2025 Ping Identity Corporation. All rights reserved. +// Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved. // // This software may be modified and distributed under the terms // of the MIT license. See the LICENSE file for details. // import Foundation +#if canImport(UIKit) import UIKit /// Utility class for common IdP validation operations @@ -35,6 +36,7 @@ public struct IdpValidationUtils { } } } +#endif /// Centralized error messages for IdP operations public struct IdpErrorMessages { diff --git a/ExternalIdPApple/ExternalIdPApple/Handlers/AppleHandler.swift b/ExternalIdPApple/ExternalIdPApple/Handlers/AppleHandler.swift index 711ec975..3706a97e 100644 --- a/ExternalIdPApple/ExternalIdPApple/Handlers/AppleHandler.swift +++ b/ExternalIdPApple/ExternalIdPApple/Handlers/AppleHandler.swift @@ -12,6 +12,7 @@ import Foundation import AuthenticationServices import PingExternalIdP +#if canImport(UIKit) ///IdpHandler for Apple @MainActor @objc public final class AppleHandler: NSObject, @preconcurrency IdpHandler, Sendable { @@ -50,3 +51,4 @@ import PingExternalIdP extension AppleHandler { public static let acceptsJSON = "acceptsJSON" } +#endif diff --git a/ExternalIdPApple/ExternalIdPApple/Handlers/AppleRequestHandler.swift b/ExternalIdPApple/ExternalIdPApple/Handlers/AppleRequestHandler.swift index bdde500b..1d1a07f7 100644 --- a/ExternalIdPApple/ExternalIdPApple/Handlers/AppleRequestHandler.swift +++ b/ExternalIdPApple/ExternalIdPApple/Handlers/AppleRequestHandler.swift @@ -13,6 +13,7 @@ import PingNetwork import AuthenticationServices import PingExternalIdP +#if canImport(UIKit) ///IdpHandler for Apple @MainActor @objc class AppleRequestHandler: NSObject, IdpRequestHandler { @@ -74,3 +75,4 @@ import PingExternalIdP throw IdpExceptions.illegalStateException(message: IdpErrorMessages.appleSignInFailed) } } +#endif diff --git a/ExternalIdPApple/ExternalIdPApple/Helpers/SIWAHelpers.swift b/ExternalIdPApple/ExternalIdPApple/Helpers/SIWAHelpers.swift index a1e29c74..6df31bb3 100644 --- a/ExternalIdPApple/ExternalIdPApple/Helpers/SIWAHelpers.swift +++ b/ExternalIdPApple/ExternalIdPApple/Helpers/SIWAHelpers.swift @@ -10,6 +10,9 @@ import AuthenticationServices import PingExternalIdP +#if canImport(UIKit) +import UIKit +#endif /// Represents the result of a Sign In With Apple request. struct SignInWithAppleResult: Sendable { @@ -55,6 +58,55 @@ struct SignInWithAppleResult: Sendable { } } +struct AppleSignInResponse: Codable { + var code: String? + var id_token: String? + var state: String? + var user: AppleSignInUser + + init(_ appleIDCredential: ASAuthorizationAppleIDCredential) { + if let code = appleIDCredential.authorizationCode { + self.code = String(data: code, encoding: .utf8) + } else { + self.code = nil + } + if let id_token = appleIDCredential.identityToken { + self.id_token = String(data: id_token, encoding: .utf8) + } else { + self.id_token = nil + } + self.state = appleIDCredential.state + self.user = AppleSignInUser(nameComponents: appleIDCredential.fullName, email: appleIDCredential.email) + } +} + +struct AppleSignInUser: Codable { + var name: FullName? + var email: String + + init(nameComponents: PersonNameComponents?, email: String?) { + if let nameComponents = nameComponents { + self.name = FullName(nameComponents) + } else { + self.name = nil + } + self.email = email ?? "" + } +} + +struct FullName: Codable { + var firstName: String? + var lastName: String? +} + +extension FullName { + init(_ nameComponents: PersonNameComponents) { + firstName = nameComponents.givenName + lastName = nameComponents.familyName + } +} + +#if canImport(UIKit) /// Helper class to handle Sign In With Apple requests. @MainActor final class SignInWithAppleHelper: NSObject { @@ -165,54 +217,6 @@ private extension SignInWithAppleHelper { } } -struct AppleSignInResponse: Codable { - var code: String? - var id_token: String? - var state: String? - var user: AppleSignInUser - - init(_ appleIDCredential: ASAuthorizationAppleIDCredential) { - if let code = appleIDCredential.authorizationCode { - self.code = String(data: code, encoding: .utf8) - } else { - self.code = nil - } - if let id_token = appleIDCredential.identityToken { - self.id_token = String(data: id_token, encoding: .utf8) - } else { - self.id_token = nil - } - self.state = appleIDCredential.state - self.user = AppleSignInUser(nameComponents: appleIDCredential.fullName, email: appleIDCredential.email) - } -} - -struct AppleSignInUser: Codable { - var name: FullName? - var email: String - - init(nameComponents: PersonNameComponents?, email: String?) { - if let nameComponents = nameComponents { - self.name = FullName(nameComponents) - } else { - self.name = nil - } - self.email = email ?? "" - } -} - -struct FullName: Codable { - var firstName: String? - var lastName: String? -} - -extension FullName { - init(_ nameComponents: PersonNameComponents) { - firstName = nameComponents.givenName - lastName = nameComponents.familyName - } -} - //MARK: ASAuthorizationControllerDelegate extension SignInWithAppleHelper: ASAuthorizationControllerDelegate { func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { @@ -239,8 +243,10 @@ extension SignInWithAppleHelper: ASAuthorizationControllerDelegate { return } } +#endif //MARK: ASAuthorizationControllerPresentationContextProviding +#if canImport(UIKit) @MainActor extension UIViewController: @retroactive ASAuthorizationControllerPresentationContextProviding { public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { @@ -272,3 +278,4 @@ extension UIViewController: @retroactive ASAuthorizationControllerPresentationCo """) } } +#endif diff --git a/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookHandler.swift b/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookHandler.swift index d1799ec0..21654e60 100644 --- a/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookHandler.swift +++ b/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookHandler.swift @@ -8,6 +8,7 @@ // of the MIT license. See the LICENSE file for details. // +#if canImport(FBSDKLoginKit) import Foundation internal import FBSDKLoginKit internal import FBSDKCoreKit @@ -90,3 +91,4 @@ import PingExternalIdP return try await FacebookHandlerUtils.authorize(idpClient: idpClient, configuration: self.configuration, manager: self.manager) } } +#endif diff --git a/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookHandlerUtils.swift b/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookHandlerUtils.swift index 219021d8..cc6bff05 100644 --- a/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookHandlerUtils.swift +++ b/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookHandlerUtils.swift @@ -8,6 +8,7 @@ // of the MIT license. See the LICENSE file for details. // +#if canImport(FBSDKLoginKit) import Foundation internal import FBSDKLoginKit internal import FBSDKCoreKit @@ -56,3 +57,4 @@ class FacebookHandlerUtils { } } } +#endif diff --git a/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookRequestHandler.swift b/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookRequestHandler.swift index 8a2c56a1..e9df4244 100644 --- a/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookRequestHandler.swift +++ b/ExternalIdPFacebook/ExternalIdPFacebook/Handlers/FacebookRequestHandler.swift @@ -8,6 +8,7 @@ // of the MIT license. See the LICENSE file for details. // +#if canImport(FBSDKLoginKit) import Foundation import PingNetwork internal import FBSDKLoginKit @@ -99,3 +100,4 @@ import PingExternalIdP return request } } +#endif diff --git a/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleHandler.swift b/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleHandler.swift index 70e92510..293e1117 100644 --- a/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleHandler.swift +++ b/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleHandler.swift @@ -9,10 +9,11 @@ // import Foundation -import UIKit import PingExternalIdP -internal import GoogleSignIn +#if canImport(UIKit) +import UIKit +internal import GoogleSignIn /// A handler class for managing Google Identity Provider (IdP) authorization. @MainActor @objc public final class GoogleHandler: NSObject, @preconcurrency IdpHandler, Sendable { @@ -37,5 +38,4 @@ internal import GoogleSignIn return try await GoogleHandlerUtils.authorize(idpClient: idpClient) } } - - +#endif diff --git a/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleHandlerUtils.swift b/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleHandlerUtils.swift index 0c799388..cde9941b 100644 --- a/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleHandlerUtils.swift +++ b/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleHandlerUtils.swift @@ -9,10 +9,11 @@ // import Foundation -import UIKit import PingExternalIdP -internal import GoogleSignIn +#if canImport(UIKit) +import UIKit +internal import GoogleSignIn /// Utility class for handling Google Sign-In operations. @MainActor class GoogleHandlerUtils { @@ -52,3 +53,4 @@ class GoogleAuthenticationManager { } } } +#endif diff --git a/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleRequestHandler.swift b/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleRequestHandler.swift index e858c4bc..60724346 100644 --- a/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleRequestHandler.swift +++ b/ExternalIdPGoogle/ExternalIdPGoogle/Handlers/GoogleRequestHandler.swift @@ -10,10 +10,11 @@ import Foundation import PingNetwork -import UIKit import PingExternalIdP -internal import GoogleSignIn +#if canImport(UIKit) +import UIKit +internal import GoogleSignIn /// A handler class for managing Google Identity Provider (IdP) authorization. @MainActor @objc public class GoogleRequestHandler: NSObject, IdpRequestHandler { @@ -60,3 +61,4 @@ internal import GoogleSignIn return request } } +#endif diff --git a/Fido/Fido/Davinci/FidoAuthenticationCollector.swift b/Fido/Fido/Davinci/FidoAuthenticationCollector.swift index c3794bb2..effb1f6d 100644 --- a/Fido/Fido/Davinci/FidoAuthenticationCollector.swift +++ b/Fido/Fido/Davinci/FidoAuthenticationCollector.swift @@ -12,7 +12,9 @@ import Foundation import PingDavinciPlugin import PingLogger +#if canImport(UIKit) import UIKit +#endif import AuthenticationServices import PingOrchestrate import PingCommons diff --git a/Fido/Fido/Davinci/FidoRegistrationCollector.swift b/Fido/Fido/Davinci/FidoRegistrationCollector.swift index 6a6c6f6c..56596e13 100644 --- a/Fido/Fido/Davinci/FidoRegistrationCollector.swift +++ b/Fido/Fido/Davinci/FidoRegistrationCollector.swift @@ -10,7 +10,9 @@ import Foundation import PingLogger +#if canImport(UIKit) import UIKit +#endif import AuthenticationServices import PingDavinciPlugin import PingOrchestrate diff --git a/Fido/Fido/Fido.swift b/Fido/Fido/Fido.swift index e2029444..bd517b7c 100644 --- a/Fido/Fido/Fido.swift +++ b/Fido/Fido/Fido.swift @@ -10,7 +10,9 @@ import Foundation import AuthenticationServices +#if canImport(UIKit) import UIKit +#endif /// Fido is a class that provides FIDO registration and authentication functionalities. public class Fido: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding { @@ -153,10 +155,12 @@ public class Fido: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationC ///- Returns: The presentation anchor. public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { guard let window = window else { + #if canImport(UIKit) if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = windowScene.windows.first { return window } + #endif fatalError("Window not set. This should never occur.") } return window @@ -244,7 +248,7 @@ public class Fido: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationC // Map excludeCredentials to ASAuthorizationPlatformPublicKeyCredentialDescriptor if let excludeCredentials = options.excludeCredentials { - if #available(iOS 17.4, *) { + if #available(iOS 17.4, macOS 13.5, *) { request.excludedCredentials = excludeCredentials.compactMap { descriptor -> ASAuthorizationPlatformPublicKeyCredentialDescriptor? in guard let credentialIDData = Data(base64Encoded: descriptor.id, options: .ignoreUnknownCharacters) else { return nil @@ -324,7 +328,7 @@ public class Fido: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationC // Determine authenticator attachment type var attachmentValue: String = FidoConstants.FIELD_AUTHENTICATOR_ATTACHMENT_PLATFORM if let registrationCredential = credential as? ASAuthorizationPlatformPublicKeyCredentialRegistration { - if #available(iOS 16.6, *) { + if #available(iOS 16.6, macOS 13.5, *) { attachmentValue = registrationCredential.attachment == .platform ? FidoConstants.FIELD_AUTHENTICATOR_ATTACHMENT_PLATFORM : FidoConstants.FIELD_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM } else { // Fallback for iOS 15 - default to platform since that's the only option on iOS 15 @@ -347,7 +351,7 @@ public class Fido: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationC // Determine authenticator attachment type for assertion var attachmentValue: String = FidoConstants.FIELD_AUTHENTICATOR_ATTACHMENT_PLATFORM if let assertionCredential = credential as? ASAuthorizationPlatformPublicKeyCredentialAssertion { - if #available(iOS 16.6, *) { + if #available(iOS 16.6, macOS 13.5, *) { attachmentValue = assertionCredential.attachment == .platform ? FidoConstants.FIELD_AUTHENTICATOR_ATTACHMENT_PLATFORM : FidoConstants.FIELD_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM } else { // Fallback for iOS 15 - default to platform since that's the only option on iOS 15 diff --git a/JourneyPlugin/JourneyPlugin/ContinueNode.swift b/JourneyPlugin/JourneyPlugin/ContinueNode.swift index 312e3339..1ec47fdf 100644 --- a/JourneyPlugin/JourneyPlugin/ContinueNode.swift +++ b/JourneyPlugin/JourneyPlugin/ContinueNode.swift @@ -96,10 +96,10 @@ extension ContinueNode { // Try to find the best match based on user's preferred locales let preferredLocales: [Locale] - if #available(iOS 26, *) { + if #available(iOS 26, macOS 26, *) { preferredLocales = Locale.preferredLocales } else { - // Fallback for iOS 16+ + // Fallback for iOS 16+ / macOS 13+ preferredLocales = Locale.preferredLanguages.map { Locale(identifier: $0) } } diff --git a/Oidc/Oidc/Module/Web.swift b/Oidc/Oidc/Module/Web.swift index fa4e7d5e..49ee0732 100644 --- a/Oidc/Oidc/Module/Web.swift +++ b/Oidc/Oidc/Module/Web.swift @@ -8,12 +8,12 @@ // of the MIT license. See the LICENSE file for details. // - import PingOrchestrate import PingBrowser import Foundation import PingNetwork +#if canImport(UIKit) /// A module that integrates OIDC capabilities into the DaVinci workflow. public class WebModule { @@ -121,3 +121,4 @@ extension WebModule { return data } } +#endif diff --git a/Oidc/Oidc/OidcWebClient.swift b/Oidc/Oidc/OidcWebClient.swift index af088eb7..8da3d8aa 100644 --- a/Oidc/Oidc/OidcWebClient.swift +++ b/Oidc/Oidc/OidcWebClient.swift @@ -41,7 +41,9 @@ public extension OidcWebClient { config.timeout = 30 config.module(OidcModule.config) + #if canImport(UIKit) config.module(WebModule.config) + #endif // Apply custom configuration block(config) diff --git a/Package.swift b/Package.swift index 44b45071..7ca730b1 100644 --- a/Package.swift +++ b/Package.swift @@ -5,8 +5,7 @@ let package = Package( name: "Ping-SDK-iOS", platforms: [ .iOS(.v16), - // Added macOS minimum to satisfy transitive dependency (GoogleSignIn) which requires macOS 10.15+ - .macOS(.v10_15) + .macOS(.v13), ], products: [ // MARK: - Foundation @@ -73,7 +72,7 @@ let package = Package( name: "PingStorage", dependencies: [], path: "Storage/Storage", - exclude: ["Storage.h"], + exclude: ["Storage.h", "CACHING_GUIDE.md"], resources: [.copy("PrivacyInfo.xcprivacy")] ), @@ -233,7 +232,7 @@ let package = Package( name: "PingExternalIdPFacebook", dependencies: [ "PingExternalIdP", - .product(name: "FacebookLogin", package: "facebook-ios-sdk") + .product(name: "FacebookLogin", package: "facebook-ios-sdk", condition: .when(platforms: [.iOS])) ], path: "ExternalIdPFacebook/ExternalIdPFacebook", exclude: ["ExternalIdPFacebook.h"], @@ -246,7 +245,7 @@ let package = Package( dependencies: [ "PingDavinciPlugin", "PingJourneyPlugin", - .product(name: "PingOneSignals", package: "pingone-signals-sdk-ios") + .product(name: "PingOneSignals", package: "pingone-signals-sdk-ios", condition: .when(platforms: [.iOS])) ], path: "Protect/Protect", exclude: ["Protect.h"], @@ -257,7 +256,7 @@ let package = Package( dependencies: [ "PingCommons", "PingJourneyPlugin", - .product(name: "RecaptchaEnterprise", package: "recaptcha-enterprise-mobile-sdk") + .product(name: "RecaptchaEnterprise", package: "recaptcha-enterprise-mobile-sdk", condition: .when(platforms: [.iOS])) ], path: "ReCaptchaEnterprise/ReCaptchaEnterprise", exclude: ["ReCaptchaEnterprise.h"], diff --git a/Protect/Protect/Journey/PingOneProtectEvaluationCallback.swift b/Protect/Protect/Journey/PingOneProtectEvaluationCallback.swift index aeb877a7..8e93404e 100644 --- a/Protect/Protect/Journey/PingOneProtectEvaluationCallback.swift +++ b/Protect/Protect/Journey/PingOneProtectEvaluationCallback.swift @@ -8,6 +8,7 @@ // of the MIT license. See the LICENSE file for details. // +#if canImport(PingOneSignals) import Foundation import PingJourneyPlugin @@ -52,3 +53,4 @@ public class PingOneProtectEvaluationCallback: AbstractProtectCallback, @uncheck } } } +#endif diff --git a/Protect/Protect/Journey/PingOneProtectInitializeCallback.swift b/Protect/Protect/Journey/PingOneProtectInitializeCallback.swift index 2a89c93c..50f828b8 100644 --- a/Protect/Protect/Journey/PingOneProtectInitializeCallback.swift +++ b/Protect/Protect/Journey/PingOneProtectInitializeCallback.swift @@ -8,6 +8,7 @@ // of the MIT license. See the LICENSE file for details. // +#if canImport(PingOneSignals) import Foundation import PingJourneyPlugin @@ -109,3 +110,4 @@ extension JourneyConstants { public static let deviceAttributesToIgnore = "deviceAttributesToIgnore" public static let pauseBehavioralData = "pauseBehavioralData" } +#endif diff --git a/Protect/Protect/Journey/ProtectCallbacks.swift b/Protect/Protect/Journey/ProtectCallbacks.swift index b984b45b..8b6a1ce2 100644 --- a/Protect/Protect/Journey/ProtectCallbacks.swift +++ b/Protect/Protect/Journey/ProtectCallbacks.swift @@ -8,6 +8,7 @@ // of the MIT license. See the LICENSE file for details. // +#if canImport(PingOneSignals) import PingJourneyPlugin import Foundation @@ -27,3 +28,4 @@ extension JourneyConstants { public static let pingOneProtectInitializeCallback = "PingOneProtectInitializeCallback" public static let pingOneProtectEvaluationCallback = "PingOneProtectEvaluationCallback" } +#endif diff --git a/Protect/Protect/Protect.swift b/Protect/Protect/Protect.swift index abda8b9c..da92fa5a 100644 --- a/Protect/Protect/Protect.swift +++ b/Protect/Protect/Protect.swift @@ -7,6 +7,7 @@ // This software may be modified and distributed under the terms // of the MIT license. See the LICENSE file for details. +#if canImport(PingOneSignals) import PingOrchestrate internal import PingOneSignals @@ -144,3 +145,4 @@ public class ProtectConfig: @unchecked Sendable { /// Initializes a new instance of the ProtectConfig. public init() {} } +#endif diff --git a/Protect/Protect/ProtectCollector.swift b/Protect/Protect/ProtectCollector.swift index ffb4ef18..7b4bc53b 100644 --- a/Protect/Protect/ProtectCollector.swift +++ b/Protect/Protect/ProtectCollector.swift @@ -7,6 +7,7 @@ // This software may be modified and distributed under the terms // of the MIT license. See the LICENSE file for details. +#if canImport(PingOneSignals) import Foundation import PingDavinciPlugin @@ -103,3 +104,4 @@ extension Constants { public static let behavioralDataCollection = "behavioralDataCollection" public static let universalDeviceIdentification = "universalDeviceIdentification" } +#endif diff --git a/Protect/Protect/ProtectLifecycleModule.swift b/Protect/Protect/ProtectLifecycleModule.swift index f8aef536..8525ff86 100644 --- a/Protect/Protect/ProtectLifecycleModule.swift +++ b/Protect/Protect/ProtectLifecycleModule.swift @@ -8,6 +8,7 @@ // of the MIT license. See the LICENSE file for details. // +#if canImport(PingOneSignals) import Foundation import PingDavinciPlugin import PingOrchestrate @@ -66,3 +67,4 @@ public class ProtectLifecycleConfig: ProtectConfig, @unchecked Sendable { public override init() {} } +#endif diff --git a/Push/Push/Utilities/PushUriParser.swift b/Push/Push/Utilities/PushUriParser.swift index dcd675e5..3d630d72 100644 --- a/Push/Push/Utilities/PushUriParser.swift +++ b/Push/Push/Utilities/PushUriParser.swift @@ -183,7 +183,7 @@ public enum PushUriParser { /// - Throws: `PushError.invalidUri` if the URL is malformed. private static func extractServerEndpoint(_ url: String) throws -> String { let urlComponents: URLComponents? - if #available(iOS 17.0, *) { + if #available(iOS 17.0, macOS 14.0, *) { urlComponents = URLComponents(string: url, encodingInvalidCharacters: true) } else { urlComponents = URLComponents(string: url) diff --git a/ReCaptchaEnterprise/ReCaptchaEnterprise/ReCaptchaEnterprise.swift b/ReCaptchaEnterprise/ReCaptchaEnterprise/ReCaptchaEnterprise.swift index a03abc5e..4a3af992 100644 --- a/ReCaptchaEnterprise/ReCaptchaEnterprise/ReCaptchaEnterprise.swift +++ b/ReCaptchaEnterprise/ReCaptchaEnterprise/ReCaptchaEnterprise.swift @@ -17,9 +17,11 @@ class ReCaptchaEnterprise: NSObject { /// Registers the ReCaptchaEnterpriseCallback with the collector factory @objc public static func registerCallbacks() { + #if canImport(RecaptchaEnterprise) Task { await CallbackRegistry.shared.register(type: JourneyConstants.reCaptchaEnterpriseCallback, callback: ReCaptchaEnterpriseCallback.self) } + #endif } } diff --git a/ReCaptchaEnterprise/ReCaptchaEnterprise/ReCaptchaEnterpriseCallback.swift b/ReCaptchaEnterprise/ReCaptchaEnterprise/ReCaptchaEnterpriseCallback.swift index e4446563..66a84611 100644 --- a/ReCaptchaEnterprise/ReCaptchaEnterprise/ReCaptchaEnterpriseCallback.swift +++ b/ReCaptchaEnterprise/ReCaptchaEnterprise/ReCaptchaEnterpriseCallback.swift @@ -8,7 +8,7 @@ // of the MIT license. See the LICENSE file for details. // - +#if canImport(RecaptchaEnterprise) import Foundation import PingJourneyPlugin import PingLogger @@ -221,6 +221,7 @@ public class ReCaptchaEnterpriseCallback: AbstractCallback, @unchecked Sendable // MARK: - ReCaptchaEnterpriseConfig + /// Configuration object for customizing reCAPTCHA Enterprise execution. /// /// This class allows fine-grained control over reCAPTCHA behavior @@ -246,3 +247,4 @@ public final class ReCaptchaEnterpriseConfig: @unchecked Sendable { /// Initializes a new instance of `ReCaptchaEnterpriseConfig` public init() {} } +#endif diff --git a/TamperDetector/TamperDetector/TamperDetector.swift b/TamperDetector/TamperDetector/TamperDetector.swift index 041bf05d..959f9b8c 100644 --- a/TamperDetector/TamperDetector/TamperDetector.swift +++ b/TamperDetector/TamperDetector/TamperDetector.swift @@ -2,7 +2,7 @@ // TamperDetector.swift // PingTamperDetector // -// Copyright (c) 2025 Ping Identity Corporation. All rights reserved. +// Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved. // // This software may be modified and distributed under the terms // of the MIT license. See the LICENSE file for details. @@ -67,10 +67,9 @@ public class TamperDetector { /// The default set of detectors used for tampering analysis. @MainActor public static var defaultDetectors: [TamperDetectorProtocol] { - return [ + var detectors: [TamperDetectorProtocol] = [ SuspiciousFilesExistenceDetector(), SuspiciousFilesAccessibleDetector(), - URLSchemeDetector(), RestrictedDirectoriesWritableDetector(), SymbolicLinkDetector(), DyldDetector(), @@ -78,6 +77,10 @@ public class TamperDetector { SuspiciousObjCClassesDetector(), SandboxRestrictedFilesAccessable() ] + #if canImport(UIKit) + detectors.append(URLSchemeDetector()) + #endif + return detectors } /// The list of detectors to be used for the analysis. diff --git a/TamperDetector/TamperDetector/URLSchemeDetector.swift b/TamperDetector/TamperDetector/URLSchemeDetector.swift index f5d6dc16..02351956 100644 --- a/TamperDetector/TamperDetector/URLSchemeDetector.swift +++ b/TamperDetector/TamperDetector/URLSchemeDetector.swift @@ -2,13 +2,13 @@ // URLSchemeDetector.swift // PingTamperDetector // -// Copyright (c) 2025 Ping Identity Corporation. All rights reserved. +// Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved. // // This software may be modified and distributed under the terms // of the MIT license. See the LICENSE file for details. // - +#if canImport(UIKit) import Foundation import UIKit import PingLogger @@ -58,3 +58,4 @@ public class URLSchemeDetector: TamperDetectorProtocol { } } } +#endif