TPInAppReceipt is a lightweight, pure-Swift library for reading and validating Apple In App Purchase Receipt locally.

Overview

TPInAppReceipt

Swift CocoaPods Compatible Swift Package Manager compatible Platform GitHub license

TPInAppReceipt is a lightweight, pure-Swift library for reading and validating Apple In App Purchase Receipt locally.

Features

  • Read all In-App Receipt Attributes
  • Validate In-App Purchase Receipt (Signature, Bundle Version and Identifier, Hash)
  • Determine Eligibility for Introductory Offer
  • Use with StoreKitTest
  • Use in Objective-C projects

Installation

Note: TPInAppReceipt in Objective-C project - If you want to use TPInAppReceipt in Objective-C project please follow this guide.

CocoaPods

To integrate TPInAppReceipt into your project using CocoaPods, specify it in your Podfile:

platform :ios, '9.0'

target 'YOUR_TARGET' do
  use_frameworks!

  pod 'TPInAppReceipt'
end

Then, run the following command:

$ pod install

In any swift file you'd like to use TPInAppReceipt, import the framework with import TPInAppReceipt.

Swift Package Manager

To integrate using Apple's Swift package manager, add the following as a dependency to your Package.swift:

.package(url: "https://github.com/tikhop/TPInAppReceipt.git", .upToNextMajor(from: "3.0.0"))

Then, specify "TPInAppReceipt" as a dependency of the Target in which you wish to use TPInAppReceipt.

Lastly, run the following command:

swift package update

Requirements

  • iOS 10.0+ / OSX 10.11+
  • Swift 5.3+

Usage

Working With a Receipt

The InAppReceipt object encapsulates information about a receipt and the purchases associated with it. To validate In-App Purchase Receipt you must create an InAppReceipt object.

Initializing Receipt

To create InAppReceipt object you can either provide a raw receipt data or initialize a local receipt.

do {
  /// Initialize receipt
  let receipt = try InAppReceipt.localReceipt() 
  // let receipt = try InAppReceipt() // Returns local receipt 
  
  // let receiptData: Data = ...
  // let receipt = try InAppReceipt.receipt(from: receiptData)
  
} catch {
  print(error)
}

Validating Receipt

TPInAppReceipt provides a variety of convenience methods for validating In-App Purchase Receipt:

/// Verify hash 
try? receipt.verifyHash()

/// Verify bundle identifier
try? receipt.verifyBundleIdentifier

/// Verify bundle version
try? receipt.verifyBundleVersion()

/// Verify signature
try? receipt.verifySignature()

/// Validate all at once 
do {
  try receipt.verify()
} catch IARError.validationFailed(reason: .hashValidation) {
  // Do smth
} catch IARError.validationFailed(reason: .bundleIdentifierVerification) {
  // Do smth
} catch IARError.validationFailed(reason: .signatureValidation) {
  // Do smth
} catch {
  // Do smth
}

NOTE: Apple recommends to perform receipt validation right after your app is launched. For additional security, you may repeat this check periodically while your application is running. NOTE: If validation fails in iOS, try to refresh the receipt first.

Determining Eligibility for Introductory Offer

If your App offers introductory pricing for auto-renewable subscriptions, you will need to dispay the correct price, either the intro or regular price.
The InAppReceipt class provides an interface for determining introductory price eligibility. At the simplest, just provide a Set of product identifiers that belong to the same subscription group:

// Check whether user is eligible for any products within the same subscription group 
var isEligible = receipt.isEligibleForIntroductoryOffer(for: ["com.test.product.bronze", "com.test.product.silver", "com.test.product.gold"])

Note: To determine if a user is eligible for an introductory offer, you must initialize and validate receipt first and only then check for eligibility.

Reading Receipt

/// Initialize receipt
let receipt = try! InAppReceipt.localReceipt() 

/// Base64 Encoded Receipt
let base64Receipt = receipt.base64
  
/// Check whether receipt contains any purchases
let hasPurchases = receipt.hasPurchases

/// All auto renewable `InAppPurchase`s,
let purchases: [InAppPurchase] = receipt.autoRenewablePurchases 

/// all ACTIVE auto renewable `InAppPurchase`s,
let activePurchases: [InAppPurchase] = receipt.activeAutoRenewableSubscriptionPurchases 

Useful methods

// Retrieve Original TransactionIdentifier for Product Name
receipt.originalTransactionIdentifier(ofProductIdentifier: subscriptionName)

// Retrieve Active Auto Renewable Subscription's Purchases for Product Name and Specific Date
receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: subscriptionName, forDate: Date())

