The AppDNA SDK integrates with Google Play Billing Library 7.0.0 to handle subscription purchases, entitlement management, and purchase restoration. All billing operations use the SUBS product type.
Billing Module
Access billing functionality through the AppDNA.billing module (BillingModule).
Get Products
Retrieve product details for one or more product IDs:
val products = AppDNA.billing.getProducts(listOf("premium_monthly", "premium_yearly"))
// Returns List<Map<String, Any>>
Each product map contains pricing, title, description, and offer details from Google Play.
ProductInfo
| Property | Type | Description |
|---|
id | String | Product identifier |
name | String | Display name |
description | String | Product description |
formattedPrice | String | Localized price string (e.g., “$9.99”) |
priceMicros | Long | Price in micros (e.g., 9990000) |
currencyCode | String | ISO 4217 currency code (e.g., “USD”) |
offerToken | String? | Offer token for the subscription offer |
Purchase a Subscription
Initiate a purchase flow for a specific product:
AppDNA.billing.purchase("premium_monthly")
This triggers the Google Play purchase Activity. The result is delivered through the billing delegate.
The purchase method must be called from an Activity context. The SDK uses the current foreground Activity to launch the Google Play billing flow.
Restore Purchases
Restore previously purchased subscriptions:
AppDNA.billing.restorePurchases()
Restoring purchases queries Google Play for all active subscriptions and updates entitlements accordingly. This is useful after a reinstall or device change.
Entitlements
Get Current Entitlements
Retrieve the list of active entitlements:
val entitlements = AppDNA.billing.getEntitlements()
// Returns List<Map<String, Any>>
Check Active Subscription
Check whether the user has any active subscription:
val hasSubscription = AppDNA.billing.hasActiveSubscription()
// Returns Boolean
Listen for Entitlement Changes
Register a listener to be notified when entitlements change:
AppDNA.billing.onEntitlementsChanged { entitlements ->
for (entitlement in entitlements) {
Log.d("Billing", "Entitlement: ${entitlement.productId}, status: ${entitlement.status}")
}
}
Billing Delegate
Implement AppDNABillingDelegate to receive billing lifecycle callbacks:
import ai.appdna.sdk.billing.AppDNABillingDelegate
import ai.appdna.sdk.billing.TransactionInfo
import ai.appdna.sdk.billing.Entitlement
class MyBillingDelegate : AppDNABillingDelegate {
override fun onPurchaseCompleted(productId: String, transaction: TransactionInfo) {
Log.d("Billing", "Purchase completed: $productId")
}
override fun onPurchaseFailed(productId: String, error: Exception) {
Log.e("Billing", "Purchase failed: $productId", error)
}
override fun onEntitlementsChanged(entitlements: List<Entitlement>) {
Log.d("Billing", "Entitlements updated: ${entitlements.size}")
}
override fun onRestoreCompleted(restoredProducts: List<String>) {
Log.d("Billing", "Restored: ${restoredProducts.joinToString()}")
}
}
Data Types
TransactionInfo
| Property | Type | Description |
|---|
transactionId | String | Google Play transaction identifier |
productId | String | Product identifier |
purchaseDate | String | ISO 8601 purchase timestamp |
environment | String | "production" or "sandbox" |
Entitlement
| Property | Type | Description |
|---|
productId | String | Product identifier |
store | String | Store identifier (e.g., "play_store") |
status | String | Status (e.g., "active", "expired") |
expiresAt | String? | ISO 8601 expiration timestamp |
isTrial | Boolean | Whether this is a free trial |
offerType | String? | Offer type if applicable |
PurchaseResult
The PurchaseResult sealed class represents all possible outcomes of a purchase:
| Variant | Description |
|---|
PurchaseResult.Purchased(entitlement) | Purchase succeeded |
PurchaseResult.Cancelled | User cancelled the purchase flow |
PurchaseResult.Pending | Purchase is pending (e.g., awaiting payment) |
PurchaseResult.Unknown | Unknown result |
PurchaseResult.Failed(error) | Purchase failed with an error |
Auto-Tracked Events
The billing module automatically tracks the following events:
| Event | Triggered When |
|---|
purchase_started | User initiates a purchase |
purchase_completed | Purchase is successfully completed |
purchase_failed | Purchase fails with an error |
purchase_canceled | User cancels the purchase flow |
purchase_pending | Purchase enters pending state |
restore_started | User initiates a restore |
restore_completed | Restore completes successfully |
purchase_restored | An individual purchase is restored |
The SDK automatically acknowledges purchases within 3 days as required by Google Play. If a purchase is not acknowledged within this window, Google Play will automatically refund it. The NativeBillingManager also handles ITEM_ALREADY_OWNED errors by automatically triggering a restore flow.
Next Steps