Supported on: iOS SDK
1.0.61+ · Android SDK 1.0.33+ · Flutter SDK 1.0.3+com.appdna.sdk/billing MethodChannel and the com.appdna.sdk/entitlements EventChannel.
Configuration
Set the billing provider when configuring the SDK:AppDNABillingProvider Options
Billing Module
Access the billing module throughAppDNA.billing, which returns an AppDNABilling instance:
Get Products
Fetch product information for one or more product identifiers:List<ProductInfo>.
ProductInfo
Purchase a Product
Initiate a purchase for a product:PurchaseResult.
PurchaseResult
Transaction Map Keys
Thetransaction payload delivered to onPurchaseCompleted (and AppDNAPaywallDelegate.onPaywallPurchaseCompleted) is a Map<String, dynamic> with the following store-verified keys:
The
offerToken parameter on purchase(...) is optional. On Android, pass the offer token from ProductInfo.offerToken to select a specific subscription offer. On iOS, this parameter is ignored. For Apple promotional offers (iOS), the SDK auto-applies any offer associated with the product in App Store Connect.Server-side receipt verification is performed automatically by the SDK. You do not need to send receipts to your own server for validation.
Restore Purchases
Restore previously purchased products (e.g., after reinstalling the app or switching devices):List<Entitlement>.
Apple requires that all apps with in-app purchases include a restore mechanism. Call
restorePurchases() when the user taps a “Restore Purchases” button.Check Active Subscription
Check whether the user has an active subscription:bool.
Get Entitlements
Retrieve all current entitlements for the user:List<Entitlement>.
Entitlement
Real-Time Entitlement Changes
Stream
Listen for entitlement changes in real time via thecom.appdna.sdk/entitlements EventChannel:
Stream<List<Entitlement>>.
Callback
Alternatively, register a callback for entitlement changes:AppDNABillingDelegate
Implement theAppDNABillingDelegate abstract class for fine-grained billing lifecycle callbacks:
onPurchaseCompleted(productId, transaction)— fires after the store completes a purchase (paywall, directAppDNA.billing.purchase(...), or transaction queue retry). Thetransactionmap shape is documented above.onPurchaseFailed(productId, error)— fires on store-side failure (user cancel, payment declined, network). Theerroris a typedObject(usuallyMap<String, dynamic>from native withmessage+typekeys, or a rawString).onEntitlementsChanged(entitlements)— fires whenever the active entitlement set changes (purchase, restore, renewal, expiry, refund). Delivers a list of entitlement maps, each shaped like anEntitlement(productId/store/status/expiresAt/isTrial/offerType) — parse each withEntitlement.fromMap. For strongly-typedEntitlementobjects you can also callAppDNA.billing.getEntitlements()from inside the callback, or subscribe to theAppDNA.billing.onEntitlementsChangedstream instead.onRestoreCompleted(restoredProductIds)— fires when a directAppDNA.billing.restorePurchases()call resolves. Empty list means no prior purchases on file.onBillingUnavailable()— fires when billing is permanently unavailable (Play Services missing or broken). Android-only — it never fires on iOS. Hide paywalls / disable purchase UI when it fires.
AppDNAPaywallDelegate. When a purchase originates from a paywall, the paywall delegate fires onPaywallPurchaseStarted / onPaywallPurchaseCompleted / onPaywallPurchaseFailed. The billing delegate ALSO fires onPurchaseCompleted / onPurchaseFailed for that same purchase — they’re independent observers. Register both if you want paywall-specific UI (banners, confetti) AND a global purchase log; register only the billing delegate if you only care about the eventual state.
Example Implementation
Full Example
Auto-Tracked Events
The SDK automatically tracks the following billing events. You don’t need to callAppDNA.track(...) for any of them.
Android-only events (fired by Play Billing’s subscription lifecycle):
These events flow into the AppDNA Console exactly like any custom event you track yourself, and feed retention / monetization dashboards out of the box.

