Purchaser is a set of classes written in Swift to help iOS developers to simplify the process of implementing In-App purchases in their applications.
- Support all kinds of products (Now only supports Auto-Renewable subscriptions).
- Add receipt validation.
- Add receipt refresh.
- iOS 9.0+
- Xcode 10.0+
- Swift 4.2+
Add this line to your podfile:
pod 'Purchaser'
Import Purchaser
in your source file:
import Purchaser
Now you have the option of setup the product idenfitiers at the beginning, so the actions the library do, will be done using these identifiers; Or you have the option to setup identifiers manually in the future on demand. In any case, it is strongly recommended that you setup Purchaser
in the AppDelegate.swift
subclass. Simply call:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Setup with product identifiers
Purchaser.setup(with: ["my_awesome_product_identifier"])
// Setup identifiers later
Purchaser.setup()
return true
}
This step is mandatory so all the transactions can be processed as expected, even if they initially fail due to a lack of internet connection or app termination.
In order to not feed the Strong Reference Cycle monster, make sure you use self
marked as weak
or unowned
as in the example code provided when needed. Purchaser
stores the completion closures in a property retaining the objects inside the closure.
To request a list of products from the App Store use the following:
Purchaser.requestProducts { [unowned self] (products, _, error) in
if let error = error {
print("error requesting products: \(error)")
} else {
self.products = products
self.reload()
}
}
It returns an array of SKProduct
objects, an array of invalid product identifiers and an Error
object identifying the error if any.
If you choose to setup product identifiers later, you should pass an array of product identifiers with the call:
let identifiers = ["my_awesome_product_identifier"]
Purchaser.requestProducts(with: identifiers) { (products, _, error) in
// Handle response
}
If not provided, the call returns a "Missing product identifiers" error.
Once you've got the list of valid products from Apple, you can call the buy(product:)
function on each product:
Purchaser.buy(product) { (state, _, _, error) in
if let error = error {
print("error buying product: \(error)")
} else {
if state == .purchasing || state == .deferred { return }
print("product purchased!")
}
}
The closure will be called for each finished transactions. For unfinished transactions, the closure will be called after the system recoveries from whatever doesn't have had allowed to finish the transaction.
Additionally (and recommended), you can pass an account
parameter that will be used in the SKPayment
object's applicationUsername
parameter. The value of this property can be a String which identifies the user making the transaction (username, email, etc). Purchaser
creates a SHA256 hash of the value you pass and sets the applicationUsername
parameter with it.
You can check if a product have been purchased by calling:
Purchaser.isProductPurchased(with: "my_awesome_product_identifier")
Sometimes the payments feature is restricted due to, for example, parental controls configured in the device. To check if the user can make payments use:
Purchaser.canMakePayments()
Developers usually hide payment related UI if the user is unable to make payments.
To restore previously finished transactions, you need to call:
Purchaser.restorePurchases { (state, _, finished, error) in
if let error = error {
print("error restoring products: \(error)")
} else {
if state == .purchasing || state == .deferred { return }
print("products restored!")
}
}
You can inspect the finished
parameter to know if all the transactions have been finished. It will be set a false
for any single transaction restored but will be set to true
when all the transactions has been restored.