diff --git a/.swiftlint.yml b/.swiftlint.yml index 8b41656f2f..af1ef85f65 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -7,6 +7,7 @@ excluded: - scan_derived_data - .git - .build + - Packages/*/.build opt_in_rules: - sorted_imports @@ -19,7 +20,9 @@ opt_in_rules: custom_rules: xctestcase_superclass: included: ".*\\.swift" - excluded: Tests/BackendIntegrationTests + excluded: + - Tests/BackendIntegrationTests + - Packages regex: "\\: XCTestCase \\{" name: "XCTestCase Superclass" message: "Test classes must inherit `TestCase` instead." diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..919434a625 --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Package.swift b/Package.swift index b6b727e7b5..f10eb512e6 100644 --- a/Package.swift +++ b/Package.swift @@ -4,25 +4,20 @@ import PackageDescription import class Foundation.ProcessInfo -func resolveTargets() -> [Target] { - let baseTargets: [Target] = [ - .target(name: "RevenueCat", - path: "Sources", - exclude: ["Info.plist"]) - ] +let dependencies: [Package.Dependency] = { + // Only add DocC Plugin when building docs, so that clients of this library won't + // unnecessarily also get the DocC Plugin + let environmentVariables = ProcessInfo.processInfo.environment + let shouldIncludeDocCPlugin = environmentVariables["INCLUDE_DOCC_PLUGIN"] == "true" - return baseTargets -} + var result: [Package.Dependency] = [] -// Only add DocC Plugin when building docs, so that clients of this library won't -// unnecessarily also get the DocC Plugin -let environmentVariables = ProcessInfo.processInfo.environment -let shouldIncludeDocCPlugin = environmentVariables["INCLUDE_DOCC_PLUGIN"] == "true" + if shouldIncludeDocCPlugin { + result.append(.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0")) + } -var dependencies: [Package.Dependency] = [] -if shouldIncludeDocCPlugin { - dependencies.append(.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0")) -} + return result +}() let package = Package( name: "RevenueCat", @@ -34,8 +29,22 @@ let package = Package( ], products: [ .library(name: "RevenueCat", - targets: ["RevenueCat"]) + targets: ["RevenueCat"]), + .library(name: "ReceiptParser", + type: .static, + targets: ["ReceiptParser"]) ], dependencies: dependencies, - targets: resolveTargets() + targets: [ + .target(name: "RevenueCat", + dependencies: [.byName(name: "ReceiptParser")], + path: "Sources", + exclude: ["Info.plist"]), + .target(name: "ReceiptParser", + dependencies: [], + path: "Packages/ReceiptParser/Sources/ReceiptParser", + swiftSettings: [ + .unsafeFlags(["-enable-library-evolution"]) + ]) + ] ) diff --git a/Packages/ReceiptParser/.gitignore b/Packages/ReceiptParser/.gitignore new file mode 100644 index 0000000000..3b29812086 --- /dev/null +++ b/Packages/ReceiptParser/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Packages/ReceiptParser/.swiftpm/xcode/xcshareddata/xcschemes/ReceiptParser.xcscheme b/Packages/ReceiptParser/.swiftpm/xcode/xcshareddata/xcschemes/ReceiptParser.xcscheme new file mode 100644 index 0000000000..137b5921a7 --- /dev/null +++ b/Packages/ReceiptParser/.swiftpm/xcode/xcshareddata/xcschemes/ReceiptParser.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Packages/ReceiptParser/Package.swift b/Packages/ReceiptParser/Package.swift new file mode 100644 index 0000000000..df17e0fe15 --- /dev/null +++ b/Packages/ReceiptParser/Package.swift @@ -0,0 +1,36 @@ +// 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: "ReceiptParser", + platforms: [ + .macOS(.v10_13), + .watchOS("6.2"), + .tvOS(.v11), + .iOS(.v11) + ], + products: [ + .library( + name: "ReceiptParser", + type: .static, + targets: ["ReceiptParser"]) + ], + dependencies: [ + .package(url: "git@github.com:Quick/Nimble.git", from: "10.0.0") + ], + targets: [ + .target( + name: "ReceiptParser", + dependencies: [], + swiftSettings: [ + .unsafeFlags(["-enable-library-evolution"]) + ] + ), + .testTarget( + name: "ReceiptParserTests", + dependencies: ["ReceiptParser", "Nimble"] + ) + ] +) diff --git a/Packages/ReceiptParser/README.md b/Packages/ReceiptParser/README.md new file mode 100644 index 0000000000..9d83a5ff3d --- /dev/null +++ b/Packages/ReceiptParser/README.md @@ -0,0 +1,3 @@ +# ReceiptParser + +A description of this package. diff --git a/Packages/ReceiptParser/ReceiptParser.podspec b/Packages/ReceiptParser/ReceiptParser.podspec new file mode 100644 index 0000000000..428c3de2c3 --- /dev/null +++ b/Packages/ReceiptParser/ReceiptParser.podspec @@ -0,0 +1,28 @@ +Pod::Spec.new do |s| + s.name = "ReceiptParser" + s.version = "4.15.0-SNAPSHOT" + s.summary = "TODO" + + s.description = <<-DESC + TODO https://www.revenuecat.com/ + DESC + + s.homepage = "https://www.revenuecat.com/" + s.license = { :type => 'MIT' } + s.author = { "RevenueCat, Inc." => "support@revenuecat.com" } + s.source = { :git => "https://github.com/revenuecat/purchases-ios.git", :tag => s.version.to_s } + s.documentation_url = "https://docs.revenuecat.com/" # TODO ? + + s.framework = 'StoreKit' + s.swift_version = '5.5' + + s.ios.deployment_target = '11.0' + s.watchos.deployment_target = '6.2' + s.tvos.deployment_target = '11.0' + s.osx.deployment_target = '10.13' + + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + + s.source_files = 'Sources/**/*.swift' + +end diff --git a/Sources/LocalReceiptParsing/BasicTypes/AppleReceipt.swift b/Packages/ReceiptParser/Sources/ReceiptParser/AppleReceipt.swift similarity index 67% rename from Sources/LocalReceiptParsing/BasicTypes/AppleReceipt.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/AppleReceipt.swift index b2b44bdf68..c8ad5f2017 100644 --- a/Sources/LocalReceiptParsing/BasicTypes/AppleReceipt.swift +++ b/Packages/ReceiptParser/Sources/ReceiptParser/AppleReceipt.swift @@ -17,13 +17,13 @@ import Foundation // swiftlint:disable nesting /// The contents of a parsed IAP receipt. -struct AppleReceipt: Equatable { +public struct AppleReceipt: Equatable { // swiftlint:disable:next line_length // https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html - struct Attribute { + public struct Attribute { - enum AttributeType: Int { + public enum AttributeType: Int { case bundleId = 2, applicationVersion = 3, @@ -36,22 +36,22 @@ struct AppleReceipt: Equatable { } - let type: AttributeType - let version: Int - let value: String + public let type: AttributeType + public let version: Int + public let value: String } - let bundleId: String - let applicationVersion: String - let originalApplicationVersion: String? - let opaqueValue: Data - let sha1Hash: Data - let creationDate: Date - let expirationDate: Date? - let inAppPurchases: [InAppPurchase] + public let bundleId: String + public let applicationVersion: String + public let originalApplicationVersion: String? + public let opaqueValue: Data + public let sha1Hash: Data + public let creationDate: Date + public let expirationDate: Date? + public let inAppPurchases: [InAppPurchase] - func purchasedIntroOfferOrFreeTrialProductIdentifiers() -> Set { + public func purchasedIntroOfferOrFreeTrialProductIdentifiers() -> Set { let productIdentifiers = self.inAppPurchases .filter { $0.isInIntroOfferPeriod == true || $0.isInTrialPeriod == true } .map { $0.productId } @@ -62,7 +62,7 @@ struct AppleReceipt: Equatable { // MARK: - Extensions -extension AppleReceipt { +public extension AppleReceipt { func containsActivePurchase(forProductIdentifier identifier: String) -> Bool { return ( @@ -79,8 +79,10 @@ extension AppleReceipt: Codable {} extension AppleReceipt: CustomDebugStringConvertible { - var debugDescription: String { - return (try? self.prettyPrintedJSON) ?? "" + public var debugDescription: String { + // TODO + return "TODO" +// return (try? self.prettyPrintedJSON) ?? "" } } diff --git a/Sources/LocalReceiptParsing/BasicTypes/ASN1Container.swift b/Packages/ReceiptParser/Sources/ReceiptParser/BasicTypes/ASN1Container.swift similarity index 100% rename from Sources/LocalReceiptParsing/BasicTypes/ASN1Container.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/BasicTypes/ASN1Container.swift diff --git a/Sources/LocalReceiptParsing/BasicTypes/ASN1ObjectIdentifier.swift b/Packages/ReceiptParser/Sources/ReceiptParser/BasicTypes/ASN1ObjectIdentifier.swift similarity index 100% rename from Sources/LocalReceiptParsing/BasicTypes/ASN1ObjectIdentifier.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/BasicTypes/ASN1ObjectIdentifier.swift diff --git a/Sources/LocalReceiptParsing/BasicTypes/InAppPurchase.swift b/Packages/ReceiptParser/Sources/ReceiptParser/BasicTypes/InAppPurchase.swift similarity index 68% rename from Sources/LocalReceiptParsing/BasicTypes/InAppPurchase.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/BasicTypes/InAppPurchase.swift index cbf00f8c42..43901f001b 100644 --- a/Sources/LocalReceiptParsing/BasicTypes/InAppPurchase.swift +++ b/Packages/ReceiptParser/Sources/ReceiptParser/BasicTypes/InAppPurchase.swift @@ -16,27 +16,27 @@ import Foundation extension AppleReceipt { - struct InAppPurchase: Equatable { - - let quantity: Int - let productId: String - let transactionId: String - let originalTransactionId: String? - let productType: ProductType - let purchaseDate: Date - let originalPurchaseDate: Date? - let expiresDate: Date? - let cancellationDate: Date? - let isInTrialPeriod: Bool? - let isInIntroOfferPeriod: Bool? - let webOrderLineItemId: Int64? - let promotionalOfferIdentifier: String? + public struct InAppPurchase: Equatable { + + public let quantity: Int + public let productId: String + public let transactionId: String + public let originalTransactionId: String? + public let productType: ProductType + public let purchaseDate: Date + public let originalPurchaseDate: Date? + public let expiresDate: Date? + public let cancellationDate: Date? + public let isInTrialPeriod: Bool? + public let isInIntroOfferPeriod: Bool? + public let webOrderLineItemId: Int64? + public let promotionalOfferIdentifier: String? } } -extension AppleReceipt.InAppPurchase { +public extension AppleReceipt.InAppPurchase { var isActiveSubscription: Bool { guard self.isSubscription, let expiration = self.expiresDate else { return false } @@ -59,7 +59,7 @@ extension AppleReceipt.InAppPurchase { extension AppleReceipt.InAppPurchase { - enum ProductType: Int { + public enum ProductType: Int { case unknown = -1, nonConsumable, @@ -72,13 +72,15 @@ extension AppleReceipt.InAppPurchase { } extension AppleReceipt.InAppPurchase { - var isSubscription: Bool { + + public var isSubscription: Bool { switch self.productType { case .unknown: return self.expiresDate != nil case .nonConsumable, .consumable: return false case .nonRenewingSubscription, .autoRenewableSubscription: return true } } + } // MARK: - @@ -88,8 +90,10 @@ extension AppleReceipt.InAppPurchase: Codable {} extension AppleReceipt.InAppPurchase: CustomDebugStringConvertible { - var debugDescription: String { - return (try? self.prettyPrintedJSON) ?? "" + public var debugDescription: String { + // TODO + return "" +// return (try? self.prettyPrintedJSON) ?? "" } } diff --git a/Sources/LocalReceiptParsing/Builders/ASN1ContainerBuilder.swift b/Packages/ReceiptParser/Sources/ReceiptParser/Builders/ASN1ContainerBuilder.swift similarity index 100% rename from Sources/LocalReceiptParsing/Builders/ASN1ContainerBuilder.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/Builders/ASN1ContainerBuilder.swift diff --git a/Sources/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilder.swift b/Packages/ReceiptParser/Sources/ReceiptParser/Builders/ASN1ObjectIdentifierBuilder.swift similarity index 100% rename from Sources/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilder.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/Builders/ASN1ObjectIdentifierBuilder.swift diff --git a/Sources/LocalReceiptParsing/Builders/AppleReceiptBuilder.swift b/Packages/ReceiptParser/Sources/ReceiptParser/Builders/AppleReceiptBuilder.swift similarity index 100% rename from Sources/LocalReceiptParsing/Builders/AppleReceiptBuilder.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/Builders/AppleReceiptBuilder.swift diff --git a/Sources/LocalReceiptParsing/Builders/InAppPurchaseBuilder.swift b/Packages/ReceiptParser/Sources/ReceiptParser/Builders/InAppPurchaseBuilder.swift similarity index 100% rename from Sources/LocalReceiptParsing/Builders/InAppPurchaseBuilder.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/Builders/InAppPurchaseBuilder.swift diff --git a/Packages/ReceiptParser/Sources/ReceiptParser/Data+Extensions.swift b/Packages/ReceiptParser/Sources/ReceiptParser/Data+Extensions.swift new file mode 100644 index 0000000000..d40e9e4736 --- /dev/null +++ b/Packages/ReceiptParser/Sources/ReceiptParser/Data+Extensions.swift @@ -0,0 +1,39 @@ +// +// File.swift +// +// +// Created by Nacho Soto on 11/18/22. +// + +import Foundation + +public extension NSData { + + func asString() -> String { + // 2 characters per byte + let deviceTokenString = NSMutableString(capacity: self.length * 2) + + self.enumerateBytes { bytes, byteRange, _ in + for index in stride(from: 0, to: byteRange.length, by: 1) { + let byte = bytes.load(fromByteOffset: index, as: UInt8.self) + deviceTokenString.appendFormat("%02x", byte) + } + } + + return deviceTokenString as String + } + +} + +public extension Data { + + var asString: String { + return (self as NSData).asString() + } + + /// Returns a string representing a fetch token. + var asFetchToken: String { + return self.base64EncodedString() + } + +} diff --git a/Sources/LocalReceiptParsing/DataConverters/ArraySlice_UInt8+Extensions.swift b/Packages/ReceiptParser/Sources/ReceiptParser/DataConverters/ArraySlice_UInt8+Extensions.swift similarity index 83% rename from Sources/LocalReceiptParsing/DataConverters/ArraySlice_UInt8+Extensions.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/DataConverters/ArraySlice_UInt8+Extensions.swift index 237b30ee62..e0c5898c6b 100644 --- a/Sources/LocalReceiptParsing/DataConverters/ArraySlice_UInt8+Extensions.swift +++ b/Packages/ReceiptParser/Sources/ReceiptParser/DataConverters/ArraySlice_UInt8+Extensions.swift @@ -53,3 +53,16 @@ extension ArraySlice where Element == UInt8 { } } + +private extension ISO8601DateFormatter { + + static let `default`: ISO8601DateFormatter = { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [ + .withInternetDateTime + ] + + return formatter + }() + +} diff --git a/Sources/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift b/Packages/ReceiptParser/Sources/ReceiptParser/DataConverters/UInt8+Extensions.swift similarity index 100% rename from Sources/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/DataConverters/UInt8+Extensions.swift diff --git a/Sources/Misc/DateExtensions.swift b/Packages/ReceiptParser/Sources/ReceiptParser/Date+Extensions.swift similarity index 100% rename from Sources/Misc/DateExtensions.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/Date+Extensions.swift diff --git a/Sources/LocalReceiptParsing/ReceiptParser.swift b/Packages/ReceiptParser/Sources/ReceiptParser/ReceiptParser.swift similarity index 69% rename from Sources/LocalReceiptParsing/ReceiptParser.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/ReceiptParser.swift index 596f1bbb35..2e9d5894d4 100644 --- a/Sources/LocalReceiptParsing/ReceiptParser.swift +++ b/Packages/ReceiptParser/Sources/ReceiptParser/ReceiptParser.swift @@ -14,9 +14,18 @@ import Foundation -class ReceiptParser { +public protocol ParserType { - static let `default`: ReceiptParser = .init() + func receiptHasTransactions(receiptData: Data) -> Bool + func parse(from receiptData: Data) throws -> AppleReceipt + +} + +// TODO: move logs outside + +public class Parser: ParserType { + + public static let `default`: ParserType = Parser() private let containerBuilder: ASN1ContainerBuilder private let receiptBuilder: AppleReceiptBuilder @@ -27,38 +36,38 @@ class ReceiptParser { self.receiptBuilder = receiptBuilder } - func receiptHasTransactions(receiptData: Data) -> Bool { - Logger.info(Strings.receipt.parsing_receipt) + public func receiptHasTransactions(receiptData: Data) -> Bool { +// Logger.info(Strings.receipt.parsing_receipt) if let receipt = try? parse(from: receiptData) { return receipt.inAppPurchases.count > 0 } - Logger.warn(Strings.receipt.parsing_receipt_failed(fileName: #fileID, functionName: #function)) +// Logger.warn(Strings.receipt.parsing_receipt_failed(fileName: #fileID, functionName: #function)) return true } - func parse(from receiptData: Data) throws -> AppleReceipt { + public func parse(from receiptData: Data) throws -> AppleReceipt { let intData = [UInt8](receiptData) - let asn1Container = try containerBuilder.build(fromPayload: ArraySlice(intData)) - guard let receiptASN1Container = try findASN1Container(withObjectId: ASN1ObjectIdentifier.data, + let asn1Container = try self.containerBuilder.build(fromPayload: ArraySlice(intData)) + guard let receiptASN1Container = try self.findASN1Container(withObjectId: ASN1ObjectIdentifier.data, inContainer: asn1Container) else { - Logger.error(Strings.receipt.data_object_identifer_not_found_receipt) +// Logger.error(Strings.receipt.data_object_identifer_not_found_receipt) throw ReceiptReadingError.dataObjectIdentifierMissing } - let receipt = try receiptBuilder.build(fromContainer: receiptASN1Container) - Logger.info(Strings.receipt.parsing_receipt_success) + let receipt = try self.receiptBuilder.build(fromContainer: receiptASN1Container) +// Logger.info(Strings.receipt.parsing_receipt_success) return receipt } } // @unchecked because: // - Class is not `final` (it's mocked). This implicitly makes subclasses `Sendable` even if they're not thread-safe. -extension ReceiptParser: @unchecked Sendable {} +extension Parser: @unchecked Sendable {} // MARK: - -private extension ReceiptParser { +private extension Parser { func findASN1Container(withObjectId objectId: ASN1ObjectIdentifier, inContainer container: ASN1Container) throws -> ASN1Container? { diff --git a/Sources/LocalReceiptParsing/ReceiptParsingError.swift b/Packages/ReceiptParser/Sources/ReceiptParser/ReceiptParsingError.swift similarity index 100% rename from Sources/LocalReceiptParsing/ReceiptParsingError.swift rename to Packages/ReceiptParser/Sources/ReceiptParser/ReceiptParsingError.swift diff --git a/Tests/UnitTests/LocalReceiptParsing/AppleReceiptTests.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/AppleReceiptTests.swift similarity index 98% rename from Tests/UnitTests/LocalReceiptParsing/AppleReceiptTests.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/AppleReceiptTests.swift index a19eb51327..76465ab3de 100644 --- a/Tests/UnitTests/LocalReceiptParsing/AppleReceiptTests.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/AppleReceiptTests.swift @@ -14,9 +14,9 @@ import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser -final class AppleReceiptTests: TestCase { +final class AppleReceiptTests: XCTestCase { // MARK: - containsActivePurchase diff --git a/Tests/UnitTests/LocalReceiptParsing/Builders/ASN1ContainerBuilderTests.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/ASN1ContainerBuilderTests.swift similarity index 96% rename from Tests/UnitTests/LocalReceiptParsing/Builders/ASN1ContainerBuilderTests.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/ASN1ContainerBuilderTests.swift index 69b07d7163..f7df387acf 100644 --- a/Tests/UnitTests/LocalReceiptParsing/Builders/ASN1ContainerBuilderTests.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/ASN1ContainerBuilderTests.swift @@ -1,16 +1,19 @@ import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser -class ASN1ContainerBuilderTests: TestCase { - var containerBuilder: ASN1ContainerBuilder! - let mockContainerPayload: [UInt8] = [0b01, 0b01, 0b01, 0b01, 0b01, 0b01, 0b01, 0b01, 0b01] - let lengthByteForIndefiniteLengthContainers = 0b10000000 +class ASN1ContainerBuilderTests: XCTestCase { + + private var containerBuilder: ASN1ContainerBuilder! + + private let mockContainerPayload: [UInt8] = [0b01, 0b01, 0b01, 0b01, 0b01, 0b01, 0b01, 0b01, 0b01] + private let lengthByteForIndefiniteLengthContainers = 0b10000000 override func setUp() { super.setUp() - containerBuilder = ASN1ContainerBuilder() + + self.containerBuilder = ASN1ContainerBuilder() } func testBuildFromContainerExtractsClassCorrectly() throws { diff --git a/Tests/UnitTests/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilderTests.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/ASN1ObjectIdentifierBuilderTests.swift similarity index 93% rename from Tests/UnitTests/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilderTests.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/ASN1ObjectIdentifierBuilderTests.swift index 2df5dd39d2..0ff787fdfa 100644 --- a/Tests/UnitTests/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilderTests.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/ASN1ObjectIdentifierBuilderTests.swift @@ -1,11 +1,12 @@ import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser -class ASN1ObjectIdentifierBuilderTests: TestCase { +class ASN1ObjectIdentifierBuilderTests: XCTestCase { + + private let encoder = ASN1ObjectIdentifierEncoder() - let encoder = ASN1ObjectIdentifierEncoder() func testBuildFromPayloadBuildsCorrectlyForDataPayload() { let payload = encoder.objectIdentifierPayload(.data) expect(try ASN1ObjectIdentifierBuilder.build(fromPayload: payload)) == .data diff --git a/Tests/UnitTests/LocalReceiptParsing/Builders/AppleReceiptBuilderTests.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/AppleReceiptBuilderTests.swift similarity index 99% rename from Tests/UnitTests/LocalReceiptParsing/Builders/AppleReceiptBuilderTests.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/AppleReceiptBuilderTests.swift index c09d5fc3c5..f0b56365a0 100644 --- a/Tests/UnitTests/LocalReceiptParsing/Builders/AppleReceiptBuilderTests.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/AppleReceiptBuilderTests.swift @@ -1,9 +1,9 @@ import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser -class AppleReceiptBuilderTests: TestCase { +class AppleReceiptBuilderTests: XCTestCase { let containerFactory = ContainerFactory() var appleReceiptBuilder: AppleReceiptBuilder! var mockInAppPurchaseBuilder: MockInAppPurchaseBuilder! diff --git a/Tests/UnitTests/LocalReceiptParsing/Builders/InAppPurchaseBuilderTests.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/InAppPurchaseBuilderTests.swift similarity index 99% rename from Tests/UnitTests/LocalReceiptParsing/Builders/InAppPurchaseBuilderTests.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/InAppPurchaseBuilderTests.swift index 56250e083b..21f78a80e5 100644 --- a/Tests/UnitTests/LocalReceiptParsing/Builders/InAppPurchaseBuilderTests.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/Builders/InAppPurchaseBuilderTests.swift @@ -7,9 +7,9 @@ import Foundation import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser -class InAppPurchaseBuilderTests: TestCase { +class InAppPurchaseBuilderTests: XCTestCase { // swiftlint:disable force_try let quantity = 2 diff --git a/Tests/UnitTests/LocalReceiptParsing/DataConverters/ArraySlice_UInt8+ExtensionsTests.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/DataConverters/ArraySlice_UInt8+ExtensionsTests.swift similarity index 84% rename from Tests/UnitTests/LocalReceiptParsing/DataConverters/ArraySlice_UInt8+ExtensionsTests.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/DataConverters/ArraySlice_UInt8+ExtensionsTests.swift index a90c539bb3..f1de735160 100644 --- a/Tests/UnitTests/LocalReceiptParsing/DataConverters/ArraySlice_UInt8+ExtensionsTests.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/DataConverters/ArraySlice_UInt8+ExtensionsTests.swift @@ -1,9 +1,10 @@ import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser + +class ArraySliceUInt8ExtensionsTests: XCTestCase { -class ArraySliceUInt8ExtensionsTests: TestCase { func testToUIntReturnsCorrectValue() { var arraySlice = ArraySlice([UInt8(0b10000000), UInt8(0b10000000)]) expect(arraySlice.toUInt64()) == 0b10000000_10000000 @@ -14,4 +15,5 @@ class ArraySliceUInt8ExtensionsTests: TestCase { arraySlice = ArraySlice([UInt8(0b10010100)]) expect(arraySlice.toUInt64()) == 0b10010100 } + } diff --git a/Tests/UnitTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/DataConverters/UInt8+ExtensionsTests.swift similarity index 96% rename from Tests/UnitTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/DataConverters/UInt8+ExtensionsTests.swift index b07dffd3aa..41985570a6 100644 --- a/Tests/UnitTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/DataConverters/UInt8+ExtensionsTests.swift @@ -1,9 +1,9 @@ import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser -class UInt8ExtensionsTests: TestCase { +class UInt8ExtensionsTests: XCTestCase { func testBitAtIndexGetsCorrectValue() { expect(try UInt8(0b10000000).bitAtIndex(0)) == 1 @@ -39,4 +39,5 @@ class UInt8ExtensionsTests: TestCase { .to(throwError(BitShiftError.rangeFlipped(from: 6, to: 1))) expect { _ = try UInt8(0b10000010).valueInRange(from: 6, to: 8)}.to(throwError(BitShiftError.invalidIndex(8))) } + } diff --git a/Tests/UnitTests/Mocks/MockASN1ContainerBuilder.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/Mocks/MockASN1ContainerBuilder.swift similarity index 96% rename from Tests/UnitTests/Mocks/MockASN1ContainerBuilder.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/Mocks/MockASN1ContainerBuilder.swift index c0314a2925..7bfd3a145c 100644 --- a/Tests/UnitTests/Mocks/MockASN1ContainerBuilder.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/Mocks/MockASN1ContainerBuilder.swift @@ -4,7 +4,8 @@ // import Foundation -@testable import RevenueCat + +@testable import ReceiptParser class MockASN1ContainerBuilder: ASN1ContainerBuilder { diff --git a/Tests/UnitTests/Mocks/MockAppleReceiptBuilder.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/Mocks/MockAppleReceiptBuilder.swift similarity index 96% rename from Tests/UnitTests/Mocks/MockAppleReceiptBuilder.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/Mocks/MockAppleReceiptBuilder.swift index 080673cbc2..ad70d36c42 100644 --- a/Tests/UnitTests/Mocks/MockAppleReceiptBuilder.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/Mocks/MockAppleReceiptBuilder.swift @@ -4,7 +4,8 @@ // import Foundation -@testable import RevenueCat + +@testable import ReceiptParser class MockAppleReceiptBuilder: AppleReceiptBuilder { diff --git a/Tests/UnitTests/Mocks/MockInAppPurchaseBuilder.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/Mocks/MockInAppPurchaseBuilder.swift similarity index 96% rename from Tests/UnitTests/Mocks/MockInAppPurchaseBuilder.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/Mocks/MockInAppPurchaseBuilder.swift index 3a13220e3f..66e48a8b8f 100644 --- a/Tests/UnitTests/Mocks/MockInAppPurchaseBuilder.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/Mocks/MockInAppPurchaseBuilder.swift @@ -4,7 +4,8 @@ // import Foundation -@testable import RevenueCat + +@testable import ReceiptParser class MockInAppPurchaseBuilder: InAppPurchaseBuilder { diff --git a/Tests/UnitTests/FoundationExtensions/NSData+RCExtensionsTests.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/NSData+RCExtensionsTests.swift similarity index 57% rename from Tests/UnitTests/FoundationExtensions/NSData+RCExtensionsTests.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/NSData+RCExtensionsTests.swift index 7171fdf957..350adc8ccf 100644 --- a/Tests/UnitTests/FoundationExtensions/NSData+RCExtensionsTests.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/NSData+RCExtensionsTests.swift @@ -7,9 +7,9 @@ import Foundation import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser -class NSDataExtensionsTests: TestCase { +class NSDataExtensionsTests: XCTestCase { func testAsString() { let data = Data([ @@ -42,20 +42,32 @@ class NSDataExtensionsTests: TestCase { extension NSDataExtensionsTests { static func sampleReceiptData(receiptName: String) -> Data { - let receiptText = readFile(named: receiptName) - guard let receiptData = Data(base64Encoded: receiptText) else { fatalError("couldn't decode file") } + let receiptText = self.readFile(named: receiptName) + guard let receiptData = Data(base64Encoded: receiptText) else { fatalError("Couldn't decode file '\(receiptName).\(Self.fileExtension)'") } return receiptData } - static func readFile(named filename: String) -> String { - guard let pathString = Bundle(for: Self.self).path(forResource: filename, ofType: "txt") else { - fatalError("\(filename) not found") - } + static func readFile(named filename: String, file: String = #file) -> String { + let path = URL(string: file)! + .deletingLastPathComponent() + .deletingLastPathComponent() + .appendingPathComponent("Resources", isDirectory: true) + .appendingPathComponent("receipts", isDirectory: true) + .appendingPathComponent(filename, isDirectory: false) + .appendingPathExtension(Self.fileExtension) + .absoluteString + do { - return try String(contentsOfFile: pathString, encoding: String.Encoding.utf8) + return try String(contentsOfFile: path, encoding: .utf8) } catch let error { - fatalError("couldn't read file named \(filename). Error: \(error.localizedDescription)") + fatalError( + "Couldn't read file named '\(filename).\(Self.fileExtension).\n" + + "Error: \(error.localizedDescription)\n" + + "URL: \(path)" + ) } } + private static let fileExtension = "txt" + } diff --git a/Tests/UnitTests/LocalReceiptParsing/ReceiptParserTests.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/ReceiptParserTests.swift similarity index 94% rename from Tests/UnitTests/LocalReceiptParsing/ReceiptParserTests.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/ReceiptParserTests.swift index 75ae6e89b4..6c51bd80e8 100644 --- a/Tests/UnitTests/LocalReceiptParsing/ReceiptParserTests.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/ReceiptParserTests.swift @@ -1,21 +1,23 @@ import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser -class ReceiptParserTests: TestCase { - var receiptParser: ReceiptParser! - var mockAppleReceiptBuilder: MockAppleReceiptBuilder! - var mockASN1ContainerBuilder: MockASN1ContainerBuilder! +class ReceiptParserTests: XCTestCase { + + private var receiptParser: Parser! + private var mockAppleReceiptBuilder: MockAppleReceiptBuilder! + private var mockASN1ContainerBuilder: MockASN1ContainerBuilder! private let containerFactory = ContainerFactory() override func setUp() { super.setUp() - mockAppleReceiptBuilder = MockAppleReceiptBuilder() - mockASN1ContainerBuilder = MockASN1ContainerBuilder() - receiptParser = ReceiptParser(containerBuilder: mockASN1ContainerBuilder, - receiptBuilder: mockAppleReceiptBuilder) + + self.mockAppleReceiptBuilder = MockAppleReceiptBuilder() + self.mockASN1ContainerBuilder = MockASN1ContainerBuilder() + self.receiptParser = Parser(containerBuilder: mockASN1ContainerBuilder, + receiptBuilder: mockAppleReceiptBuilder) } func testParseFromReceiptDataBuildsContainerAfterObjectIdentifier() throws { diff --git a/Tests/UnitTests/TestHelpers/ASN1ObjectIdentifierEncoder.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/TestHelpers/ASN1ObjectIdentifierEncoder.swift similarity index 98% rename from Tests/UnitTests/TestHelpers/ASN1ObjectIdentifierEncoder.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/TestHelpers/ASN1ObjectIdentifierEncoder.swift index 9299992a85..1140ff8c0b 100644 --- a/Tests/UnitTests/TestHelpers/ASN1ObjectIdentifierEncoder.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/TestHelpers/ASN1ObjectIdentifierEncoder.swift @@ -4,9 +4,11 @@ // import Foundation -@testable import RevenueCat + +@testable import ReceiptParser class ASN1ObjectIdentifierEncoder { + func objectIdentifierPayload(_ objectIdentifier: ASN1ObjectIdentifier) -> ArraySlice { return encodeASN1ObjectIdentifier(numbers: objectIdentifierNumbers(objectIdentifier)) } @@ -25,6 +27,7 @@ class ASN1ObjectIdentifierEncoder { return ArraySlice(encodedNumbers) } + } private extension ASN1ObjectIdentifierEncoder { diff --git a/Tests/UnitTests/TestHelpers/ContainerFactory.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/TestHelpers/ContainerFactory.swift similarity index 99% rename from Tests/UnitTests/TestHelpers/ContainerFactory.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/TestHelpers/ContainerFactory.swift index b22b85d4bf..4619cf74c7 100644 --- a/Tests/UnitTests/TestHelpers/ContainerFactory.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/TestHelpers/ContainerFactory.swift @@ -4,9 +4,11 @@ // import Foundation -@testable import RevenueCat + +@testable import ReceiptParser class ContainerFactory { + private let objectIdentifierEncoder = ASN1ObjectIdentifierEncoder() func simpleDataContainer() -> ASN1Container { diff --git a/Tests/UnitTests/LocalReceiptParsing/TestsAgainstRealReceipts/ReceiptParsing+TestsWithRealReceipts.swift b/Packages/ReceiptParser/Tests/ReceiptParserTests/TestsAgainstRealReceipts/ReceiptParsing+TestsWithRealReceipts.swift similarity index 96% rename from Tests/UnitTests/LocalReceiptParsing/TestsAgainstRealReceipts/ReceiptParsing+TestsWithRealReceipts.swift rename to Packages/ReceiptParser/Tests/ReceiptParserTests/TestsAgainstRealReceipts/ReceiptParsing+TestsWithRealReceipts.swift index 6c23ec5ccf..fada950158 100644 --- a/Tests/UnitTests/LocalReceiptParsing/TestsAgainstRealReceipts/ReceiptParsing+TestsWithRealReceipts.swift +++ b/Packages/ReceiptParser/Tests/ReceiptParserTests/TestsAgainstRealReceipts/ReceiptParsing+TestsWithRealReceipts.swift @@ -10,15 +10,15 @@ import Foundation import Nimble import XCTest -@testable import RevenueCat +@testable import ReceiptParser -class ReceiptParsingRealReceiptTests: TestCase { +class ReceiptParsingRealReceiptTests: XCTestCase { - let receipt1Name = "base64encodedreceiptsample1" + private let receipt1Name = "base64encodedreceiptsample1" func testBasicReceiptAttributesForSample1() throws { - let receiptData = sampleReceiptData(receiptName: receipt1Name) - let receipt = try ReceiptParser.default.parse(from: receiptData) + let receiptData = self.sampleReceiptData(receiptName: receipt1Name) + let receipt = try Parser.default.parse(from: receiptData) expect(receipt.applicationVersion) == "4" expect(receipt.bundleId) == "com.revenuecat.sampleapp" @@ -27,9 +27,10 @@ class ReceiptParsingRealReceiptTests: TestCase { expect(receipt.expirationDate).to(beNil()) } + // swiftlint:disable:next function_body_length func testInAppPurchasesAttributesForSample1() throws { let receiptData = sampleReceiptData(receiptName: receipt1Name) - let receipt = try ReceiptParser.default.parse(from: receiptData) + let receipt = try Parser.default.parse(from: receiptData) let inAppPurchases = receipt.inAppPurchases expect(inAppPurchases.count) == 9 diff --git a/Tests/UnitTests/Resources/receipts/base64EncodedReceiptSampleForDataExtension.txt b/Packages/ReceiptParser/Tests/Resources/receipts/base64EncodedReceiptSampleForDataExtension.txt similarity index 100% rename from Tests/UnitTests/Resources/receipts/base64EncodedReceiptSampleForDataExtension.txt rename to Packages/ReceiptParser/Tests/Resources/receipts/base64EncodedReceiptSampleForDataExtension.txt diff --git a/Tests/UnitTests/Resources/receipts/base64encoded_sandboxReceipt.txt b/Packages/ReceiptParser/Tests/Resources/receipts/base64encoded_sandboxReceipt.txt similarity index 100% rename from Tests/UnitTests/Resources/receipts/base64encoded_sandboxReceipt.txt rename to Packages/ReceiptParser/Tests/Resources/receipts/base64encoded_sandboxReceipt.txt diff --git a/Tests/UnitTests/Resources/receipts/base64encodedreceiptsample1.txt b/Packages/ReceiptParser/Tests/Resources/receipts/base64encodedreceiptsample1.txt similarity index 100% rename from Tests/UnitTests/Resources/receipts/base64encodedreceiptsample1.txt rename to Packages/ReceiptParser/Tests/Resources/receipts/base64encodedreceiptsample1.txt diff --git a/Tests/UnitTests/Resources/receipts/verifyReceiptSample1.txt b/Packages/ReceiptParser/Tests/Resources/receipts/verifyReceiptSample1.txt similarity index 100% rename from Tests/UnitTests/Resources/receipts/verifyReceiptSample1.txt rename to Packages/ReceiptParser/Tests/Resources/receipts/verifyReceiptSample1.txt diff --git a/RevenueCat.podspec b/RevenueCat.podspec index 8d1065ef7b..257cc279f2 100644 --- a/RevenueCat.podspec +++ b/RevenueCat.podspec @@ -25,5 +25,8 @@ Pod::Spec.new do |s| s.source_files = 'Sources/**/*.swift' - + # TODO: this won't lint when making a release because + # this version won't exist. Should we remove the version? + s.dependency 'ReceiptParser', "#{s.version.to_s}" + end diff --git a/RevenueCat.xcodeproj/project.pbxproj b/RevenueCat.xcodeproj/project.pbxproj index dd37bdd5af..ca8c978f00 100644 --- a/RevenueCat.xcodeproj/project.pbxproj +++ b/RevenueCat.xcodeproj/project.pbxproj @@ -29,10 +29,6 @@ 2D3BFAD226DEA46600370B11 /* MockProductsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35B08709090FBBFB16EBD /* MockProductsRequest.swift */; }; 2D3BFAD326DEA47100370B11 /* MockSKProductDiscount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41E724F6F61B005BC22D /* MockSKProductDiscount.swift */; }; 2D3BFAD426DEA49200370B11 /* SKProductSubscriptionDurationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41E924F6F844005BC22D /* SKProductSubscriptionDurationExtensions.swift */; }; - 2D4D6AF424F717B800B656BE /* ASN1ObjectIdentifierEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35C4A4B241A545D1D06BD /* ASN1ObjectIdentifierEncoder.swift */; }; - 2D4D6AF524F717B800B656BE /* ContainerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35092F0E41512E0D610BA /* ContainerFactory.swift */; }; - 2D4D6AF624F7193700B656BE /* verifyReceiptSample1.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2DDE559A24C8B5E300DCB087 /* verifyReceiptSample1.txt */; }; - 2D4D6AF724F7193700B656BE /* base64encodedreceiptsample1.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2DDE559B24C8B5E300DCB087 /* base64encodedreceiptsample1.txt */; }; 2D4E926526990AB1000E10B0 /* StoreKit1Wrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D4E926426990AB1000E10B0 /* StoreKit1Wrapper.swift */; }; 2D735F7E26EFF198004E82A7 /* UnitTestsConfiguration.storekit in Resources */ = {isa = PBXBuildFile; fileRef = 2D43017726EBFD7100BAB891 /* UnitTestsConfiguration.storekit */; }; 2D803F6326F144830069D717 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = 2D803F6226F144830069D717 /* Nimble */; }; @@ -54,8 +50,6 @@ 2D90F8C226FD20F7009B9142 /* MockETagManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35D83311262FBD4200E60AC5 /* MockETagManager.swift */; }; 2D90F8C326FD214F009B9142 /* MockAttributionTypeFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 351B514426D449E600BD2BD7 /* MockAttributionTypeFactory.swift */; }; 2D90F8C526FD216A009B9142 /* MockSKProductDiscount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41E724F6F61B005BC22D /* MockSKProductDiscount.swift */; }; - 2D90F8C726FD221D009B9142 /* MockASN1ContainerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E351EB3689AF304E5B1031 /* MockASN1ContainerBuilder.swift */; }; - 2D90F8C826FD2225009B9142 /* MockAppleReceiptBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35C1554F296F7F1317747 /* MockAppleReceiptBuilder.swift */; }; 2D90F8CA26FD257A009B9142 /* MockStoreKit2TransactionListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D90F8C926FD257A009B9142 /* MockStoreKit2TransactionListener.swift */; }; 2D90F8CC26FD2BA1009B9142 /* StoreKitConfigTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D90F8CB26FD2BA1009B9142 /* StoreKitConfigTestCase.swift */; }; 2D971CC12744364C0093F35F /* SKError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D971CC02744364C0093F35F /* SKError+Extensions.swift */; }; @@ -78,35 +72,11 @@ 2DD58DD827F240EB000FDFE3 /* EmptyFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DD58DD727F240EB000FDFE3 /* EmptyFile.swift */; }; 2DD9F4BE274EADC20031AE2C /* Purchases+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DD9F4BD274EADC20031AE2C /* Purchases+async.swift */; }; 2DDF419624F6F331005BC22D /* ProductsRequestFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35E8DCF998D9DB63850F8 /* ProductsRequestFactory.swift */; }; - 2DDF419724F6F331005BC22D /* DateExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E3567189CF6A746EE3CCC2 /* DateExtensions.swift */; }; 2DDF419D24F6F331005BC22D /* IntroEligibilityCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D97458E24BDFCEF006245E9 /* IntroEligibilityCalculator.swift */; }; - 2DDF419F24F6F331005BC22D /* ReceiptParsingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D8F622224D30F9D00F993AA /* ReceiptParsingError.swift */; }; 2DDF41A224F6F331005BC22D /* ProductsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35C7060D7E486F5958BED /* ProductsManager.swift */; }; - 2DDF41A324F6F331005BC22D /* ReceiptParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5BB46A24C8E8ED00E27537 /* ReceiptParser.swift */; }; - 2DDF41AB24F6F37C005BC22D /* AppleReceipt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41A724F6F37C005BC22D /* AppleReceipt.swift */; }; - 2DDF41AC24F6F37C005BC22D /* ASN1Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41A824F6F37C005BC22D /* ASN1Container.swift */; }; - 2DDF41AD24F6F37C005BC22D /* ASN1ObjectIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41A924F6F37C005BC22D /* ASN1ObjectIdentifier.swift */; }; - 2DDF41AE24F6F37C005BC22D /* InAppPurchase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41AA24F6F37C005BC22D /* InAppPurchase.swift */; }; - 2DDF41B324F6F387005BC22D /* InAppPurchaseBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41AF24F6F387005BC22D /* InAppPurchaseBuilder.swift */; }; - 2DDF41B424F6F387005BC22D /* ASN1ContainerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41B024F6F387005BC22D /* ASN1ContainerBuilder.swift */; }; - 2DDF41B524F6F387005BC22D /* AppleReceiptBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41B124F6F387005BC22D /* AppleReceiptBuilder.swift */; }; - 2DDF41B624F6F387005BC22D /* ASN1ObjectIdentifierBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41B224F6F387005BC22D /* ASN1ObjectIdentifierBuilder.swift */; }; - 2DDF41BB24F6F392005BC22D /* UInt8+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41B824F6F392005BC22D /* UInt8+Extensions.swift */; }; - 2DDF41BC24F6F392005BC22D /* ArraySlice_UInt8+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41B924F6F392005BC22D /* ArraySlice_UInt8+Extensions.swift */; }; - 2DDF41C924F6F4C3005BC22D /* UInt8+ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41BF24F6F4C3005BC22D /* UInt8+ExtensionsTests.swift */; }; - 2DDF41CA24F6F4C3005BC22D /* ArraySlice_UInt8+ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41C024F6F4C3005BC22D /* ArraySlice_UInt8+ExtensionsTests.swift */; }; - 2DDF41CB24F6F4C3005BC22D /* ASN1ObjectIdentifierBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41C224F6F4C3005BC22D /* ASN1ObjectIdentifierBuilderTests.swift */; }; - 2DDF41CC24F6F4C3005BC22D /* AppleReceiptBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41C324F6F4C3005BC22D /* AppleReceiptBuilderTests.swift */; }; - 2DDF41CD24F6F4C3005BC22D /* ASN1ContainerBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41C424F6F4C3005BC22D /* ASN1ContainerBuilderTests.swift */; }; - 2DDF41CE24F6F4C3005BC22D /* InAppPurchaseBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41C524F6F4C3005BC22D /* InAppPurchaseBuilderTests.swift */; }; - 2DDF41CF24F6F4C3005BC22D /* ReceiptParsing+TestsWithRealReceipts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41C724F6F4C3005BC22D /* ReceiptParsing+TestsWithRealReceipts.swift */; }; - 2DDF41DA24F6F4DB005BC22D /* ReceiptParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E351D0EBC4698E1D3585A6 /* ReceiptParserTests.swift */; }; - 2DDF41DE24F6F527005BC22D /* MockAppleReceiptBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35C1554F296F7F1317747 /* MockAppleReceiptBuilder.swift */; }; 2DDF41DF24F6F527005BC22D /* MockProductsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35C9439E087F63ECC4F59 /* MockProductsManager.swift */; }; - 2DDF41E024F6F527005BC22D /* MockInAppPurchaseBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E355744D64075AA91342DE /* MockInAppPurchaseBuilder.swift */; }; 2DDF41E124F6F527005BC22D /* MockReceiptParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E354B13440508B46C9A530 /* MockReceiptParser.swift */; }; 2DDF41E224F6F527005BC22D /* MockProductsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35B08709090FBBFB16EBD /* MockProductsRequest.swift */; }; - 2DDF41E324F6F527005BC22D /* MockASN1ContainerBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E351EB3689AF304E5B1031 /* MockASN1ContainerBuilder.swift */; }; 2DDF41E624F6F5DC005BC22D /* MockSK1Product.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41E524F6F5DC005BC22D /* MockSK1Product.swift */; }; 2DDF41E824F6F61B005BC22D /* MockSKProductDiscount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41E724F6F61B005BC22D /* MockSKProductDiscount.swift */; }; 2DDF41EA24F6F844005BC22D /* SKProductSubscriptionDurationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DDF41E924F6F844005BC22D /* SKProductSubscriptionDurationExtensions.swift */; }; @@ -228,7 +198,6 @@ 573A10D92800ADCD00F976E5 /* StoreKitErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 573A10D82800ADCD00F976E5 /* StoreKitErrorTests.swift */; }; 573A10DB2800AF4700F976E5 /* PurchaseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 573A10DA2800AF4700F976E5 /* PurchaseErrorTests.swift */; }; 573E7F092819B989007C9128 /* StoreKitWorkarounds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 573E7F082819B989007C9128 /* StoreKitWorkarounds.swift */; }; - 5744D8AB28E3B86600646735 /* AppleReceiptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5744D8AA28E3B86600646735 /* AppleReceiptTests.swift */; }; 5746508C27586B2E0053AB09 /* Result+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5746508B27586B2E0053AB09 /* Result+Extensions.swift */; }; 5746508E275949F20053AB09 /* DispatchTimeInterval+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5746508D275949F20053AB09 /* DispatchTimeInterval+Extensions.swift */; }; 574A2EE7282C3F0800150D40 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 574A2EE6282C3F0800150D40 /* AnyDecodable.swift */; }; @@ -254,6 +223,7 @@ 575A8EE32922C5E100936709 /* AsyncTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 575A8EE02922C56300936709 /* AsyncTestHelpers.swift */; }; 575A8EE52922C9F300936709 /* MockStoreKit2TransactionListenerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 575A8EE42922C9F300936709 /* MockStoreKit2TransactionListenerDelegate.swift */; }; 575A8EE62922C9F300936709 /* MockStoreKit2TransactionListenerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 575A8EE42922C9F300936709 /* MockStoreKit2TransactionListenerDelegate.swift */; }; + 575FAC1229258A74005F5B01 /* ReceiptParser in Frameworks */ = {isa = PBXBuildFile; productRef = 575FAC1129258A74005F5B01 /* ReceiptParser */; }; 5766AA3E283C750300FA6091 /* Operators+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5766AA3D283C750300FA6091 /* Operators+Extensions.swift */; }; 5766AA42283C768600FA6091 /* OperatorExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5766AA41283C768600FA6091 /* OperatorExtensionsTests.swift */; }; 5766AA56283D4C5400FA6091 /* IgnoreHashable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5766AA55283D4C5400FA6091 /* IgnoreHashable.swift */; }; @@ -286,7 +256,6 @@ 579189EB28F47F0F00BF4963 /* MockPurchases.swift in Sources */ = {isa = PBXBuildFile; fileRef = 579189EA28F47F0F00BF4963 /* MockPurchases.swift */; }; 579189FD28F4966500BF4963 /* OtherIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 579189FC28F4966500BF4963 /* OtherIntegrationTests.swift */; }; 5791A1C82767FC9400C972AA /* ManageSubscriptionsHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5791A1C72767FC9400C972AA /* ManageSubscriptionsHelperTests.swift */; }; - 5791CE80273F26A000E50C4B /* base64encoded_sandboxReceipt.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5791CE7F273F26A000E50C4B /* base64encoded_sandboxReceipt.txt */; }; 579234E327F7788900B39C68 /* BaseBackendIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 579234E127F777EE00B39C68 /* BaseBackendIntegrationTests.swift */; }; 579234E527F779FE00B39C68 /* SubscriberAttributesManagerIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 579234E427F779FE00B39C68 /* SubscriberAttributesManagerIntegrationTests.swift */; }; 5793397028E77A5100C1232C /* PaymentQuueWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5793396F28E77A5100C1232C /* PaymentQuueWrapperTests.swift */; }; @@ -399,8 +368,6 @@ B302206E2728B798008F1A0D /* BackendErrorStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B302206D2728B798008F1A0D /* BackendErrorStrings.swift */; }; B3022072272B3DDC008F1A0D /* DescribableError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3022071272B3DDC008F1A0D /* DescribableError.swift */; }; B3083A132699334C007B5503 /* Offering.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3083A122699334C007B5503 /* Offering.swift */; }; - B319514926C19856002CA9AC /* NSData+RCExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35ABEE9FD79CCA64E4F8B /* NSData+RCExtensionsTests.swift */; }; - B319514B26C1991E002CA9AC /* base64EncodedReceiptSampleForDataExtension.txt in Resources */ = {isa = PBXBuildFile; fileRef = B319514A26C1991E002CA9AC /* base64EncodedReceiptSampleForDataExtension.txt */; }; B31C8BEC285BD58F001017B7 /* MockIdentityAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B31C8BEB285BD58F001017B7 /* MockIdentityAPI.swift */; }; B31C8BEF285BDD76001017B7 /* MockIdentityAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B31C8BEB285BD58F001017B7 /* MockIdentityAPI.swift */; }; B325543C2825C81800DA62EA /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B325543B2825C81800DA62EA /* Configuration.swift */; }; @@ -573,12 +540,10 @@ 2D34D9D127481D9B00C05DB6 /* TrialOrIntroPriceEligibilityCheckerSK2Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrialOrIntroPriceEligibilityCheckerSK2Tests.swift; sourceTree = ""; }; 2D43017726EBFD7100BAB891 /* UnitTestsConfiguration.storekit */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = UnitTestsConfiguration.storekit; sourceTree = ""; }; 2D4E926426990AB1000E10B0 /* StoreKit1Wrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreKit1Wrapper.swift; sourceTree = ""; }; - 2D5BB46A24C8E8ED00E27537 /* ReceiptParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptParser.swift; sourceTree = ""; }; 2D69384426DFF93300FCDBC0 /* StoreProductTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreProductTests.swift; sourceTree = ""; }; 2D84458826B9CD270033B5A3 /* ReceiptFetcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptFetcherTests.swift; sourceTree = ""; }; 2D8D03B42799A2B90044C2ED /* DocCDocumentation.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = DocCDocumentation.docc; sourceTree = ""; }; 2D8DB34A24072AAE00BE3D31 /* SubscriberAttributeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriberAttributeTests.swift; sourceTree = ""; }; - 2D8F622224D30F9D00F993AA /* ReceiptParsingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptParsingError.swift; sourceTree = ""; }; 2D8FC8AB26E01AE70049A85C /* PurchasesOrchestratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchasesOrchestratorTests.swift; sourceTree = ""; }; 2D90F8C926FD257A009B9142 /* MockStoreKit2TransactionListener.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockStoreKit2TransactionListener.swift; sourceTree = ""; }; 2D90F8CB26FD2BA1009B9142 /* StoreKitConfigTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreKitConfigTestCase.swift; sourceTree = ""; }; @@ -599,25 +564,6 @@ 2DD58DD727F240EB000FDFE3 /* EmptyFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyFile.swift; sourceTree = ""; }; 2DD9F4BD274EADC20031AE2C /* Purchases+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Purchases+async.swift"; sourceTree = ""; }; 2DDA3E4624DB0B5400EDFE5B /* OperationDispatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationDispatcher.swift; sourceTree = ""; }; - 2DDE559A24C8B5E300DCB087 /* verifyReceiptSample1.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = verifyReceiptSample1.txt; sourceTree = ""; }; - 2DDE559B24C8B5E300DCB087 /* base64encodedreceiptsample1.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = base64encodedreceiptsample1.txt; sourceTree = ""; }; - 2DDF41A724F6F37C005BC22D /* AppleReceipt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleReceipt.swift; sourceTree = ""; }; - 2DDF41A824F6F37C005BC22D /* ASN1Container.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1Container.swift; sourceTree = ""; }; - 2DDF41A924F6F37C005BC22D /* ASN1ObjectIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1ObjectIdentifier.swift; sourceTree = ""; }; - 2DDF41AA24F6F37C005BC22D /* InAppPurchase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppPurchase.swift; sourceTree = ""; }; - 2DDF41AF24F6F387005BC22D /* InAppPurchaseBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppPurchaseBuilder.swift; sourceTree = ""; }; - 2DDF41B024F6F387005BC22D /* ASN1ContainerBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1ContainerBuilder.swift; sourceTree = ""; }; - 2DDF41B124F6F387005BC22D /* AppleReceiptBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleReceiptBuilder.swift; sourceTree = ""; }; - 2DDF41B224F6F387005BC22D /* ASN1ObjectIdentifierBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1ObjectIdentifierBuilder.swift; sourceTree = ""; }; - 2DDF41B824F6F392005BC22D /* UInt8+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UInt8+Extensions.swift"; sourceTree = ""; }; - 2DDF41B924F6F392005BC22D /* ArraySlice_UInt8+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ArraySlice_UInt8+Extensions.swift"; sourceTree = ""; }; - 2DDF41BF24F6F4C3005BC22D /* UInt8+ExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UInt8+ExtensionsTests.swift"; sourceTree = ""; }; - 2DDF41C024F6F4C3005BC22D /* ArraySlice_UInt8+ExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ArraySlice_UInt8+ExtensionsTests.swift"; sourceTree = ""; }; - 2DDF41C224F6F4C3005BC22D /* ASN1ObjectIdentifierBuilderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1ObjectIdentifierBuilderTests.swift; sourceTree = ""; }; - 2DDF41C324F6F4C3005BC22D /* AppleReceiptBuilderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppleReceiptBuilderTests.swift; sourceTree = ""; }; - 2DDF41C424F6F4C3005BC22D /* ASN1ContainerBuilderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1ContainerBuilderTests.swift; sourceTree = ""; }; - 2DDF41C524F6F4C3005BC22D /* InAppPurchaseBuilderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppPurchaseBuilderTests.swift; sourceTree = ""; }; - 2DDF41C724F6F4C3005BC22D /* ReceiptParsing+TestsWithRealReceipts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ReceiptParsing+TestsWithRealReceipts.swift"; sourceTree = ""; }; 2DDF41E524F6F5DC005BC22D /* MockSK1Product.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockSK1Product.swift; sourceTree = ""; }; 2DDF41E724F6F61B005BC22D /* MockSKProductDiscount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockSKProductDiscount.swift; sourceTree = ""; }; 2DDF41E924F6F844005BC22D /* SKProductSubscriptionDurationExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SKProductSubscriptionDurationExtensions.swift; sourceTree = ""; }; @@ -638,7 +584,6 @@ 2DEAC2E026EFE46E006914ED /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 2DEAC2E526EFE470006914ED /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 2DEAC2EA26EFE470006914ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 2DEC0CFB24A2A1B100B0E5BB /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = SOURCE_ROOT; }; 33FFC8744F2BAE7BD8889A4C /* Pods_RevenueCat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RevenueCat.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 350A1B84226E3E8700CCA10F /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 351B513C26D4491E00BD2BD7 /* MockDeviceCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDeviceCache.swift; sourceTree = ""; }; @@ -690,10 +635,7 @@ 37E3507939634ED5A9280544 /* Strings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; 37E3508E52201122137D4B4A /* PurchasesSubscriberAttributesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PurchasesSubscriberAttributesTests.swift; sourceTree = ""; }; 37E3508EC20EEBAB4EAC4C82 /* NSDate+RCExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSDate+RCExtensionsTests.swift"; sourceTree = ""; }; - 37E35092F0E41512E0D610BA /* ContainerFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainerFactory.swift; sourceTree = ""; }; 37E350E57B0A393455A72B40 /* ProductRequestDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductRequestDataTests.swift; sourceTree = ""; }; - 37E351D0EBC4698E1D3585A6 /* ReceiptParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiptParserTests.swift; sourceTree = ""; }; - 37E351EB3689AF304E5B1031 /* MockASN1ContainerBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockASN1ContainerBuilder.swift; sourceTree = ""; }; 37E351F0E21361EAEC078A0D /* ProductsFetcherSK1Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductsFetcherSK1Tests.swift; sourceTree = ""; }; 37E3521731D8DC16873F55F3 /* AttributionFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributionFetcher.swift; sourceTree = ""; }; 37E35294EBC1E5A879C95540 /* IdentityManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityManagerTests.swift; sourceTree = ""; }; @@ -704,19 +646,14 @@ 37E3548189DA008320B3FC98 /* ProductRequestDataInitializationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductRequestDataInitializationTests.swift; sourceTree = ""; }; 37E354B13440508B46C9A530 /* MockReceiptParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockReceiptParser.swift; sourceTree = ""; }; 37E354B18710B488B8B0D443 /* IntroEligibilityCalculatorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntroEligibilityCalculatorTests.swift; sourceTree = ""; }; - 37E355744D64075AA91342DE /* MockInAppPurchaseBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockInAppPurchaseBuilder.swift; sourceTree = ""; }; - 37E3567189CF6A746EE3CCC2 /* DateExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateExtensions.swift; sourceTree = ""; }; 37E3567E972B9B04FE079ABA /* SubscriberAttributesManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriberAttributesManagerTests.swift; sourceTree = ""; }; 37E357C2D977BBB081216B5F /* OfferingsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OfferingsTests.swift; sourceTree = ""; }; 37E357D16038F07915D7825D /* MockUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockUserDefaults.swift; sourceTree = ""; }; 37E3582920E16E065502E5FC /* EntitlementInfosTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntitlementInfosTests.swift; sourceTree = ""; }; 37E3583675928C01D92E3166 /* ProductRequestDataExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductRequestDataExtensions.swift; sourceTree = ""; }; 37E359D8F304C83184560135 /* CustomerInfoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomerInfoTests.swift; sourceTree = ""; }; - 37E35ABEE9FD79CCA64E4F8B /* NSData+RCExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSData+RCExtensionsTests.swift"; sourceTree = ""; }; 37E35B08709090FBBFB16EBD /* MockProductsRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockProductsRequest.swift; sourceTree = ""; }; 37E35B9AC7A350CA2437049D /* ISOPeriodFormatterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ISOPeriodFormatterTests.swift; sourceTree = ""; }; - 37E35C1554F296F7F1317747 /* MockAppleReceiptBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockAppleReceiptBuilder.swift; sourceTree = ""; }; - 37E35C4A4B241A545D1D06BD /* ASN1ObjectIdentifierEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1ObjectIdentifierEncoder.swift; sourceTree = ""; }; 37E35C4A795A0F056381A1B3 /* DeviceCacheSubscriberAttributesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceCacheSubscriberAttributesTests.swift; sourceTree = ""; }; 37E35C7060D7E486F5958BED /* ProductsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductsManager.swift; sourceTree = ""; }; 37E35C9439E087F63ECC4F59 /* MockProductsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockProductsManager.swift; sourceTree = ""; }; @@ -741,12 +678,14 @@ 570896B727596E8800296F1C /* SwiftAPITester.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftAPITester.xcodeproj; path = Tests/APITesters/SwiftAPITester/SwiftAPITester.xcodeproj; sourceTree = ""; }; 570896BD27596E8800296F1C /* ObjCAPITester.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ObjCAPITester.xcodeproj; path = Tests/APITesters/ObjCAPITester/ObjCAPITester.xcodeproj; sourceTree = ""; }; 570FAF4A2864EC2300D3C769 /* NonSubscriptionTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonSubscriptionTransaction.swift; sourceTree = ""; }; + 57121E0B29258A1F004DF525 /* ReceiptParser */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = ReceiptParser; sourceTree = ""; }; 571E7AD3279F2D0C003B3606 /* StoreKitTestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreKitTestHelpers.swift; sourceTree = ""; }; 5721360E28B4602C006C46BE /* Purchases+nonasync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Purchases+nonasync.swift"; sourceTree = ""; }; 572247D027BEC28E00C524A7 /* Array+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extensions.swift"; sourceTree = ""; }; 572247F627BF1ADF00C524A7 /* ArrayExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayExtensionsTests.swift; sourceTree = ""; }; 5722482627C2BD3200C524A7 /* LockTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockTests.swift; sourceTree = ""; }; 5723FBBD28EDE1360003BA16 /* InternalAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalAPI.swift; sourceTree = ""; }; + 5725F54C292574BF00A2A9B5 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 5733B18D27FF586A00EC2045 /* BackendError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackendError.swift; sourceTree = ""; }; 5733B1A327FF9F8300EC2045 /* NetworkErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkErrorTests.swift; sourceTree = ""; }; 5733B1A727FFBCC800EC2045 /* BackendErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackendErrorTests.swift; sourceTree = ""; }; @@ -758,7 +697,6 @@ 573A10D82800ADCD00F976E5 /* StoreKitErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreKitErrorTests.swift; sourceTree = ""; }; 573A10DA2800AF4700F976E5 /* PurchaseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseErrorTests.swift; sourceTree = ""; }; 573E7F082819B989007C9128 /* StoreKitWorkarounds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreKitWorkarounds.swift; sourceTree = ""; }; - 5744D8AA28E3B86600646735 /* AppleReceiptTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleReceiptTests.swift; sourceTree = ""; }; 5746508B27586B2E0053AB09 /* Result+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Result+Extensions.swift"; sourceTree = ""; }; 5746508D275949F20053AB09 /* DispatchTimeInterval+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DispatchTimeInterval+Extensions.swift"; sourceTree = ""; }; 574A2EE6282C3F0800150D40 /* AnyDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = ""; }; @@ -809,7 +747,6 @@ 579189EA28F47F0F00BF4963 /* MockPurchases.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPurchases.swift; sourceTree = ""; }; 579189FC28F4966500BF4963 /* OtherIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherIntegrationTests.swift; sourceTree = ""; }; 5791A1C72767FC9400C972AA /* ManageSubscriptionsHelperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManageSubscriptionsHelperTests.swift; sourceTree = ""; }; - 5791CE7F273F26A000E50C4B /* base64encoded_sandboxReceipt.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = base64encoded_sandboxReceipt.txt; sourceTree = ""; }; 579234E127F777EE00B39C68 /* BaseBackendIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseBackendIntegrationTests.swift; sourceTree = ""; }; 579234E427F779FE00B39C68 /* SubscriberAttributesManagerIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriberAttributesManagerIntegrationTests.swift; sourceTree = ""; }; 5793396F28E77A5100C1232C /* PaymentQuueWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentQuueWrapperTests.swift; sourceTree = ""; }; @@ -910,7 +847,6 @@ B302206D2728B798008F1A0D /* BackendErrorStrings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackendErrorStrings.swift; sourceTree = ""; }; B3022071272B3DDC008F1A0D /* DescribableError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DescribableError.swift; sourceTree = ""; }; B3083A122699334C007B5503 /* Offering.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Offering.swift; sourceTree = ""; }; - B319514A26C1991E002CA9AC /* base64EncodedReceiptSampleForDataExtension.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = base64EncodedReceiptSampleForDataExtension.txt; sourceTree = ""; }; B31C8BEB285BD58F001017B7 /* MockIdentityAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockIdentityAPI.swift; sourceTree = ""; }; B325543B2825C81800DA62EA /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; B32B750026868C1D005647BF /* EntitlementInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntitlementInfo.swift; sourceTree = ""; }; @@ -1018,6 +954,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 575FAC1229258A74005F5B01 /* ReceiptParser in Frameworks */, A5B6CDD8280F3843007629D5 /* AdServices.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1154,18 +1091,6 @@ path = Strings; sourceTree = ""; }; - 2D1A28CB24AA6F4B006BE931 /* LocalReceiptParsing */ = { - isa = PBXGroup; - children = ( - 37E35FCF87558ACB498521F1 /* BasicTypes */, - 37E355596456B3DFA01EF081 /* Builders */, - 37E35556F2D7B8B28B169C77 /* DataConverters */, - 2D5BB46A24C8E8ED00E27537 /* ReceiptParser.swift */, - 2D8F622224D30F9D00F993AA /* ReceiptParsingError.swift */, - ); - path = LocalReceiptParsing; - sourceTree = ""; - }; 2D1DB44A26EA61AB00DDE736 /* StoreKit1 */ = { isa = PBXGroup; children = ( @@ -1230,7 +1155,6 @@ B324DC482720C15300103EE9 /* Error Handling */, 2CD72940268A820E00BFC976 /* FoundationExtensions */, B3A36AAC26BC76230059EDEA /* Identity */, - 2D1A28CB24AA6F4B006BE931 /* LocalReceiptParsing */, 2D11F5DE250FF63E005A70E8 /* Logging */, 2DDA3E4524DB0B4500EDFE5B /* Misc */, 35D832CB262A5B3400E60AC5 /* Networking */, @@ -1250,12 +1174,10 @@ 37E35AE0CDC4C2AA8260FB58 /* Caching */, 35F82BBB26A9BFA60051DF03 /* FoundationExtensions */, 37E35BCB85973ABD4CEC5904 /* Identity */, - 2DD02D5924AD128A00419CD9 /* LocalReceiptParsing */, 35272E1A26D0023400F22C3B /* Misc */, 2DDF41DD24F6F4F9005BC22D /* Mocks */, 35D832FE262FAD6900E60AC5 /* Networking */, 354235D624C11160008C84EE /* Purchasing */, - 2DDE559824C8B5D100DCB087 /* Resources */, F591492426B994A100D32E58 /* StoreKitExtensions */, B36824BB268FBB9B00957E4C /* SubscriberAttributes */, 37E35A5970D1604E8C8011FC /* TestHelpers */, @@ -1264,18 +1186,6 @@ path = UnitTests; sourceTree = ""; }; - 2DD02D5924AD128A00419CD9 /* LocalReceiptParsing */ = { - isa = PBXGroup; - children = ( - 2DDF41C124F6F4C3005BC22D /* Builders */, - 2DDF41BD24F6F4C3005BC22D /* DataConverters */, - 2DDF41C624F6F4C3005BC22D /* TestsAgainstRealReceipts */, - 37E351D0EBC4698E1D3585A6 /* ReceiptParserTests.swift */, - 5744D8AA28E3B86600646735 /* AppleReceiptTests.swift */, - ); - path = LocalReceiptParsing; - sourceTree = ""; - }; 2DD58DD627F240E0000FDFE3 /* DocCDocumentation */ = { isa = PBXGroup; children = ( @@ -1292,7 +1202,6 @@ 576C8A8A27CFCB150058FA6E /* AnyEncodable.swift */, 57A0FBEF2749C0C2009E2FC3 /* Atomic.swift */, 352B7D7827BD919B002A47DD /* DangerousSettings.swift */, - 37E3567189CF6A746EE3CCC2 /* DateExtensions.swift */, 0313FD40268A506400168386 /* DateProvider.swift */, 5796A3A827D7C43500653165 /* Deprecations.swift */, 2D22BF6426F3CB31001AE2F9 /* FatalErrorUtil.swift */, @@ -1316,25 +1225,6 @@ path = Misc; sourceTree = ""; }; - 2DDE559824C8B5D100DCB087 /* Resources */ = { - isa = PBXGroup; - children = ( - 2DDE559924C8B5E300DCB087 /* receipts */, - ); - path = Resources; - sourceTree = ""; - }; - 2DDE559924C8B5E300DCB087 /* receipts */ = { - isa = PBXGroup; - children = ( - 2DDE559A24C8B5E300DCB087 /* verifyReceiptSample1.txt */, - 2DDE559B24C8B5E300DCB087 /* base64encodedreceiptsample1.txt */, - 5791CE7F273F26A000E50C4B /* base64encoded_sandboxReceipt.txt */, - B319514A26C1991E002CA9AC /* base64EncodedReceiptSampleForDataExtension.txt */, - ); - path = receipts; - sourceTree = ""; - }; 2DDE870027E5238500D8B390 /* Tests */ = { isa = PBXGroup; children = ( @@ -1349,39 +1239,9 @@ path = Tests; sourceTree = ""; }; - 2DDF41BD24F6F4C3005BC22D /* DataConverters */ = { - isa = PBXGroup; - children = ( - 2DDF41BF24F6F4C3005BC22D /* UInt8+ExtensionsTests.swift */, - 2DDF41C024F6F4C3005BC22D /* ArraySlice_UInt8+ExtensionsTests.swift */, - ); - path = DataConverters; - sourceTree = ""; - }; - 2DDF41C124F6F4C3005BC22D /* Builders */ = { - isa = PBXGroup; - children = ( - 2DDF41C224F6F4C3005BC22D /* ASN1ObjectIdentifierBuilderTests.swift */, - 2DDF41C324F6F4C3005BC22D /* AppleReceiptBuilderTests.swift */, - 2DDF41C424F6F4C3005BC22D /* ASN1ContainerBuilderTests.swift */, - 2DDF41C524F6F4C3005BC22D /* InAppPurchaseBuilderTests.swift */, - ); - path = Builders; - sourceTree = ""; - }; - 2DDF41C624F6F4C3005BC22D /* TestsAgainstRealReceipts */ = { - isa = PBXGroup; - children = ( - 2DDF41C724F6F4C3005BC22D /* ReceiptParsing+TestsWithRealReceipts.swift */, - ); - path = TestsAgainstRealReceipts; - sourceTree = ""; - }; 2DDF41DD24F6F4F9005BC22D /* Mocks */ = { isa = PBXGroup; children = ( - 37E35C1554F296F7F1317747 /* MockAppleReceiptBuilder.swift */, - 37E351EB3689AF304E5B1031 /* MockASN1ContainerBuilder.swift */, 57544C24285FA8E6004E54D5 /* MockAttributeSyncing.swift */, 351B515F26D44BB600BD2BD7 /* MockAttributionDataMigrator.swift */, 351B515926D44B6200BD2BD7 /* MockAttributionFetcher.swift */, @@ -1398,7 +1258,6 @@ 351B514C26D44A8600BD2BD7 /* MockHTTPClient.swift */, B31C8BEB285BD58F001017B7 /* MockIdentityAPI.swift */, 351B513E26D4496000BD2BD7 /* MockIdentityManager.swift */, - 37E355744D64075AA91342DE /* MockInAppPurchaseBuilder.swift */, 351B517126D44EF300BD2BD7 /* MockInMemoryCachedOfferings.swift */, 351B515B26D44B7900BD2BD7 /* MockIntroEligibilityCalculator.swift */, 35E840CD2710E2EB00899AE2 /* MockManageSubscriptionsHelper.swift */, @@ -1488,10 +1347,11 @@ isa = PBXGroup; children = ( 2DC5621724EC63420031F69B /* Sources */, + 571779C3292579BD0049B08A /* Packages */, 2DDE870027E5238500D8B390 /* Tests */, 352629FF1F7C4B9100C04F2C /* Products */, 3530C18722653E8F00D6DF52 /* Frameworks */, - 2DEC0CFB24A2A1B100B0E5BB /* Package.swift */, + 5725F54C292574BF00A2A9B5 /* Package.swift */, 57B530E52858F3FD00FA4E37 /* SwiftStyleGuide.swift */, ); sourceTree = ""; @@ -1679,7 +1539,6 @@ 37E35FDA0A44EA03EA12DAA2 /* DateFormatter+ExtensionsTests.swift */, 57ACB13628184CF1000DCC9F /* DecoderExtensionTests.swift */, 2DD269162522A20A006AC4BC /* DictionaryExtensionsTests.swift */, - 37E35ABEE9FD79CCA64E4F8B /* NSData+RCExtensionsTests.swift */, 37E3508EC20EEBAB4EAC4C82 /* NSDate+RCExtensionsTests.swift */, 37E353AF2CAD3CEDE6D9B368 /* NSError+RCExtensionsTests.swift */, 5766AA41283C768600FA6091 /* OperatorExtensionsTests.swift */, @@ -1690,31 +1549,9 @@ path = FoundationExtensions; sourceTree = ""; }; - 37E35556F2D7B8B28B169C77 /* DataConverters */ = { - isa = PBXGroup; - children = ( - 2DDF41B924F6F392005BC22D /* ArraySlice_UInt8+Extensions.swift */, - 2DDF41B824F6F392005BC22D /* UInt8+Extensions.swift */, - ); - path = DataConverters; - sourceTree = ""; - }; - 37E355596456B3DFA01EF081 /* Builders */ = { - isa = PBXGroup; - children = ( - 2DDF41B124F6F387005BC22D /* AppleReceiptBuilder.swift */, - 2DDF41B024F6F387005BC22D /* ASN1ContainerBuilder.swift */, - 2DDF41B224F6F387005BC22D /* ASN1ObjectIdentifierBuilder.swift */, - 2DDF41AF24F6F387005BC22D /* InAppPurchaseBuilder.swift */, - ); - path = Builders; - sourceTree = ""; - }; 37E35A5970D1604E8C8011FC /* TestHelpers */ = { isa = PBXGroup; children = ( - 37E35C4A4B241A545D1D06BD /* ASN1ObjectIdentifierEncoder.swift */, - 37E35092F0E41512E0D610BA /* ContainerFactory.swift */, 575A17AA2773A59300AA6F22 /* CurrentTestCaseTracker.swift */, 576C8A9127D27DDD0058FA6E /* SnapshotTesting+Extensions.swift */, 57DE80AD28075D77008D6C6F /* OSVersionEquivalent.swift */, @@ -1744,17 +1581,6 @@ path = Identity; sourceTree = ""; }; - 37E35FCF87558ACB498521F1 /* BasicTypes */ = { - isa = PBXGroup; - children = ( - 2DDF41A724F6F37C005BC22D /* AppleReceipt.swift */, - 2DDF41A824F6F37C005BC22D /* ASN1Container.swift */, - 2DDF41A924F6F37C005BC22D /* ASN1ObjectIdentifier.swift */, - 2DDF41AA24F6F37C005BC22D /* InAppPurchase.swift */, - ); - path = BasicTypes; - sourceTree = ""; - }; 570896B627596E6E00296F1C /* APITesters */ = { isa = PBXGroup; children = ( @@ -1765,6 +1591,14 @@ path = ..; sourceTree = ""; }; + 571779C3292579BD0049B08A /* Packages */ = { + isa = PBXGroup; + children = ( + 57121E0B29258A1F004DF525 /* ReceiptParser */, + ); + path = Packages; + sourceTree = ""; + }; 571E7AD0279F2CE9003B3606 /* TestHelpers */ = { isa = PBXGroup; children = ( @@ -2067,6 +1901,7 @@ ); name = RevenueCat; packageProductDependencies = ( + 575FAC1129258A74005F5B01 /* ReceiptParser */, ); productName = Purchases; productReference = 2DC5621624EC63420031F69B /* RevenueCat.framework */; @@ -2265,11 +2100,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2D4D6AF624F7193700B656BE /* verifyReceiptSample1.txt in Resources */, - 2D4D6AF724F7193700B656BE /* base64encodedreceiptsample1.txt in Resources */, 5774F9BE2805E71100997128 /* Fixtures in Resources */, - 5791CE80273F26A000E50C4B /* base64encoded_sandboxReceipt.txt in Resources */, - B319514B26C1991E002CA9AC /* base64EncodedReceiptSampleForDataExtension.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2345,7 +2176,6 @@ F5E5E2EE28479BD000216ECD /* ProductsFetcherSK2Tests.swift in Sources */, 3543913626F90D6A00E669DF /* TrialOrIntroPriceEligibilityCheckerSK1Tests.swift in Sources */, 2D34D9D227481D9B00C05DB6 /* TrialOrIntroPriceEligibilityCheckerSK2Tests.swift in Sources */, - 2D90F8C726FD221D009B9142 /* MockASN1ContainerBuilder.swift in Sources */, F535515F286B5BE5009CA47A /* MockOfferingsManager.swift in Sources */, F52CFAFC28290AE500E8ABC5 /* StoreKit2StorefrontListenerTests.swift in Sources */, 57ACB12528174B9F000DCC9F /* CustomerInfo+TestExtensions.swift in Sources */, @@ -2374,7 +2204,6 @@ 576C8ABC27D2997C0058FA6E /* SnapshotTesting+Extensions.swift in Sources */, F5355164286B7125009CA47A /* MockOfferingsFactory.swift in Sources */, 57CFB96D27FE0E79002A6730 /* MockCurrentUserProvider.swift in Sources */, - 2D90F8C826FD2225009B9142 /* MockAppleReceiptBuilder.swift in Sources */, 57C381B72791E593009E3940 /* StoreKit2TransactionListenerTests.swift in Sources */, 2D90F8C026FD20DF009B9142 /* MockAttributionDataMigrator.swift in Sources */, F55FFA5D27634E1900995146 /* MockTransactionsManager.swift in Sources */, @@ -2422,7 +2251,6 @@ 5723FBBE28EDE1360003BA16 /* InternalAPI.swift in Sources */, A55D5D66282ECCC100FA7623 /* PostAdServicesTokenOperation.swift in Sources */, B3B5FBB4269CED4B00104A0C /* BackendErrorCode.swift in Sources */, - 2DDF41B624F6F387005BC22D /* ASN1ObjectIdentifierBuilder.swift in Sources */, 35D832D2262E56DB00E60AC5 /* HTTPStatusCode.swift in Sources */, 572247D127BEC28E00C524A7 /* Array+Extensions.swift in Sources */, 57D5412E27F6311C004CC35C /* OfferingsResponse.swift in Sources */, @@ -2435,7 +2263,6 @@ F5C0196926E880800005D61E /* StoreKitStrings.swift in Sources */, 2D4E926526990AB1000E10B0 /* StoreKit1Wrapper.swift in Sources */, 2DDF419624F6F331005BC22D /* ProductsRequestFactory.swift in Sources */, - 2DDF419724F6F331005BC22D /* DateExtensions.swift in Sources */, 9A65E0A52591A23500DE00B0 /* PurchaseStrings.swift in Sources */, 57EAE52B274332830060EB74 /* Obsoletions.swift in Sources */, 2C0B98CD2797070B00C5874F /* PromotionalOffer.swift in Sources */, @@ -2461,7 +2288,6 @@ 5746508E275949F20053AB09 /* DispatchTimeInterval+Extensions.swift in Sources */, 2D294E5C26DECFD500B8FE4F /* StoreKit2TransactionListener.swift in Sources */, 57AC4C182770F55C00DDE30F /* SK2StoreProduct.swift in Sources */, - 2DDF41B524F6F387005BC22D /* AppleReceiptBuilder.swift in Sources */, 2D00A41D2767C08300FC3DD8 /* ManageSubscriptionsStrings.swift in Sources */, 2DD9F4BE274EADC20031AE2C /* Purchases+async.swift in Sources */, B3C4AAD526B8911300E1B3C8 /* Backend.swift in Sources */, @@ -2471,18 +2297,15 @@ B378156D285A9772000A7B93 /* OfferingsAPI.swift in Sources */, B34605C0279A6E380031CA74 /* CustomerInfoCallback.swift in Sources */, B33CEAA0268CDCC9008A3144 /* ISOPeriodFormatter.swift in Sources */, - 2DDF41A324F6F331005BC22D /* ReceiptParser.swift in Sources */, 2CB8CF9327BF538F00C34DE3 /* PlatformInfo.swift in Sources */, 35D832F4262E606500E60AC5 /* HTTPResponse.swift in Sources */, 352B7D7927BD919B002A47DD /* DangerousSettings.swift in Sources */, A56F9AB126990E9200AFC48F /* CustomerInfo.swift in Sources */, - 2DDF41AE24F6F37C005BC22D /* InAppPurchase.swift in Sources */, B32B750126868C1D005647BF /* EntitlementInfo.swift in Sources */, 57ABA76D28F08DDA003D9181 /* Either.swift in Sources */, 35F82BB426A9A74D0051DF03 /* HTTPClient.swift in Sources */, B3A55B7D26C452A7007EFC56 /* AttributionPoster.swift in Sources */, 2DC19195255F36D10039389A /* Logger.swift in Sources */, - 2DDF419F24F6F331005BC22D /* ReceiptParsingError.swift in Sources */, 57BB070E28D27A2B007F5DF0 /* CachingProductsManager.swift in Sources */, 2DDF419D24F6F331005BC22D /* IntroEligibilityCalculator.swift in Sources */, 57536A2627851FFE00E2AE7F /* SK1StoreTransaction.swift in Sources */, @@ -2504,11 +2327,9 @@ B3DDB55926854865008CCF23 /* PurchaseOwnershipType.swift in Sources */, 57A0FBF02749C0C2009E2FC3 /* Atomic.swift in Sources */, 2DC5623224EC63730031F69B /* TransactionsFactory.swift in Sources */, - 2DDF41B424F6F387005BC22D /* ASN1ContainerBuilder.swift in Sources */, B35F9E0926B4BEED00095C3F /* String+Extensions.swift in Sources */, 574A2EE7282C3F0800150D40 /* AnyDecodable.swift in Sources */, B34605CF279A6E380031CA74 /* GetOfferingsOperation.swift in Sources */, - 2DDF41AC24F6F37C005BC22D /* ASN1Container.swift in Sources */, 9A65E07B2591977500DE00B0 /* NetworkStrings.swift in Sources */, F530E4FF275646EF001AF6BD /* MacDevice.swift in Sources */, F5714EAC26D7A87B00635477 /* PurchaseOwnershipType+Extensions.swift in Sources */, @@ -2517,11 +2338,8 @@ F5714EAA26D7A85D00635477 /* PeriodType+Extensions.swift in Sources */, F5BE447D269E4ADB00254A30 /* ASIdManagerProxy.swift in Sources */, 80E80EF226970E04008F245A /* ReceiptFetcher.swift in Sources */, - 2DDF41AB24F6F37C005BC22D /* AppleReceipt.swift in Sources */, - 2DDF41BB24F6F392005BC22D /* UInt8+Extensions.swift in Sources */, B3B5FBC1269E17CE00104A0C /* DeviceCache.swift in Sources */, F5BE424226965F9F00254A30 /* ProductRequestData+Initialization.swift in Sources */, - 2DDF41AD24F6F37C005BC22D /* ASN1ObjectIdentifier.swift in Sources */, 35549323269E298B005F9AE9 /* OfferingsFactory.swift in Sources */, 57536A28278522B400E2AE7F /* SK2StoreTransaction.swift in Sources */, 2D9C7BB326D838FC006838BE /* UIApplication+RCExtensions.swift in Sources */, @@ -2532,7 +2350,6 @@ A55D08302722368600D919E0 /* SK2BeginRefundRequestHelper.swift in Sources */, 35D832CD262A5B7500E60AC5 /* ETagManager.swift in Sources */, A56DFDF0286643BF00EF2E32 /* PostAttributionDataOperation.swift in Sources */, - 2DDF41BC24F6F392005BC22D /* ArraySlice_UInt8+Extensions.swift in Sources */, 574A2F4B282D7AEA00150D40 /* PostOfferResponse.swift in Sources */, F575858D26C088FE00C12B97 /* OfferingsManager.swift in Sources */, B34605CB279A6E380031CA74 /* PostReceiptDataOperation.swift in Sources */, @@ -2553,7 +2370,6 @@ 2D971CC12744364C0093F35F /* SKError+Extensions.swift in Sources */, 57EAE527274324C60060EB74 /* Lock.swift in Sources */, B32B74FF26868AEB005647BF /* Package.swift in Sources */, - 2DDF41B324F6F387005BC22D /* InAppPurchaseBuilder.swift in Sources */, 57D5414227F656D9004CC35C /* NetworkError.swift in Sources */, B3781568285A79FC000A7B93 /* IdentityAPI.swift in Sources */, B325543C2825C81800DA62EA /* Configuration.swift in Sources */, @@ -2611,7 +2427,6 @@ 579189B728F4747700BF4963 /* EitherTests.swift in Sources */, 57069A5E28E398E100B86355 /* AsyncExtensionsTests.swift in Sources */, 35272E2226D0048D00F22C3B /* HTTPClientTests.swift in Sources */, - 2DDF41CB24F6F4C3005BC22D /* ASN1ObjectIdentifierBuilderTests.swift in Sources */, 5766AA5A283D4CAB00FA6091 /* IgnoreHashableTests.swift in Sources */, B36824BF268FBC8700957E4C /* SubscriberAttributeTests.swift in Sources */, 351B51BC26D450E800BD2BD7 /* OfferingsTests.swift in Sources */, @@ -2621,19 +2436,15 @@ 57554C84282AC273009A7E58 /* PeriodTypeTests.swift in Sources */, 57057FF828B0048900995F21 /* TestLogHandler.swift in Sources */, 57E415F12846997B00EA5460 /* PurchasesAttributionDataTests.swift in Sources */, - 2DDF41CF24F6F4C3005BC22D /* ReceiptParsing+TestsWithRealReceipts.swift in Sources */, 57FDAA962846BDE2009A48F1 /* PurchasesTransactionHandlingTests.swift in Sources */, 575A17AB2773A59300AA6F22 /* CurrentTestCaseTracker.swift in Sources */, 351B514326D449C100BD2BD7 /* MockSubscriberAttributesManager.swift in Sources */, B300E4C026D4371200B22262 /* SKPaymentTransactionExtensionsTests.swift in Sources */, - 2DDF41C924F6F4C3005BC22D /* UInt8+ExtensionsTests.swift in Sources */, - 2D4D6AF524F717B800B656BE /* ContainerFactory.swift in Sources */, 57E415FF28469EAB00EA5460 /* PurchasesGetProductsTests.swift in Sources */, 351B514726D44A0D00BD2BD7 /* MockSystemInfo.swift in Sources */, B300E4C226D439B700B22262 /* IntroEligibilityCalculatorTests.swift in Sources */, 57554C62282ABFD9009A7E58 /* StoreTests.swift in Sources */, 5733D00928CFA7A4008638D8 /* MockPaymentQueueWrapper.swift in Sources */, - 2DDF41CA24F6F4C3005BC22D /* ArraySlice_UInt8+ExtensionsTests.swift in Sources */, 2DDF41E124F6F527005BC22D /* MockReceiptParser.swift in Sources */, 57E415EB2846962500EA5460 /* PurchasesSyncPurchasesTests.swift in Sources */, 5766AAC5283E843300FA6091 /* PurchasesConfiguringTests.swift in Sources */, @@ -2642,7 +2453,6 @@ 578FB10E27ADDA8000F70709 /* AvailabilityChecks.swift in Sources */, 57E415EF284697A300EA5460 /* PurchasesDeferredPurchasesTests.swift in Sources */, 35F82BB226A98EC50051DF03 /* AttributionDataMigratorTests.swift in Sources */, - 5744D8AB28E3B86600646735 /* AppleReceiptTests.swift in Sources */, B3CAFF10285CE8E30048A994 /* MockOfferingsAPI.swift in Sources */, 351B51BF26D450E800BD2BD7 /* StoreKitRequestFetcherTests.swift in Sources */, 2DDF41E224F6F527005BC22D /* MockProductsRequest.swift in Sources */, @@ -2662,9 +2472,7 @@ B380D69B27726AB500984578 /* DNSCheckerTests.swift in Sources */, 5774F9C12805EA3000997128 /* BaseHTTPResponseTest.swift in Sources */, 351B51B526D450E800BD2BD7 /* ProductsFetcherSK1Tests.swift in Sources */, - 2DDF41CC24F6F4C3005BC22D /* AppleReceiptBuilderTests.swift in Sources */, 575A8EE52922C9F300936709 /* MockStoreKit2TransactionListenerDelegate.swift in Sources */, - 2DDF41CD24F6F4C3005BC22D /* ASN1ContainerBuilderTests.swift in Sources */, 573A10D52800A7C800F976E5 /* SKErrorTests.swift in Sources */, B31C8BEC285BD58F001017B7 /* MockIdentityAPI.swift in Sources */, 351B513D26D4491E00BD2BD7 /* MockDeviceCache.swift in Sources */, @@ -2697,11 +2505,8 @@ 5766AA42283C768600FA6091 /* OperatorExtensionsTests.swift in Sources */, 351B516A26D44CB300BD2BD7 /* ISOPeriodFormatterTests.swift in Sources */, 57DC9F4A27CD37BA00DA6AF9 /* HTTPStatusCodeTests.swift in Sources */, - 2DDF41DE24F6F527005BC22D /* MockAppleReceiptBuilder.swift in Sources */, - 2DDF41E324F6F527005BC22D /* MockASN1ContainerBuilder.swift in Sources */, 576C8AD927D2BCB90058FA6E /* HTTPRequestTests.swift in Sources */, 5766AAE5283E9E9C00FA6091 /* PurchasesGetOfferingsTests.swift in Sources */, - 2DDF41DA24F6F4DB005BC22D /* ReceiptParserTests.swift in Sources */, 2D1015E2275A67E40086173F /* SubscriptionPeriodTests.swift in Sources */, 579189EB28F47F0F00BF4963 /* MockPurchases.swift in Sources */, 574A2EE9282C403800150D40 /* AnyDecodableTests.swift in Sources */, @@ -2740,7 +2545,6 @@ B390F5BA271DDC7400B64D65 /* PurchasesDeprecation.swift in Sources */, 57FDAABE28493A29009A48F1 /* SandboxEnvironmentDetectorTests.swift in Sources */, 57BA943128330ACA00CD5FC5 /* ConfigurationTests.swift in Sources */, - 2D4D6AF424F717B800B656BE /* ASN1ObjectIdentifierEncoder.swift in Sources */, 5774F9C22805EA6900997128 /* CustomerInfoDecodingTests.swift in Sources */, F5BE444726985E7B00254A30 /* AttributionTypeFactoryTests.swift in Sources */, 2DDF41EA24F6F844005BC22D /* SKProductSubscriptionDurationExtensions.swift in Sources */, @@ -2748,11 +2552,9 @@ 351B514E26D44ACE00BD2BD7 /* SubscriberAttributesManagerTests.swift in Sources */, 57BB071628D282A4007F5DF0 /* CachingProductsManagerTests.swift in Sources */, 574A2F4F282D7B9E00150D40 /* PostOfferDecodingTests.swift in Sources */, - 2DDF41CE24F6F4C3005BC22D /* InAppPurchaseBuilderTests.swift in Sources */, 573A10DB2800AF4700F976E5 /* PurchaseErrorTests.swift in Sources */, B300E4BF26D436F900B22262 /* LogIntent.swift in Sources */, 351B513F26D4496000BD2BD7 /* MockIdentityManager.swift in Sources */, - B319514926C19856002CA9AC /* NSData+RCExtensionsTests.swift in Sources */, 5733B1A427FF9F8300EC2045 /* NetworkErrorTests.swift in Sources */, 351B517026D44E8D00BD2BD7 /* MockDateProvider.swift in Sources */, 2D1C3F3926B9D8B800112626 /* MockBundle.swift in Sources */, @@ -2777,7 +2579,6 @@ 5793397028E77A5100C1232C /* PaymentQuueWrapperTests.swift in Sources */, 57FDAA9A2846C2BD009A48F1 /* PurchasesDelegateTests.swift in Sources */, 351B516026D44BB600BD2BD7 /* MockAttributionDataMigrator.swift in Sources */, - 2DDF41E024F6F527005BC22D /* MockInAppPurchaseBuilder.swift in Sources */, 37E352973B0901E3CAA717E1 /* DateFormatter+ExtensionsTests.swift in Sources */, B3F8418F26F3A93400E560FB /* ErrorCodeTests.swift in Sources */, 5793397228E77A6E00C1232C /* MockPaymentQueue.swift in Sources */, @@ -3463,6 +3264,10 @@ package = 2D9C5ECB26F2815E0057FC45 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; productName = OHHTTPStubsSwift; }; + 575FAC1129258A74005F5B01 /* ReceiptParser */ = { + isa = XCSwiftPackageProductDependency; + productName = ReceiptParser; + }; 576C8ABD27D299860058FA6E /* SnapshotTesting */ = { isa = XCSwiftPackageProductDependency; package = 57E04739277260DE0082FE91 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */; diff --git a/Sources/FoundationExtensions/Data+Extensions.swift b/Sources/FoundationExtensions/Data+Extensions.swift index 5833068e68..f11372cd52 100644 --- a/Sources/FoundationExtensions/Data+Extensions.swift +++ b/Sources/FoundationExtensions/Data+Extensions.swift @@ -17,20 +17,6 @@ import Foundation extension NSData { - func asString() -> String { - // 2 characters per byte - let deviceTokenString = NSMutableString(capacity: self.length * 2) - - self.enumerateBytes { bytes, byteRange, _ in - for index in stride(from: 0, to: byteRange.length, by: 1) { - let byte = bytes.load(fromByteOffset: index, as: UInt8.self) - deviceTokenString.appendFormat("%02x", byte) - } - } - - return deviceTokenString as String - } - var uuid: UUID? { let bytes = [UInt8](self) return NSUUID(uuidBytes: bytes) as UUID @@ -40,15 +26,6 @@ extension NSData { extension Data { - var asString: String { - return (self as NSData).asString() - } - - // Returns a string representing a fetch token. - var asFetchToken: String { - return self.base64EncodedString() - } - var uuid: UUID? { (self as NSData).uuid } diff --git a/Sources/Logging/Strings/ReceiptStrings.swift b/Sources/Logging/Strings/ReceiptStrings.swift index 3c3910c4f0..1627f7be16 100644 --- a/Sources/Logging/Strings/ReceiptStrings.swift +++ b/Sources/Logging/Strings/ReceiptStrings.swift @@ -14,6 +14,8 @@ import Foundation +import ReceiptParser + // swiftlint:disable identifier_name enum ReceiptStrings { diff --git a/Sources/Networking/Operations/PostReceiptDataOperation.swift b/Sources/Networking/Operations/PostReceiptDataOperation.swift index 5026fa2413..a188838c2b 100644 --- a/Sources/Networking/Operations/PostReceiptDataOperation.swift +++ b/Sources/Networking/Operations/PostReceiptDataOperation.swift @@ -13,6 +13,8 @@ import Foundation +import ReceiptParser + class PostReceiptDataOperation: CacheableNetworkOperation { struct PostData { @@ -82,7 +84,7 @@ private extension PostReceiptDataOperation { func printReceiptData() { do { - let receipt = try ReceiptParser.default.parse(from: self.postData.receiptData) + let receipt = try ReceiptParser.Parser.default.parse(from: self.postData.receiptData) self.log(Strings.receipt.posting_receipt(receipt)) for purchase in receipt.inAppPurchases where purchase.purchaseDateEqualsExpiration { diff --git a/Sources/Purchasing/IntroEligibilityCalculator.swift b/Sources/Purchasing/IntroEligibilityCalculator.swift index 868461cc5f..d3c6378245 100644 --- a/Sources/Purchasing/IntroEligibilityCalculator.swift +++ b/Sources/Purchasing/IntroEligibilityCalculator.swift @@ -15,13 +15,15 @@ import Foundation import StoreKit +import ReceiptParser + class IntroEligibilityCalculator { private let productsManager: ProductsManagerType - private let receiptParser: ReceiptParser + private let receiptParser: ReceiptParser.ParserType init(productsManager: ProductsManagerType, - receiptParser: ReceiptParser) { + receiptParser: ReceiptParser.ParserType) { self.productsManager = productsManager self.receiptParser = receiptParser } diff --git a/Sources/Purchasing/Purchases/Purchases.swift b/Sources/Purchasing/Purchases/Purchases.swift index 0e5fcce041..b65fadf74b 100644 --- a/Sources/Purchasing/Purchases/Purchases.swift +++ b/Sources/Purchasing/Purchases/Purchases.swift @@ -20,6 +20,8 @@ import Foundation import StoreKit +import ReceiptParser + // MARK: Block definitions /** @@ -274,7 +276,7 @@ public typealias StartPurchaseBlock = (@escaping PurchaseCompletedBlock) -> Void let offeringsFactory = OfferingsFactory() let userDefaults = userDefaults ?? UserDefaults.standard let deviceCache = DeviceCache(sandboxEnvironmentDetector: systemInfo, userDefaults: userDefaults) - let receiptParser = ReceiptParser.default + let receiptParser = ReceiptParser.Parser.default let transactionsManager = TransactionsManager(receiptParser: receiptParser) let customerInfoManager = CustomerInfoManager(operationDispatcher: operationDispatcher, deviceCache: deviceCache, @@ -1099,7 +1101,7 @@ internal extension Purchases { func fetchReceipt(_ policy: ReceiptRefreshPolicy) async throws -> AppleReceipt? { let receipt = await self.receiptFetcher.receiptData(refreshPolicy: policy) - return try receipt.map { try ReceiptParser.default.parse(from: $0) } + return try receipt.map { try ReceiptParser.Parser.default.parse(from: $0) } } #endif diff --git a/Sources/Purchasing/Purchases/PurchasesOrchestrator.swift b/Sources/Purchasing/Purchases/PurchasesOrchestrator.swift index 7301db02e9..92a55c3118 100644 --- a/Sources/Purchasing/Purchases/PurchasesOrchestrator.swift +++ b/Sources/Purchasing/Purchases/PurchasesOrchestrator.swift @@ -14,6 +14,9 @@ import Foundation import StoreKit +// @_implementationOnly +import ReceiptParser + @objc protocol PurchasesOrchestratorDelegate { func readyForPromotedProduct(_ product: StoreProduct, @@ -30,6 +33,10 @@ import StoreKit // swiftlint:disable file_length type_body_length final class PurchasesOrchestrator { + var receiptName: String { + return AppleReceipt.InAppPurchase.ProductType.consumable.rawValue.description + } + var finishTransactions: Bool { self.systemInfo.finishTransactions } var allowSharingAppStoreAccount: Bool { get { self._allowSharingAppStoreAccount.value ?? self.currentUserProvider.currentUserIsAnonymous } diff --git a/Sources/Purchasing/ReceiptFetcher.swift b/Sources/Purchasing/ReceiptFetcher.swift index cf79d308d8..561b0d2433 100644 --- a/Sources/Purchasing/ReceiptFetcher.swift +++ b/Sources/Purchasing/ReceiptFetcher.swift @@ -14,10 +14,12 @@ import Foundation +import ReceiptParser + class ReceiptFetcher { private let requestFetcher: StoreKitRequestFetcher - private let receiptParser: ReceiptParser + private let receiptParser: ReceiptParser.ParserType private let fileReader: FileReader let systemInfo: SystemInfo @@ -25,7 +27,7 @@ class ReceiptFetcher { init( requestFetcher: StoreKitRequestFetcher, systemInfo: SystemInfo, - receiptParser: ReceiptParser = .default, + receiptParser: ReceiptParser.ParserType = ReceiptParser.Parser.default, fileReader: FileReader = DefaultFileReader() ) { self.requestFetcher = requestFetcher diff --git a/Sources/Purchasing/TransactionsManager.swift b/Sources/Purchasing/TransactionsManager.swift index 6bc38c864e..6043ff5cde 100644 --- a/Sources/Purchasing/TransactionsManager.swift +++ b/Sources/Purchasing/TransactionsManager.swift @@ -13,11 +13,13 @@ import StoreKit +import ReceiptParser + class TransactionsManager { - private let receiptParser: ReceiptParser + private let receiptParser: ReceiptParser.ParserType - init(receiptParser: ReceiptParser) { + init(receiptParser: ReceiptParser.ParserType) { self.receiptParser = receiptParser } diff --git a/Tests/StoreKitUnitTests/LocalReceiptParserStoreKitTests.swift b/Tests/StoreKitUnitTests/LocalReceiptParserStoreKitTests.swift index d820533cd2..eb16e85ad0 100644 --- a/Tests/StoreKitUnitTests/LocalReceiptParserStoreKitTests.swift +++ b/Tests/StoreKitUnitTests/LocalReceiptParserStoreKitTests.swift @@ -13,7 +13,10 @@ import Foundation import Nimble + +@testable import ReceiptParser @testable import RevenueCat + import StoreKit import XCTest @@ -25,7 +28,7 @@ class LocalReceiptParserStoreKitTests: StoreKitConfigTestCase { private var requestFetcher: StoreKitRequestFetcher! private var systemInfo: SystemInfo! private var receiptFetcher: ReceiptFetcher! - private var parser: ReceiptParser! + private var parser: ParserType! override func setUpWithError() throws { try super.setUpWithError() @@ -37,7 +40,7 @@ class LocalReceiptParserStoreKitTests: StoreKitConfigTestCase { operationDispatcher: operationDispatcher, storeKit2Setting: .disabled) self.receiptFetcher = ReceiptFetcher(requestFetcher: self.requestFetcher, systemInfo: systemInfo) - self.parser = .default + self.parser = Parser.default } @MainActor diff --git a/Tests/TestPlans/AllTests.xctestplan b/Tests/TestPlans/AllTests.xctestplan index 50d55d75dd..3423a420a7 100644 --- a/Tests/TestPlans/AllTests.xctestplan +++ b/Tests/TestPlans/AllTests.xctestplan @@ -24,7 +24,7 @@ "target" : { "containerPath" : "container:RevenueCat.xcodeproj", "identifier" : "2DC5621D24EC63430031F69B", - "name" : "RevenueCatTests" + "name" : "UnitTests" } }, { @@ -33,6 +33,14 @@ "identifier" : "2DAC5F7126F13C9800C5258F", "name" : "StoreKitUnitTests" } + }, + { + "parallelizable" : true, + "target" : { + "containerPath" : "container:Packages\/ReceiptParser", + "identifier" : "ReceiptParserTests", + "name" : "ReceiptParserTests" + } } ], "version" : 1 diff --git a/Tests/TestPlans/CI-AllTests.xctestplan b/Tests/TestPlans/CI-AllTests.xctestplan index 9c8434ac8b..8a8168e9d6 100644 --- a/Tests/TestPlans/CI-AllTests.xctestplan +++ b/Tests/TestPlans/CI-AllTests.xctestplan @@ -34,6 +34,13 @@ "identifier" : "2DAC5F7126F13C9800C5258F", "name" : "StoreKitUnitTests" } + }, + { + "target" : { + "containerPath" : "container:Packages\/ReceiptParser", + "identifier" : "ReceiptParserTests", + "name" : "ReceiptParserTests" + } } ], "version" : 1 diff --git a/Tests/TestingApps/PurchaseTesterSwiftUI/PurchaseTester.xcodeproj/project.pbxproj b/Tests/TestingApps/PurchaseTesterSwiftUI/PurchaseTester.xcodeproj/project.pbxproj index af3f7add6a..a7b7878573 100644 --- a/Tests/TestingApps/PurchaseTesterSwiftUI/PurchaseTester.xcodeproj/project.pbxproj +++ b/Tests/TestingApps/PurchaseTesterSwiftUI/PurchaseTester.xcodeproj/project.pbxproj @@ -22,10 +22,10 @@ 2CD2C518278C9B02005D1CC2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2C4EF278C9B01005D1CC2 /* ContentView.swift */; }; 2CD2C51A278C9B02005D1CC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2C4F0278C9B02005D1CC2 /* Assets.xcassets */; }; 2CF428692863EEAC007E6A78 /* Package+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CF428682863EEAC007E6A78 /* Package+Extensions.swift */; }; + 5725F5502925753300A2A9B5 /* RevenueCat in Frameworks */ = {isa = PBXBuildFile; productRef = 5725F54F2925753300A2A9B5 /* RevenueCat */; }; 575642A2290C78DD00719219 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 575642A1290C78DD00719219 /* Logger.swift */; }; 575642A4290C7A2700719219 /* LoggerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 575642A3290C7A2700719219 /* LoggerView.swift */; }; 575642A6290C7D3100719219 /* Windows.swift in Sources */ = {isa = PBXBuildFile; fileRef = 575642A5290C7D3100719219 /* Windows.swift */; }; - 57C217AD29159B83005236DB /* RevenueCat in Frameworks */ = {isa = PBXBuildFile; productRef = 57C217AC29159B83005236DB /* RevenueCat */; }; 57E9CF09290B0E0600EE12D1 /* AppIcon.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 57E9CF08290B0BE500EE12D1 /* AppIcon.xcassets */; }; 57ED6A80290886B6009580C6 /* ConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57ED6A7F290886B6009580C6 /* ConfigurationView.swift */; }; 57ED6A8229089111009580C6 /* Identifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57ED6A8129089111009580C6 /* Identifiable.swift */; }; @@ -80,7 +80,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 57C217AD29159B83005236DB /* RevenueCat in Frameworks */, + 5725F5502925753300A2A9B5 /* RevenueCat in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -202,7 +202,7 @@ ); name = PurchaseTester; packageProductDependencies = ( - 57C217AC29159B83005236DB /* RevenueCat */, + 5725F54F2925753300A2A9B5 /* RevenueCat */, ); productName = "PurchaseTester (iOS)"; productReference = 2CD2C4F5278C9B02005D1CC2 /* PurchaseTester.app */; @@ -233,7 +233,7 @@ ); mainGroup = 2CD2C4E8278C9B01005D1CC2; packageReferences = ( - 577E0E3B29159A8B0071E063 /* XCRemoteSwiftPackageReference "purchases-ios" */, + 579254E72925625100025DC7 /* XCRemoteSwiftPackageReference "purchases-ios" */, ); productRefGroup = 2CD2C4F6278C9B02005D1CC2 /* Products */; projectDirPath = ""; @@ -527,15 +527,23 @@ minimumVersion = 4.14.0; }; }; + 579254E72925625100025DC7 /* XCRemoteSwiftPackageReference "purchases-ios" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/nachosoto/purchases-ios"; + requirement = { + branch = "receipt-parser-spm-2"; + kind = branch; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 577E0E3E29159B340071E063 /* RevenueCat */ = { + 5725F54F2925753300A2A9B5 /* RevenueCat */ = { isa = XCSwiftPackageProductDependency; - package = 577E0E3B29159A8B0071E063 /* XCRemoteSwiftPackageReference "purchases-ios" */; + package = 579254E72925625100025DC7 /* XCRemoteSwiftPackageReference "purchases-ios" */; productName = RevenueCat; }; - 57C217AC29159B83005236DB /* RevenueCat */ = { + 577E0E3E29159B340071E063 /* RevenueCat */ = { isa = XCSwiftPackageProductDependency; package = 577E0E3B29159A8B0071E063 /* XCRemoteSwiftPackageReference "purchases-ios" */; productName = RevenueCat; diff --git a/Tests/TestingApps/PurchaseTesterSwiftUI/Shared/Views/HomeView.swift b/Tests/TestingApps/PurchaseTesterSwiftUI/Shared/Views/HomeView.swift index bdf242f2d5..20aa2cadba 100644 --- a/Tests/TestingApps/PurchaseTesterSwiftUI/Shared/Views/HomeView.swift +++ b/Tests/TestingApps/PurchaseTesterSwiftUI/Shared/Views/HomeView.swift @@ -8,6 +8,7 @@ import Foundation import SwiftUI import RevenueCat +import ReceiptParser struct HomeView: View { @EnvironmentObject var revenueCatCustomerData: RevenueCatCustomerData diff --git a/Tests/UnitTests/FoundationExtensions/DateFormatter+ExtensionsTests.swift b/Tests/UnitTests/FoundationExtensions/DateFormatter+ExtensionsTests.swift index 9f5e1d0458..0dcb98daf7 100644 --- a/Tests/UnitTests/FoundationExtensions/DateFormatter+ExtensionsTests.swift +++ b/Tests/UnitTests/FoundationExtensions/DateFormatter+ExtensionsTests.swift @@ -1,6 +1,7 @@ import Nimble import XCTest +@testable import ReceiptParser @testable import RevenueCat class DateFormatterExtensionTests: TestCase { diff --git a/Tests/UnitTests/Mocks/MockBundle.swift b/Tests/UnitTests/Mocks/MockBundle.swift index 5dc24481b0..0a6c2bffcd 100644 --- a/Tests/UnitTests/Mocks/MockBundle.swift +++ b/Tests/UnitTests/Mocks/MockBundle.swift @@ -47,6 +47,7 @@ final class MockBundle: Bundle { // MARK: - + // TODO: move these private static let mockAppStoreReceiptFileName = "base64encodedreceiptsample1" private static let mockSandboxReceiptFileName = "base64encoded_sandboxReceipt" diff --git a/Tests/UnitTests/Mocks/MockReceiptParser.swift b/Tests/UnitTests/Mocks/MockReceiptParser.swift index 156d5bb611..cee8ef8276 100644 --- a/Tests/UnitTests/Mocks/MockReceiptParser.swift +++ b/Tests/UnitTests/Mocks/MockReceiptParser.swift @@ -4,11 +4,13 @@ // import Foundation + +@testable import ReceiptParser @testable import RevenueCat import XCTest -class MockReceiptParser: ReceiptParser { +class MockReceiptParser: ParserType { var invokedParse = false var invokedParseCount = 0 @@ -34,12 +36,9 @@ class MockReceiptParser: ReceiptParser { ) ] - convenience init() { - self.init(containerBuilder: MockASN1ContainerBuilder(), - receiptBuilder: MockAppleReceiptBuilder()) - } + init() {} - override func parse(from receiptData: Data) throws -> AppleReceipt { + func parse(from receiptData: Data) throws -> AppleReceipt { self.invokedParse = true self.invokedParseCount += 1 self.invokedParseParameters = receiptData @@ -64,7 +63,7 @@ class MockReceiptParser: ReceiptParser { var invokedReceiptHasTransactionsParametersList = [(receiptData: Data, Void)]() var stubbedReceiptHasTransactionsResult: Bool! = false - override func receiptHasTransactions(receiptData: Data) -> Bool { + func receiptHasTransactions(receiptData: Data) -> Bool { invokedReceiptHasTransactions = true invokedReceiptHasTransactionsCount += 1 invokedReceiptHasTransactionsParameters = (receiptData, ()) diff --git a/Tests/UnitTests/Purchasing/IntroEligibilityCalculatorTests.swift b/Tests/UnitTests/Purchasing/IntroEligibilityCalculatorTests.swift index f9a592c490..99cec5449c 100644 --- a/Tests/UnitTests/Purchasing/IntroEligibilityCalculatorTests.swift +++ b/Tests/UnitTests/Purchasing/IntroEligibilityCalculatorTests.swift @@ -1,6 +1,7 @@ import Nimble import XCTest +@testable import ReceiptParser @testable import RevenueCat @available(iOS 12.0, macOS 10.14, macCatalyst 13.0, tvOS 12.0, watchOS 6.2, *) diff --git a/Tests/UnitTests/Purchasing/ReceiptFetcherTests.swift b/Tests/UnitTests/Purchasing/ReceiptFetcherTests.swift index 5f0c3d7096..3bd393ec25 100644 --- a/Tests/UnitTests/Purchasing/ReceiptFetcherTests.swift +++ b/Tests/UnitTests/Purchasing/ReceiptFetcherTests.swift @@ -12,9 +12,10 @@ // Created by Andrés Boedo on 8/3/21. import Foundation +import Nimble import XCTest -import Nimble +@testable import ReceiptParser @testable import RevenueCat class BaseReceiptFetcherTests: TestCase { diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 6e65d2fade..fcd5e2f0d4 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -14,6 +14,7 @@ default_platform(:ios) files_with_version_number = [ './RevenueCat.podspec', + './Packages/ReceiptParser/ReceiptParser.podspec', './Sources/Misc/SystemInfo.swift', './.jazzy.yaml', './.version', @@ -574,6 +575,7 @@ platform :ios do end def push_pods + pod_push(path: "Packages/ReceiptParser/ReceiptParser.podspec", synchronous: true) pod_push(path: "RevenueCat.podspec", synchronous: true) end @@ -604,7 +606,14 @@ end lane :check_pods do pod_lib_lint( verbose: true, - podspec:'RevenueCat.podspec', + podspec: 'RevenueCat.podspec', + # TODO: re-add watchOS when https://github.com/CocoaPods/CocoaPods/issues/11558 is fixed. + platforms:"ios,osx,tvos", + fail_fast: true + ) + pod_lib_lint( + verbose: true, + podspec: 'Packages/ReceiptParser/ReceiptParser.podspec', # TODO: re-add watchOS when https://github.com/CocoaPods/CocoaPods/issues/11558 is fixed. platforms:"ios,osx,tvos", fail_fast: true