Migration from Legacy AppCoins SDK to new Aptoide SDK
This page helps the developers to migrate from the legacy AppCoins Billing SDK to the newest Aptoide Billing SDK
Overview
This document provides a complete, step-by-step guide to migrate your application from the legacy AppCoins Billing SDK (io.catappult:android-appcoins-billing) to the latest Aptoide Billing SDK (com.aptoide:android-aptoide-billing). The new SDK introduces modernized APIs, cleaner structure, improved compatibility with Android features, and better alignment to the Billing standards in the industry.
Migration Steps Summary
The main steps to have a successful migration are the following:
-
Update SDK Dependency
Replace the AppCoins SDK dependency with the new Aptoide SDK in your Gradle files. -
Refactor Billing Client Initialization
ReplaceAppcoinsBillingClientwithAptoideBillingClientusing the new builder pattern. -
Update Purchase Listener
Update thePurchasesUpdatedListenerto handleBillingResultinstead of integer for the ResponseCode. -
Update Purchase Querying Logic
ReplacequeryPurchases(SkuType)withqueryPurchasesAsync(QueryPurchasesParams). -
Migrate Product Querying Logic
ReplacequerySkuDetailsAsyncwithqueryProductDetailsAsync, usingQueryProductDetailsParamsto define the type of Products to be searched and receiveProductDetailsinstead ofSkuDetails. -
Update Purchase Flow
Replace direct SKU-based purchases withBillingFlowParamsusingProductDetailsParams. -
Refactor Consumption Logic
Replace the oldconsumeAsync(token)method with a new method that usesConsumeParams.
1. Update SDK Dependency
AppCoins SDK:
implementation("io.catappult:android-appcoins-billing:0.9.+")Aptoide SDK:
implementation("com.aptoide:android-aptoide-billing:1.+")Update your build.gradle and sync the project.
Once the project is synced, update all the imports from the Legacy AppCoins Billing SDK to the new Aptoide Billing SDK by replacing appcoins with aptoide, as per example:
Legacy Imports:
import com.appcoins.sdk.billing.PurchaseNew Imports:
import com.aptoide.sdk.billing.Purchase2. Refactor Billing Client Initialization
Legacy Initialization:
val cab = CatapultBillingAppCoinsFactory.BuildAppcoinsBilling(context, publicKey, listener)
cab.startConnection(appCoinsBillingStateListener)CatappultAppcoinsBilling cab = CatapultBillingAppCoinsFactory.BuildAppcoinsBilling(context, publicKey, listener)
cab.startConnection(appCoinsBillingStateListener)New Initialization:
val billingClient = AptoideBillingClient.newBuilder(context)
.setListener(purchasesUpdatedListener)
.setPublicKey(publicKey)
.build()
billingClient.startConnection(aptoideBillingClientStateListener)AptoideBillingClient billingClient = AptoideBillingClient.newBuilder(context)
.setListener(purchasesUpdatedListener)
.setPublicKey(publicKey)
.build();
billingClient.startConnection(aptoideBillingClientStateListener);Changes Required:
- Replace
AppcoinsBillingClientwithAptoideBillingClient - Replace
AppCoinsBillingStateListenerwithAptoideBillingClientStateListener - Use
BillingResultinstead of raw integers for response codes
3. Update Purchase Listener
Legacy:
val purchasesUpdatedListener = PurchasesUpdatedListener { responseCode, purchases ->
if (responseCode == ResponseCode.OK.value) {
for (purchase in purchases) {
// Apply here your Purchase result logic
}
}
}PurchasesUpdatedListener purchasesUpdatedListener = (responseCode, purchases) -> {
if (responseCode == ResponseCode.OK.getValue()) {
for (Purchase purchase : purchases) {
// Apply here your Purchase result logic
}
}
};New:
val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases ->
if (billingResult.responseCode == BillingResponseCode.OK) {
for (purchase in purchases) {
// Apply here your Purchase result logic
}
}
}PurchasesUpdatedListener purchasesUpdatedListener = (billingResult, purchases) -> {
if (billingResult.getResponseCode() == BillingResponseCode.OK) {
for (Purchase purchase : purchases) {
// Apply here your Purchase result logic
}
}
};Highlights:
- Response codes now come from
billingResult.responseCode - Maintain same logic to extract token and handle delivery/consumption
4. Update Purchase Querying Logic
Legacy:
val purchasesResult = cab.queryPurchases(SkuType.inapp)PurchasesResult purchasesResult = cab.queryPurchases(SkuType.inapp)New:
val params = QueryPurchasesParams.newBuilder()
.setProductType(ProductType.INAPP)
.build()
billingClient.queryPurchasesAsync(params) { billingResult, purchases ->
// Handle results
}QueryPurchasesParams params = QueryPurchasesParams.newBuilder()
.setProductType(ProductType.INAPP)
.build();
billingClient.queryPurchasesAsync(params, (billingResult, purchases) -> {
// Handle results
});5. Migrate Product Query Logic
Legacy:
cab.querySkuDetailsAsync(SkuDetailsParams(...), listener)cab.querySkuDetailsAsync(new SkuDetailsParams(...), listener)New:
val params = QueryProductDetailsParams.newBuilder()
.setProductList(
listOf(
Product.newBuilder()
.setProductId("your_product_id")
.setProductType(ProductType.INAPP)
.build()
)
).build()
billingClient.queryProductDetailsAsync(params) { billingResult, productDetailsResult ->
if (billingResult.responseCode == BillingResponseCode.OK) {
for (product in productDetailsResult.productDetailsList) {
// Use product details here
}
}
}QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
.setProductList(
List.of(
Product.newBuilder()
.setProductId("your_product_id")
.setProductType(ProductType.INAPP)
.build()
)
).build();
billingClient.queryProductDetailsAsync(params, (billingResult, productDetailsResult) -> {
if (billingResult.getResponseCode() == BillingResponseCode.OK) {
for (ProductDetails product : productDetailsResult.getProductDetailsList()) {
// Use product details here
}
}
});Notes:
- Replace
SkuDetailsParamswithQueryProductDetailsParams - Replace
SkuTypewithProductType
6. Update Purchase Flow
Legacy:
val billingFlowParams = BillingFlowParams(...)
cab.launchBillingFlow(activity, billingFlowParams)BillingFlowParams billingFlowParams = new BillingFlowParams(...);
cab.launchBillingFlow(activity, billingFlowParams);New:
val productDetailsParams = BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.build()
val billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(listOf(productDetailsParams))
.setObfuscatedAccountId(userId)
.setFreeTrial(true)
.build()
billingClient.launchBillingFlow(activity, billingFlowParams)BillingFlowParams.ProductDetailsParams productParams =
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.build();
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(List.of(productParams))
.setObfuscatedAccountId(userId)
.setFreeTrial(true) // Use this to initiate Free Trials
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);Key Changes:
- Uses
ProductDetailsinstead of raw SKU strings - Adds
setObfuscatedAccountId()for user-level tracking setFreeTrial()handles trial logic
7. Refactor Consumption Logic
Legacy:
cab.consumeAsync(purchase.token, consumeResponseListener)cab.consumeAsync(purchase.getToken(), consumeResponseListener);New:
val consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.consumeAsync(consumeParams, consumeResponseListener)ConsumeParams consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.consumeAsync(consumeParams, consumeResponseListener);Important:
- Always consume purchases within 48 hours
- Subscriptions should also be consumed or acknowledged (via Backend API)
Changes Comparison Table
| Feature | Legacy AppCoins SDK | New Aptoide SDK |
|---|---|---|
| Billint Client Class | AppcoinsBillingClient | AptoideBillingClient |
| Querying Products | querySkuDetailsAsync | queryProductDetailsAsync |
| Purchase Flow Params | BillingFlowParams with SKU | BillingFlowParams with ProductDetails |
| Billing action result | Int values as ResponseCode | Uses BillingResult which contains BillingResponseCode and Debug Message |
| Consumption | consumeAsync(token) | consumeAsync(ConsumeParams) |
FAQ
Where can I find the entire Aptoide Billing SDK Integration documentation?
Our entire documentation for the new Aptoide Billing SDK Integration can be found in here. It contains the most important steps to have a complete and successful integration of our Billing system.
Where can I find the legacy AppCoins Billing SDK Integration documentation?
Our documentation for the legacy Aptoide Billing SDK Integration can be found in here.
Updated 26 days ago
