diff --git a/Package.swift b/Package.swift index 3951a29..37ecffd 100644 --- a/Package.swift +++ b/Package.swift @@ -6,9 +6,11 @@ import PackageDescription let package = Package( name: "UID2", defaultLocalization: "en", + // NB: The UID2 framework code only runs on iOS 13 & tvOS 13, however this allows + // integration in apps supporting iOS 12. platforms: [ - .iOS(.v13), - .tvOS(.v13) + .iOS(.v12), + .tvOS(.v12) ], products: [ .library( diff --git a/Sources/UID2/CryptoUtil.swift b/Sources/UID2/CryptoUtil.swift index 5e16329..88a6c59 100644 --- a/Sources/UID2/CryptoUtil.swift +++ b/Sources/UID2/CryptoUtil.swift @@ -9,6 +9,7 @@ import CryptoKit import Foundation import SwiftASN1 +@available(iOS 13, tvOS 13, *) struct CryptoUtil: Sendable { // Parses a server's public key and returns a newly generated public key and symmetric key. var parseKey: @Sendable (_ string: String) throws -> (SymmetricKey, P256.KeyAgreement.PublicKey) @@ -17,6 +18,7 @@ struct CryptoUtil: Sendable { var encrypt: @Sendable (_ data: Data, _ key: SymmetricKey, _ authenticatedData: Data) throws -> AES.GCM.SealedBox } +@available(iOS 13, tvOS 13, *) extension CryptoUtil { private static let serverPublicKeyPrefixLength = 9 diff --git a/Sources/UID2/Extensions/PublicKey+Extensions.swift b/Sources/UID2/Extensions/PublicKey+Extensions.swift index e0f1e01..279608c 100644 --- a/Sources/UID2/Extensions/PublicKey+Extensions.swift +++ b/Sources/UID2/Extensions/PublicKey+Extensions.swift @@ -9,6 +9,7 @@ import CryptoKit import Foundation import SwiftASN1 +@available(iOS 13, tvOS 13, *) extension P256.KeyAgreement.PublicKey { // CryptoKit's implementation is only available in iOS 14 var derRepresentation: Data { diff --git a/Sources/UID2/Extensions/URLSession+Extensions.swift b/Sources/UID2/Extensions/URLSession+Extensions.swift index e7c0b09..8dae129 100644 --- a/Sources/UID2/Extensions/URLSession+Extensions.swift +++ b/Sources/UID2/Extensions/URLSession+Extensions.swift @@ -7,6 +7,7 @@ import Foundation +@available(iOS 13, tvOS 13, *) extension URLSession: NetworkSession { func loadData(for request: URLRequest) async throws -> (Data, HTTPURLResponse) { diff --git a/Sources/UID2/Internal/Broadcaster.swift b/Sources/UID2/Internal/Broadcaster.swift index 278b38f..d403eaa 100644 --- a/Sources/UID2/Internal/Broadcaster.swift +++ b/Sources/UID2/Internal/Broadcaster.swift @@ -1,6 +1,7 @@ import Foundation /// Send a value to multiple observers +@available(iOS 13, tvOS 13, *) actor Broadcaster { typealias Identifier = UUID private var continuations: [Identifier: AsyncStream.Continuation] = [:] diff --git a/Sources/UID2/Internal/Queue.swift b/Sources/UID2/Internal/Queue.swift index 93fc8e9..d00663a 100644 --- a/Sources/UID2/Internal/Queue.swift +++ b/Sources/UID2/Internal/Queue.swift @@ -3,6 +3,7 @@ import Foundation /// When bridging from a sync to async context using multiple `Task`s, order of execution is not guaranteed. /// Using an `AsyncStream` we can bridge enqueued work to an async context within a single `Task`. /// https://forums.swift.org/t/a-pitfall-when-using-didset-and-task-together-order-cant-be-guaranteed/71311/6 +@available(iOS 13, tvOS 13, *) final class Queue { typealias Operation = @Sendable () async -> Void private let continuation: AsyncStream.Continuation diff --git a/Sources/UID2/KeychainManager.swift b/Sources/UID2/KeychainManager.swift index 8e9f2aa..d5f6875 100644 --- a/Sources/UID2/KeychainManager.swift +++ b/Sources/UID2/KeychainManager.swift @@ -5,6 +5,7 @@ import Foundation import Security +@available(iOS 13, tvOS 13, *) extension Storage { static func keychainStorage() -> Storage { let storage = KeychainManager() @@ -17,6 +18,7 @@ extension Storage { } /// Securely manages data in the Keychain +@available(iOS 13, tvOS 13, *) actor KeychainManager { private let attrAccount = "uid2" diff --git a/Sources/UID2/Networking/ClientGenerate.swift b/Sources/UID2/Networking/ClientGenerate.swift index 8b361b2..1d91cd9 100644 --- a/Sources/UID2/Networking/ClientGenerate.swift +++ b/Sources/UID2/Networking/ClientGenerate.swift @@ -9,6 +9,8 @@ import CryptoKit import Foundation extension Request { + + @available(iOS 13, tvOS 13, *) static func clientGenerate( payload: Data, initializationVector: Data, @@ -54,6 +56,7 @@ struct ClientGeneratePayload: Encodable { } } +@available(iOS 13, tvOS 13, *) extension ClientGeneratePayload { init(_ identity: IdentityType) { switch identity { @@ -87,6 +90,7 @@ struct ClientGenerateRequestBody: Encodable { } } +@available(iOS 13, tvOS 13, *) fileprivate extension String { func sha256hash() -> Data { let digest = SHA256.hash(data: Data(self.utf8)) diff --git a/Sources/UID2/Networking/DataEnvelope.swift b/Sources/UID2/Networking/DataEnvelope.swift index 389ce31..4f93823 100644 --- a/Sources/UID2/Networking/DataEnvelope.swift +++ b/Sources/UID2/Networking/DataEnvelope.swift @@ -8,6 +8,7 @@ import CryptoKit import Foundation +@available(iOS 13, tvOS 13, *) internal enum DataEnvelope { /// Decrypts raw response envelope data, which is expected to be a base64 encoded string. diff --git a/Sources/UID2/Networking/NetworkSession.swift b/Sources/UID2/Networking/NetworkSession.swift index 34fb6de..faeac48 100644 --- a/Sources/UID2/Networking/NetworkSession.swift +++ b/Sources/UID2/Networking/NetworkSession.swift @@ -8,6 +8,7 @@ import Foundation /// Common interface for networking and unit testing +@available(iOS 13, tvOS 13, *) protocol NetworkSession: Sendable { func loadData(for request: URLRequest) async throws -> (Data, HTTPURLResponse) diff --git a/Sources/UID2/UID2Client.swift b/Sources/UID2/UID2Client.swift index c9c899b..a3b9b8c 100644 --- a/Sources/UID2/UID2Client.swift +++ b/Sources/UID2/UID2Client.swift @@ -14,6 +14,7 @@ import Foundation #endif @preconcurrency import OSLog +@available(iOS 13, tvOS 13, *) internal final class UID2Client: Sendable { private let clientVersion: String private let environment: Environment diff --git a/Sources/UID2/UID2Manager.State.swift b/Sources/UID2/UID2Manager.State.swift index 8bddd8f..1e2d858 100644 --- a/Sources/UID2/UID2Manager.State.swift +++ b/Sources/UID2/UID2Manager.State.swift @@ -4,6 +4,7 @@ import Foundation +@available(iOS 13, tvOS 13, *) extension UID2Manager { public enum State: Hashable, Sendable, Codable { case optout @@ -15,6 +16,7 @@ extension UID2Manager { } } +@available(iOS 13, tvOS 13, *) extension UID2Manager.State { /// A 'case path' returning the current `IdentityStatus`. public var identityStatus: IdentityStatus { @@ -49,6 +51,7 @@ extension UID2Manager.State { } } +@available(iOS 13, tvOS 13, *) extension UID2Manager.State { init?(_ package: IdentityPackage) { switch package.status { diff --git a/Sources/UID2/UID2Manager.swift b/Sources/UID2/UID2Manager.swift index d9f5dba..fc7e29f 100644 --- a/Sources/UID2/UID2Manager.swift +++ b/Sources/UID2/UID2Manager.swift @@ -10,6 +10,7 @@ import Foundation import OSLog // swiftlint:disable:next type_body_length +@available(iOS 13, tvOS 13, *) public final actor UID2Manager { private enum InitializationState { case pending diff --git a/Tests/TestHelpers/TestCryptoUtil.swift b/Tests/TestHelpers/TestCryptoUtil.swift index de8a583..bef9c7e 100644 --- a/Tests/TestHelpers/TestCryptoUtil.swift +++ b/Tests/TestHelpers/TestCryptoUtil.swift @@ -36,6 +36,7 @@ private final class Atomic: @unchecked Sendable { /// A test convenience which exposes the Symmetric Key it generates for the client. /// This key can then be used to encrypt stub responses for the client. +@available(iOS 13, tvOS 13, *) public final class TestCryptoUtil { private let atomicSymmetricKey: Atomic diff --git a/Tests/TestHelpers/XCTest+Extensions.swift b/Tests/TestHelpers/XCTest+Extensions.swift index fc51f56..99c4ad9 100644 --- a/Tests/TestHelpers/XCTest+Extensions.swift +++ b/Tests/TestHelpers/XCTest+Extensions.swift @@ -8,6 +8,7 @@ import XCTest /// `XCTAssertThrowsError` doesn't support async expressions. +@available(iOS 13, tvOS 13, *) public func assertThrowsError( _ expression: @escaping @autoclosure () async throws -> T, _ message: @autoclosure () -> String = "", diff --git a/UID2.podspec.json b/UID2.podspec.json index 7450727..91424b5 100644 --- a/UID2.podspec.json +++ b/UID2.podspec.json @@ -12,8 +12,8 @@ "tag": "v1.5.0" }, "platforms": { - "ios": "13.0", - "tvos": "13.0" + "ios": "12.0", + "tvos": "12.0" }, "swift_versions": [ "5"