### Custom Decoder Engine Implementation Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Architecture.md Provides an example of how to implement a custom decoder engine by conforming to the AppReceiptDecoder.Engine protocol. This allows for custom parsing logic when decoding receipt data. ```swift struct MyEngine: AppReceiptDecoder.Engine { func decode(from data: Data) throws -> AppReceipt { // custom parsing } } let decoder = AppReceiptDecoder(engine: MyEngine()) let receipt = try decoder.decode(from: data) ``` -------------------------------- ### Decoding Receipt Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Provides examples for decoding App Store receipt data, both from a local file and from raw data. ```APIDOC ## Decoding Receipt ```swift import TPInAppReceipt // Local receipt let receipt = try await AppReceipt.local // From raw data let receipt = try AppReceipt.receipt(from: data) ``` `AppReceipt` is a typealias over `ContentInfo>` — the full PKCS#7 structure is accessible. ``` -------------------------------- ### Introductory Offer Eligibility Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Explains how to check if a user is eligible for an introductory offer for a given subscription group. ```APIDOC ## Introductory Offer Eligibility Pass product identifiers within the same subscription group: ```swift receipt.isEligibleForIntroductoryOffer( for: ["com.example.bronze", "com.example.silver", "com.example.gold"] ) ``` ``` -------------------------------- ### Checking Introductory Offer Eligibility Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Determine if a user is eligible for an introductory offer for a given subscription group. Pass an array of product identifiers belonging to the same group. ```swift receipt.isEligibleForIntroductoryOffer( for: ["com.example.bronze", "com.example.silver", "com.example.gold"] ) ``` -------------------------------- ### Format Code with Swift Format Source: https://github.com/tikhop/tpinappreceipt/blob/master/CONTRIBUTING.md Use this command to format all Swift files recursively according to the project's .swift-format guidelines. Ensure code is reasonably short and uses meaningful names. ```bash swift format -i . --recursive ``` -------------------------------- ### Run Project Tests Source: https://github.com/tikhop/tpinappreceipt/blob/master/CONTRIBUTING.md Execute all project tests using this command. Ensure all tests pass before submitting contributions. ```bash swift test ``` -------------------------------- ### Update Receipt Initialization Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/TPInAppReceipt 4.0 Migration Guide.md Migrate from the old `InAppReceipt` initialization to the new `AppReceipt` async initialization. ```swift // Before let receipt = try InAppReceipt.localReceipt() // or let receipt = try InAppReceipt() // After let receipt = try await AppReceipt.local ``` ```swift // Before let receipt = try InAppReceipt.receipt(from: data) // After let receipt = try AppReceipt.receipt(from: data) ``` -------------------------------- ### Add TPInAppReceipt via Swift Package Manager Source: https://github.com/tikhop/tpinappreceipt/blob/master/README.md Add the TPInAppReceipt library to your project using Swift Package Manager. Ensure your target includes the library as a dependency. ```swift dependencies: [ .package(url: "https://github.com/tikhop/TPInAppReceipt.git", from: "4.0.2") ] ``` ```swift .target( name: "YourTarget", dependencies: ["TPInAppReceipt"]) ``` -------------------------------- ### Read Local or Raw Data Receipt in Swift Source: https://github.com/tikhop/tpinappreceipt/blob/master/README.md Import the TPInAppReceipt library to access receipt data. Use `AppReceipt.local` for the local receipt or `AppReceipt.receipt(from: data)` for raw data. ```swift import TPInAppReceipt // Local receipt let receipt = try await AppReceipt.local // From raw data let receipt = try AppReceipt.receipt(from: data) ``` -------------------------------- ### Custom Verifier Implementation Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Architecture.md Demonstrates how to implement a custom receipt verifier by conforming to the ReceiptVerifier protocol. This allows for custom validation logic to be added to the receipt validation process. ```swift struct MyVerifier: ReceiptVerifier { func verify(_ receipt: ReceiptValidatable) async -> VerificationResult { // custom check return .valid } } let validator = ReceiptValidator { X509ChainVerifier(rootCertificates: [rootCert]) MyVerifier() } ``` -------------------------------- ### Managing Purchases Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Shows how to access and query purchase information from the receipt, including all purchases, auto-renewable subscriptions, and active subscriptions. ```APIDOC ## Managing Purchases ```swift receipt.purchases // [InAppPurchase] receipt.hasPurchases receipt.autoRenewablePurchases receipt.activeAutoRenewableSubscriptionPurchases ``` Query by product: ```swift receipt.purchases(ofProductIdentifier: "com.example.sub") receipt.containsPurchase(ofProductIdentifier: "com.example.premium") receipt.hasActiveAutoRenewableSubscription( ofProductIdentifier: "com.example.sub", forDate: Date() ) receipt.lastAutoRenewableSubscriptionPurchase( ofProductIdentifier: "com.example.sub" ) ``` ``` -------------------------------- ### Querying Purchases by Product Identifier Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Filter purchases by their product identifiers. This is useful for checking specific subscriptions or in-app purchases. ```swift receipt.purchases(ofProductIdentifier: "com.example.sub") receipt.containsPurchase(ofProductIdentifier: "com.example.premium") receipt.hasActiveAutoRenewableSubscription( ofProductIdentifier: "com.example.sub", forDate: Date() ) receipt.lastAutoRenewableSubscriptionPurchase( ofProductIdentifier: "com.example.sub" ) ``` -------------------------------- ### Reading Receipt Properties Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Demonstrates how to access various properties of the decoded receipt, such as bundle identifier, app version, environment, and dates. ```APIDOC ## Reading Receipt Properties ```swift receipt.bundleIdentifier receipt.appVersion receipt.originalAppVersion // String? receipt.environment // .production, .sandbox, .xcode, .productionSandbox receipt.creationDate receipt.expirationDate // VPP only ``` See for the full list of fields. ``` -------------------------------- ### Accessing Purchase Information Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Retrieve lists of purchases, check for the existence of purchases, and filter auto-renewable subscriptions. Use these properties to manage user entitlements. ```swift receipt.purchases // [InAppPurchase] receipt.hasPurchases receipt.autoRenewablePurchases receipt.activeAutoRenewableSubscriptionPurchases ``` -------------------------------- ### Use Blocking API for Synchronous Operations Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/TPInAppReceipt 4.0 Migration Guide.md Import TPInAppReceipt with `@_spi(Blocking)` to access synchronous variants of asynchronous receipt loading and validation methods. ```swift @_spi(Blocking) import TPInAppReceipt // Load receipt let receipt = try AppReceipt.local_blocking // Validate let result = receipt.validate_blocking() ``` -------------------------------- ### Refreshing Receipt Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Provides instructions on how to request an updated receipt from the App Store. ```APIDOC ## Refreshing Receipt Request an updated receipt from the App Store: ```swift try await AppReceipt.refresh() ``` ``` -------------------------------- ### Custom Receipt Validation with @VerifierBuilder Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Validating Receipt.md Create a custom validator by combining different verifiers. This allows for fine-grained control over the validation process. Verifiers run in parallel and will cancel if any one fails. ```swift let validator = ReceiptValidator { X509ChainVerifier(rootCertificates: [rootCert]) SignatureVerifier() HashVerifier(deviceIdentifier: deviceId) MetaVerifier( appVersionProvider: { Bundle.main.appVersion }, bundleIdentifierProvider: { Bundle.main.bundleIdentifier } ) } let result = await validator.validate(receipt) ``` -------------------------------- ### Reading Receipt Fields Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Access various fields from the decoded receipt object, such as bundle identifier, app version, and environment. Some fields like expirationDate are only available for VPP. ```swift receipt.bundleIdentifier receipt.appVersion receipt.originalAppVersion // String? receipt.environment // .production, .sandbox, .xcode, .productionSandbox receipt.creationDate receipt.expirationDate // VPP only ``` -------------------------------- ### Validate App Receipt in Blocking Mode Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Blocking Mode.md Use this snippet to perform synchronous validation of a local app receipt. Ensure the `@_spi(Blocking) import TPInAppReceipt` is included. ```swift @_spi(Blocking) import TPInAppReceipt let receipt = try AppReceipt.local_blocking let result = receipt.validate_blocking() ``` -------------------------------- ### Default Receipt Validation Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Validating Receipt.md Use this method for a quick and comprehensive validation of the receipt. It automatically selects the correct Apple root certificate. ```swift let result = await receipt.validate() switch result { case .valid: break case .invalid(let error): print(error) } ``` -------------------------------- ### Update Receipt Refresh Mechanism Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/TPInAppReceipt 4.0 Migration Guide.md Replace the callback-based `InAppReceipt.refresh` with the new `await AppReceipt.refresh()` and utilize Swift Concurrency task cancellation for managing refresh operations. ```swift // Before InAppReceipt.refresh { error in // ... } // After try await AppReceipt.refresh() ``` -------------------------------- ### Refreshing the App Store Receipt Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Working with Receipt.md Request an updated receipt from the App Store. This is an asynchronous operation that may require network access. ```swift try await AppReceipt.refresh() ``` -------------------------------- ### Update Receipt Validation Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/TPInAppReceipt 4.0 Migration Guide.md Replace the synchronous `receipt.verify()` with the new asynchronous `await receipt.validate()` and handle the `ReceiptValidatorError`. ```swift // Before do { try receipt.verify() } catch IARError.validationFailed(reason: .hashValidation) { // ... } // After let result = await receipt.validate() switch result { case .valid: break case .invalid(let error): // error is typed: ReceiptValidatorError, ChainVerificationError, etc. print(error) } ``` -------------------------------- ### AppReceipt Type Alias Source: https://github.com/tikhop/tpinappreceipt/blob/master/Sources/Docs.docc/Architecture.md Defines AppReceipt as a type alias for the nested structure of ContentInfo, SignedData, and InAppReceiptPayload. ```swift public typealias AppReceipt = ContentInfo> ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.