-
Notifications
You must be signed in to change notification settings - Fork 4
Billing Integration
AdManageKit provides a comprehensive billing integration module (admanagekit-billing) that simplifies Google Play Billing Library v9 implementation.
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-billing:v4.4.0'
implementation 'com.github.i2hammad.AdManageKit:ad-manage-kit-core:v4.4.0'val products = listOf(
// Consumable (coins, gems)
PurchaseItem("coins_100", TYPE_IAP.PURCHASE, PurchaseCategory.CONSUMABLE),
// Lifetime premium (disables ads)
PurchaseItem("lifetime", TYPE_IAP.PURCHASE, PurchaseCategory.LIFETIME_PREMIUM),
// Remove ads only
PurchaseItem("remove_ads", TYPE_IAP.PURCHASE, PurchaseCategory.REMOVE_ADS),
// Subscription with trial
PurchaseItem("premium_monthly", "free_trial", TYPE_IAP.SUBSCRIPTION)
)class MyApp : Application() {
override fun onCreate() {
super.onCreate()
// Inject your build state (a library AAR always has BuildConfig.DEBUG = false).
// In debug builds this registers a test product and routes purchase()/subscribe()
// to the dev purchase bottom sheet instead of the real Play flow. Call BEFORE initBilling.
AppPurchase.getInstance().setDebugMode(BuildConfig.DEBUG)
AppPurchase.getInstance().initBilling(this, products)
}
}Acknowledgment is automatic.
AppPurchaseacknowledges everyPURCHASEDpurchase before firing its callbacks, on both the new-purchase and restore paths — preventing Google Play's 3-day auto-refund of unacknowledged purchases. OnlyPurchaseState.PURCHASEDgrants entitlement (pending purchases do not). Consumables still require a manualconsumePurchase(productId)after granting.
// In-app purchase
AppPurchase.getInstance().purchase(activity, "remove_ads")
// Subscription
AppPurchase.getInstance().subscribe(activity, "premium_monthly")if (AppPurchase.getInstance().isPurchased()) {
// User has premium (subscription, lifetime, or remove_ads)
}val billing = AppPurchase.getInstance()
val name = billing.getProductName("premium_monthly") // "Monthly Premium"
val description = billing.getProductDescription("premium_monthly")
val hasTrial = billing.hasFreeTrial("premium_monthly") // true/false
val period = billing.getBillingPeriod("premium_monthly") // "P1M"For multi-offer subscriptions, use OfferInfo to read each offer's trial,
introductory, and base phases without parsing ProductDetails manually:
val trial = billing.getTrialOffer("premium_yearly")
trial?.let {
badge.text = "Free for ${it.trialPeriod}" // "P7D"
price.text = "${it.basePrice} / ${it.billingPeriod}"
}
val base = billing.getBaseOffer("premium_yearly") // non-promo offer
val all = billing.getOffers("premium_yearly") // every offersubscribe(activity, subsId) picks the offer for you (the configured trialId,
else Play's last offer), so on a multi-offer product it can charge for the
wrong plan. Pass the offer the user actually tapped:
val offers = billing.getOffers("premium_sub")
billing.subscribe(activity, offers[selectedIndex]) // exactly this planSee Subscription Offers for offer lookup, price normalization, savings badges, trial eligibility, and one-time product offers.
billing.setProductDetailsListener(object : ProductDetailsListener {
override fun onProductDetailsLoaded(
productType: String,
loaded: List<ProductDetails>,
unfetched: List<UnfetchedProduct>,
) {
unfetched.forEach { Log.e("Billing", "${it.productId}: status ${it.statusCode}") }
}
override fun onProductDetailsFailed(productType: String, responseCode: Int, debugMessage: String?) { }
})Register it before initBilling. Products land in unfetched when the id is
misspelled, the product is inactive in Play Console, or the signed-in account
cannot see the release track. isProductDetailsLoaded(id) and
areAllProductDetailsLoaded() distinguish "missing" from "not loaded yet".
// Google-recommended hashed identifiers — never raw account data. Max 64 chars.
billing.setObfuscatedAccountId(sha256(userId))
billing.setObfuscatedProfileId(sha256(profileId))
// Required EU disclosure when prices are personalized per user.
billing.setOfferPersonalized(true)Applied to every flow the library launches (purchase, subscribe,
updateSubscription). Set after sign-in; pass null on sign-out.
- Purchase Categories - Product classification system
- Subscription Offers - Offers, trials, intro pricing, price comparison
- Consumable Products - Handling consumables with manual consumption
- Subscriptions - Subscription lifecycle management
- Subscription Upgrades - Upgrade/downgrade handling
- Purchase History - Tracking purchases with PurchaseHistoryListener
- PurchaseResult API - Full API reference for PurchaseResult
- Server Verification - Server-side purchase verification
AdManageKit v3.3.4 | GitHub | API Docs | Report Issue | Buy me a coffee