AppStoreManger is an easy to use, StoreKit 2 based, in-App Purchase manager.
If you find AppStoreManger useful and would like to help support its continued development and maintenance, please consider making a small donation, especially if you are using it in a commercial product:
It's through the support of contributors like yourself, I can continue to build, release and maintain high-quality, well documented Swift Packages like AppStoreManger for free.
Swift Package Manager (Xcode 11 and above)
- In Xcode, select the File > Add Package Dependency… menu item.
- Paste
https://github.com/Appracatappra/AppStoreManger.gitin the dialog box. - Follow the Xcode's instruction to complete the installation.
Why not CocoaPods, or Carthage, or etc?
Supporting multiple dependency managers makes maintaining a library exponentially more complicated and time consuming.
Since, the Swift Package Manager is integrated with Xcode 11 (and greater), it's the easiest choice to support going further.
By simply including AppStoreManager in your App Project and defining your Products.plist file, it provides automatic support for the following:
- Family Sharing.
- Promoted In-App Purchases.
- Restored Product Purchases.
You'll need to include a Products.plist in your App's Bundle that defines the Products that you have for sale, along with any useful metadata (such as an Image or Long Description) that you wish to define.
The following is a SampleProducts.plist that is included:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>InAppPurchaseID01</key>
<dict>
<key>Image</key>
<string>ProductImageName01</string>
<key>Description</key>
<string>ProductDescription01</string>
</dict>
<key>InAppPurchaseID02</key>
<dict>
<key>Image</key>
<string>ProductImageName02</string>
<key>Description</key>
<string>ProductDescription02</string>
</dict>
<key>InAppPurchaseID03</key>
<dict>
<key>Image</key>
<string>ProductImageName03</string>
<key>Description</key>
<string>ProductDescription03</string>
</dict>
</dict>
</plist>
The first Key in the Products dictionary is critical as should be a valid In-App Purchase ID as defined in App Store Connect for you App.
The sub Dictionary includes any metadata attributes that you'd like to associate with the individual products as both a String kay and String value. In the case of this example, we are including both an Image Name and Long Description.
Later we can use a StoreManager function to fetch any attribute that we have defined. To get the Image Name that we defined above for the last Product, you could use:
let imageName = StoreManager.shared.getAttribute("Image", for: "InAppPurchaseID03")
There are a few events that you will want to listen to so you can respond to user interaction:
purchasesUpdated- Will get called whenever a In-App Purchase is modified by the App Store, such as when a product is successfully purchased or a purchase fails.productRevoked- Is called whenever a Purchase Transaction is revoked by the App Store. TheTransactionis handed to the event.promotedInAppPurchaseEvent- Handles the user interacting with a Promoted In-App Purchase from the App Store. The events is handed theProductand aBoolflag for success or failure of the interaction.
For example, in your App's Main Module, you can do the following:
WindowGroup {
...
}
.onChange(of: scenePhase) { oldScenePhase, newScenePhase in
switch newScenePhase {
case .active:
// Listen for Store Manager Events
StoreManager.shared.productRevoked = {transaction in
// Handle Revoked Purchase events
...
}
StoreManager.shared.promotedInAppPurchaseEvent = {product, successful in
// Handle Promoted In-App Purchase events
...
}
case .inactive:
break
case .background:
// Release Store Manager Events
StoreManager.shared.releaseEventHandlers()
@unknown default:
print("App has entered an unexpected scene: \(oldScenePhase), \(newScenePhase)")
}
}
Before your app quits or enters the background, call StoreManager.shared.releaseEventHandlers() to release any handlers that you attached.
The following functions are the most commonly used:
- purchase -
public func purchase(_ product: Product) async throws -> Transaction?attempts to purchase the given product. - isPurchased - Either
public func isPurchased(_ product: Product) async throws -> Boolorpublic func isPurchased(id:String) -> Boolwill returntrueif a given product is purchased. - productFor -
public func productFor(id:String) -> Product?Returns theProductfor the given In-App Purchase ID. - getAttribute -
public func getAttribute(_ name:String, for productID:String, defaultValue:String = "") -> StringReturns an attribute for the given In-App Purchase ID as defined in theProduct.plistfile included in your App Bundle. - beginRefundProcess -
public func beginRefundProcess(for productID: String, completionHandler: purchaseUpdateHandler? = nil)Begins the refund process for the given In-App Purchase ID.
The Package includes full DocC Documentation for all of its features.
