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
ReplaceAppcoinsBillingClient
withAptoideBillingClient
using the new builder pattern. -
Update Purchase Listener
Update thePurchasesUpdatedListener
to handleBillingResult
instead of integer for the ResponseCode. -
Update Purchase Querying Logic
ReplacequeryPurchases(SkuType)
withqueryPurchasesAsync(QueryPurchasesParams)
. -
Migrate Product Querying Logic
ReplacequerySkuDetailsAsync
withqueryProductDetailsAsync
, usingQueryProductDetailsParams
to define the type of Products to be searched and receiveProductDetails
instead ofSkuDetails
. -
Update Purchase Flow
Replace direct SKU-based purchases withBillingFlowParams
usingProductDetailsParams
. -
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.Purchase
New Imports:
import com.aptoide.sdk.billing.Purchase
2. 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
AppcoinsBillingClient
withAptoideBillingClient
- Replace
AppCoinsBillingStateListener
withAptoideBillingClientStateListener
- Use
BillingResult
instead 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
SkuDetailsParams
withQueryProductDetailsParams
- Replace
SkuType
withProductType
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
ProductDetails
instead 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 about 1 month ago