// Retrieve All Purchases for Product Name
receipt.purchases(ofProductIdentifier: subscriptionName)

Refreshing/Requesting Receipt

When necessary, use this method to ensure the receipt you are working with is up-to-date.

InAppReceipt.refresh { (error) in
  if let err = error
  {
    print(err)
  } else {
    initializeReceipt()
  }
}

Essential Reading

License

TPInAppReceipt is released under an MIT license. See LICENSE for more information.

Comments
  • Fail to parse StoreKitTest receipt

    Fail to parse StoreKitTest receipt

    Platform

    • [X ] iOS
    • [ ] macOS
    • [ ] tvOS

    Environment

    • [ X] Sandbox
    • [ ] Production

    Version

    ℹ Please replace this with the version of TPInAppReceipt you're using. 16ac80c7f2cf0810dbe1de0c5ac48ac67b031d0b (latest master at time of writing)

    Related issues

    Report

    Setting up a test using https://developer.apple.com/documentation/xcode/setting_up_storekit_testing_in_xcode - this is a manual test, not using StoreKitTest

    InAppReceipt.local() fails because pkcs7.extractInAppPayload()! returns Nil (InAppReceipt:67).

    I'm aware of the different cert, but I don't even get to the point of loading the cert

    Issue summary

    Set up your StoreKitTest file. Upgrade. Validate the receipt.

    What did you expect to happen

    receipt should be parsed.

    What happened instead

    crash due to force unwrap of nil

    opened by motocodeltd 32
  • Introductory Offer Support?

    Introductory Offer Support?

    Wondering if we can get introductory offer support by implementing the ability to check eligibility?

    Each product returns whether it has an introductory offer tied to it. However in order to check eligibility we must parse the receipt. (Hence the feature request)

    This would entail parsing the receipt for is_trial_period as well as is_in_intro_offer_period. If these values are equal to 1 somewhere, a user has already used free trial/introductory offer.

    Helpful articles outlining this: https://www.revenuecat.com/blog/ios-introductory-prices https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/implementing_introductory_offers_in_your_app https://blog.apphud.com/introductory-offers-in-ios/

    Helpful article snippet:

    "As of iOS 12.0, SKProduct now includes subscriptionGroupIdentifier property, so it's now possible to compute Introductory Pricing eligibility locally. While this update is great, calculating intro eligibility locally still requires a lot of unnecessary dev work. To check intro eligibility on iOS >= 12.0, you need to:

    • Refresh the receipt so you have updated information about the user's purchases
    • Parse the receipt and look for purchases made with introductory pricing
    • Transform the identifiers for purchases made with intro pricing into SKProducts
    • Transform the productIdentifiers you want to check eligibility for into SKProducts
    • Check if there's a match - if there's at least one purchase made using intro pricing for the same product identifier or the same subscription group, the user is not eligible. If none are found, they're eligible." https://www.revenuecat.com/blog/ios-introductory-prices
    feature request 
    opened by Jerland2 19
  • Expiration date / purchase seems to not be in in same timezone as swift Date()

    Expiration date / purchase seems to not be in in same timezone as swift Date()

    Hi,

    I've got something weird on my iOS app. I did a StoreKit configuration to test my auto renewable purchase flow.

    I buy a 1 month subscription (which expire in 30s). When I call isActiveAutoRenewableSubscription with Date() as parameter it seems that date are not working well, this is what I get :

    date : 2020-12-03 20:54:33 +0000 purchaseDate : 2020-12-03 21:54:32 +0000 <--- Seems to be GMT +1 expiration: 2020-12-03 21:55:03 +0000 <--- Seems to be GMT +1

    21:54:33 was my current time in France (GMT +1) when I did these logs.

    I looked at the expiration date string we received in receipt and it was : 2020-12-03T21:55:03Z.

    In a real case, in the moment of the renewing, my user based in France will no longer have active subscriptions detected until the timezone time value has been elapsed.

    Have you the same "timezoned" date values on your side ?

    Tell me if I'm not clear :)

    Thanks for your job.

    opened by NameX44 17
  • InAppReceipt.localReceipt() - Crashed!

    InAppReceipt.localReceipt() - Crashed!

    Hello, The lib crashing at the 2.0.6 version for some users. Attaching the crash log:

    0 | TPInAppReceipt | $s10Foundation4DataV15_RepresentationOyACSnySiGcigTf4xn_n + 672 -- | -- | -- 1 | TPInAppReceipt | $s14TPInAppReceipt10ASN1ObjectV13extractLenght4fromAC6LengthO10Foundation4DataVz_tKFZTf4nd_n + 280 2 | TPInAppReceipt | $s14TPInAppReceipt10ASN1ObjectV11isDataValid14checkingLength_S2b_10Foundation0G0VztFZTf4nnd_n + 136 3 | TPInAppReceipt | $s14TPInAppReceipt10ASN1ObjectV5value33_FC213C5763315B30AA3A82B9DB6D97D1LLAA0D21ExtractableValueTypes_pSgyF + 1868 4 | TPInAppReceipt | $s14TPInAppReceipt02InbC7PayloadV8asn1DataAC10Foundation0G0V_tcfcyAA0dbC9AttributeVXEfU_ + 268 5 | TPInAppReceipt | $s14TPInAppReceipt10ASN1ObjectV011enumerateInbC10Attributes4withyyAA0gbC9AttributeVXE_tF04$s14ab62Receipt02InbC7PayloadV8asn1DataAC10Foundation0G0V_tcfcyAA0dbC9J6VXEfU_SS10Foundation0Q0VSSA2KSayAA0gB8PurchaseVGS2SSgSSTf1cn_n + 512 6 | TPInAppReceipt | $s14TPInAppReceipt02InbC7PayloadV8asn1DataAC10Foundation0G0V_tcfCTf4gd_n + 432 7 | TPInAppReceipt | $s14TPInAppReceipt02InbC0V05localC0ACyKFZ + 260

    opened by weizenberg 15
  • CryptoSwift files need update

    CryptoSwift files need update

    Hello, due to xcode 12.5 the CryptoSwift files that are in use here UInt n+Extension.swift are throwing errors. The fix is available in the CryptoSwift pod, and it is trivial.

    thanks! christian

    bug 
    opened by ungerc 11
  • Can be used with sandbox receipts?

    Can be used with sandbox receipts?

    Hi, I'm using it to validate sandbox receipts that i get with SKReceiptRefreshRequest but it fails...

    Error Domain=NSOSStatusErrorDomain Code=-25318 "“Mac App Store and iTunes Store Receipt Signing” certificate is not trusted" UserInfo={NSLocalizedDescription=“Mac App Store and iTunes Store Receipt Signing” certificate is not trusted, NSUnderlyingError=0x2830b7b10 {Error Domain=NSOSStatusErrorDomain Code=-25318 "Certificate 0 “Mac App Store and iTunes Store Receipt Signing” has errors: Unable to build chain to root (possible missing intermediate);" UserInfo={NSLocalizedDescription=Certificate 0 “Mac App Store and iTunes Store Receipt Signing” has errors: Unable to build chain to root (possible missing intermediate);}}}

    Can it be used with sandbox or not?

    opened by andrefmsilva 10
  • Background Task SKReceiptRefreshRequest was created over 30 seconds ago

    Background Task SKReceiptRefreshRequest was created over 30 seconds ago

    After refreshing receipt I'm getting a warning:

    Background Task 3 ("SKReceiptRefreshRequest"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this.
    

    The request completes successfully and the warning appears later on. It seems to be similar to https://github.com/RevenueCat/purchases-ios/issues/391

    And it should probably be resolved by cancelling the request both after success and error in RefreshSession, similar to what is done https://github.com/RevenueCat/purchases-ios/pull/418

    opened by victorkifer 9
  • Fix Carthage

    Fix Carthage

    When I try to add this in Xcode 11.3.1 via "Add Package Dependency…" I get an error saying "Package Resolution Failed".

    The package dependency graph can not be resolved; unable find any available tag for the following requirements: https://github.com/tikhop/TPInAppReceipt.git — 3.0.2..<4.0.0

    Any idea how to fix this? Thanks a lot!

    bug 
    opened by gubikmic 9
  • [Catalyst] Big Sur App Receipt not found

    [Catalyst] Big Sur App Receipt not found

    This issue is thrown in Big Sur beta 8 and validation fails

    Error validating receipt: initializationFailed(reason: TPInAppReceipt.IARError.ReceiptInitializationFailureReason.appStoreReceiptNotFound)

    bug 
    opened by chrisvanbuskirk 8
  • Permanent ValidationFailed error

    Permanent ValidationFailed error

    Platform

    • [ ] macOS

    Environment

    • [ ] Sandbox
    • [ ] Production

    Version

    ℹ 2.3.4

    Related issues

    Report

    Issue summary

    ℹI get permanent ValidationFailed error. Rolled back to version 2.2 and everything works fine

    What did you expect to happen

    ℹ expect the validation will be success on apple's MAS receipt

    What happened instead

    ℹ Please replace this with what happened instead.

    opened by CineDev 8
  • openssl as a module file not correct

    openssl as a module file not correct

    If I include TPInAppReceipt in my main file, the main file works fine. However if I compile my Test target, Swift will now try to include and compile openssl for the Test target and I get the error "...Pods/TPInAppReceipt/Vendor/OpenSSL/include/openssl/bio.h:62:11: 'openssl/e_os2.h' file not found" for all the swift files in my Test target.

    My suspicion is that the Pods/TPInAppRceipt/Vendor/OpenSSL/module.modulemap has an error, but I don't know enough about modulemaps. IBM has created a module for Swift for OpenSSL. https://github.com/IBM-Swift/OpenSSL Perhaps that is useable

    opened by ovdm 8
  • Compiled module was created by an older version of the compiler

    Compiled module was created by an older version of the compiler

    Hi, I have been using TPInAppReceipt in my app "Pilot Log for Tesla" (thank you). I have had no issue so far. However in Xcode (latest) I now get "Compiled module was created by an older version of the compiler; rebuild 'TPInAppReceipt' and try again". This appears as a "red" error, but the build is successful and the app runs normally. Not sure the matter is on your side, but, I'd appreciate your insight on this issue. Thks

    question 
    opened by Jim3750 3
  • Purchase cancellationDate is not only for renewable subscribtions

    Purchase cancellationDate is not only for renewable subscribtions

    Hello, and thank you for such great library.

    The comment for cancellationDate says: Returns nil if the purchase is not a renewable subscription

    But the docs say that this field is designed for use with auto-renewable subscription, non-consumable and non-renewing subscription products. So, although your comment don't say it, does this field get filled when using non-consumable products? If yes, I suggest changing the comment so it gets more clear.

    Thank you, and best regards. Sergio.

    question 
    opened by sjvc 3
  • Build failed for iOS Simulator

    Build failed for iOS Simulator

    When building for any iOS simulator on an M1 Mac, the following error occurs:

    Could not find module 'TPInAppReceipt' for target 'x86_64-apple-ios-simulator'; found: arm64-apple-ios-simulator, at: /Users/wizfinger/Library/Developer/Xcode/DerivedData/appname-bkfhgmponcvrxfawozdvxtgsikwn/Build/Products/Debug-iphonesimulator/TPInAppReceipt.swiftmodule

    (TPInAppReceipt_Objc has the same result).

    Build for device works correctly.

    What can I do to fix this?

    bug 
    opened by ghost 4
  • Clarification of Subscription Trial Period ASN.1 Field type

    Clarification of Subscription Trial Period ASN.1 Field type

    Hi,

    You have done a nice work. I want to clarify about Subscription Trial Period ASN.1 Field type.

    https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1

    Document say's:- If a previous subscription period in the receipt has the value “true” for either the is_trial_period or the is_in_intro_offer_period key, the user is not eligible for a free trial or introductory price within that subscription group.

    Subscription Introductory Price Period :- ASN.1 Field Type 1719 Subscription Trial Period:- ASN.1 Field Type (none)

    But you used "ASN.1 Field Type 1713" for Subscription Trial Period.

    Did you get "1713" from somewhere documented? or through test and Assumption?

    question 
    opened by thaya-cameraxis 1
Releases(3.3.4)
  • 3.3.4(Jul 29, 2022)

  • 3.3.0(Sep 24, 2021)

    • Try different network interfaces (en0, en1) when getting the GUID on macOS for hash computation (Thanks to @mshibanami)
    • Improve docs (Thanks to @nneubauer)
    Source code(tar.gz)
    Source code(zip)
  • 3.2.0(May 25, 2021)

    • (https://github.com/tikhop/TPInAppReceipt/issues/85) Introductory Offer Support. Thanks @Jerland2 for bringing this up.
    • (https://github.com/tikhop/TPInAppReceipt/issues/84) Make it possible to use the library in Objective-C project. Thanks @MacMark for making it possible.
    • InAppReceipt.init() initializes a local receipt.
    Source code(tar.gz)
    Source code(zip)
  • 3.1.1(Apr 3, 2021)

    • (https://github.com/tikhop/TPInAppReceipt/issues/83) Fix StoreKitTest receipt encoding. InAppPurchase.originalPurchaseDate is nil in StoreKitTest. Thanks @Jerland2 for the report.
    Source code(tar.gz)
    Source code(zip)
  • 3.1.0(Apr 2, 2021)

Owner
Pavel T
Pavel T
Swift implementation of KERI (Key Event Receipt Infrastructure)

keri-swift Swift implementation of KERI (Key Event Receipt Infrastructure) Introduction keri-swift is an open source go implementation of the Key Even

WebOfTrust 1 Jun 2, 2022
iOS SDK for cross-platform in-app purchase and subscription infrastructure, revenue analytics, engagement automation, and integrations

Qonversion is the data platform to power in-app subscription revenue growth. fast in-app subscriptions implementation back-end infrastructure to valid

Qonversion 248 Nov 8, 2022
In App Purchase Manager framework for iOS

InAppFramework In App Purchase Manager framework for iOS Disclaimer I know it's been too long since the last update, quite a few things happened in my

Sándor Gyulai 40 May 23, 2020
A jailed in-app purchase cracker for iOS 12.2-15.6

Satella Jailed For, um, educational purposes only or something. Definitely don't use this to pirate in-app purchases in apps to which you don't have l

Lilly 252 Nov 16, 2022
A lightweight iOS library for In-App Purchases

#RMStore A lightweight iOS library for In-App Purchases. RMStore adds blocks and notifications to StoreKit, plus receipt verification, content downloa

Robot Media 2.4k Nov 17, 2022
Lightweight In App Purchases Swift framework for iOS 8.0+, tvOS 9.0+ and macOS 10.10+ ⛺

SwiftyStoreKit is a lightweight In App Purchases framework for iOS, tvOS, watchOS, macOS, and Mac Catalyst. Features Super easy-to-use block-based API

Andrea Bizzotto 6.1k Nov 15, 2022
Implement donate to Ukraine inside your app, with Apple Pay

DonateToUkraine gives you a simple way to provide "donate to Ukraine" functionality in your app via an official donation service (endorsed here). The service will be opened inside the app, keeping a native feel. Apple Pay is supported.

Oleg Dreyman 22 Aug 2, 2022
Allow to add .pkpass files to Apple wallet

Allow to add .pkpass file to Apple Wallet

Jose Valentin Abundo Hernandez 4 Nov 11, 2022
Better payment user experience library with cool animation in Swift

?? Preview ?? Features Easily usable Simple Swift syntax Cool flip animation Compatible with Carthage Compatible with CocoaPods Customizable Universal

yassir RAMDANI 177 Nov 20, 2022
Easy to use iOS library with components for input of Credit Card data.

AnimatedCardInput This library allows you to drop into your project two easily customisable, animated components that will make input of Credit Card i

Netguru 39 Oct 16, 2022
In-app purchases and subscriptions made easy. Support for iOS, iPadOS, watchOS, and Mac.

In-app purchases and subscriptions made easy. Support for iOS, iPadOS, watchOS, and Mac.

RevenueCat 1.6k Nov 25, 2022
OnTime - OnTime App is for Scheduling your day and prioritizing your task and also for saving notes

OnTime OnTime App is for Scheduling your day and prioritizing your task and also

Mohammed Sulaiman 1 Jan 29, 2022
Make and accept payments in your iOS app via Venmo

Venmo iOS SDK The Venmo iOS SDK lets you make and accept payments in your app using Venmo. Installation If you're using CocoaPods: If you don't have a

Venmo 168 Sep 29, 2022
Accept credit cards and PayPal in your iOS app

Important: PayPal Mobile SDKs are Deprecated. The APIs powering them will remain operational long enough for merchants to migrate, but the SDKs themse

PayPal 972 Nov 4, 2022
Easily integrate Credit Card payments module in iOS App. Swift 4.0

MFCard Buy me a coffee MFCard is an awesome looking Credit Card input & validation control. Written in Swift 3. YOoo, Now MFCard is on Swift 5. Swift

MobileFirst 361 Nov 20, 2022
A modern In-App Purchases management framework for iOS.

MerchantKit A modern In-App Purchases management framework for iOS developers. MerchantKit dramatically simplifies the work indie developers have to d

Benjamin Mayo 1.1k Nov 17, 2022
With SwiftUI payment share app

Splitpayment With SwiftUI payment share app.

Ahmet Onur Şahin 3 Apr 18, 2022
Square In-App Payments iOS SDK SwiftUI

Square In-App Payments iOS SDK SwiftUI Build remarkable payments experiences in

Ashley Bailey 2 Mar 8, 2022
SwiftUI BusinessCard - Created iOS Business card app to practice SwiftUI

SwiftUI_BusinessCard Created iOS Business card app to practice SwiftUI

null 0 Jan 29, 2022