Android
Xsolla Mobile SDK requires very few steps to get a working integration, which normally consists of:
- Configuration and initialization
- Launching a purchasing flow
- Awarding the purchased content to the user (i.e. consumption)
Here is a fully-fledged example implementation that achieves the aforementioned functionality in just under 150 lines of code:
package com.example.yoursdkintegration;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.xsolla.android.mobile.*;
import com.xsolla.android.mobile.common.LogLevel;
import java.util.Arrays;
import java.util.List;
public class YourSDKIntegrationActivity extends Activity {
private static final String TAG = "YourSDKIntegration";
@Nullable
private BillingClient mBillingClient = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Config.Common configCommon = Config.Common.getDefault()
.withDebugEnabled(true)
.withLogLevel(LogLevel.VERBOSE)
.withSandboxEnabled(true);
final Config.Integration configIntegration = Config.Integration.forXsolla(
Config.Integration.Xsolla.Authentication.forAutoJWT(
ProjectId.parse(77640).getRight(),
LoginUUID.parse("026201e3-7e40-11ea-a85b-42010aa80004").getRight()
)
);
final Config.Payments configPayments = Config.Payments.getDefault();
final Config config = new Config(
configCommon,
configIntegration,
configPayments
);
mBillingClient = BillingClient.newBuilder(this)
.setConfig(config)
.setListener(new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(
@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases
) {
if (billingResult.isSuccess() && purchases != null) {
for (int i = 0; i < purchases.size(); ++i) {
final ConsumeParams consumeParams = ConsumeParams.newBuilder()
.setPurchaseToken(purchases.get(i).getPurchaseToken())
.build();
mBillingClient.consumeAsync(consumeParams, new ConsumeResponseListener() {
@Override
public void onConsumeResponse(
@NonNull BillingResult billingResult, String purchaseToken
) {
Log.d(TAG,
"Purchase consumption response: " +
billingResult.getResponseCode()
);
}
});
}
} else {
Log.e(TAG,
"Purchase consumption response: " +
billingResult.getResponseCode()
);
}
}
})
.build();
mBillingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingServiceDisconnected() {
Log.d(TAG, "Disconnected.");
}
@Override
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
if (billingResult.isSuccess()) {
final QueryProductDetailsParams queryProductDetailsParams =
QueryProductDetailsParams.newBuilder()
.setProductList(Arrays.asList(
QueryProductDetailsParams.Product.newBuilder()
.setProductId("key_1")
.setProductType(BillingClient.ProductType.INAPP)
.build()
))
.build();
mBillingClient.queryProductDetailsAsync(
queryProductDetailsParams, new ProductDetailsResponseListener() {
@Override
public void onProductDetailsResponse(
@NonNull BillingResult billingResult,
@Nullable List<ProductDetails> productDetailsList
) {
if (billingResult.isSuccess() && productDetailsList != null &&
!productDetailsList.isEmpty()) {
// We'll just use the very first element on the list, but you'd normally
// want to handle the rest of the product details as well.
final ProductDetails productDetails = productDetailsList.get(0);
// Create parameters for the purchasing flow..
final BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(Arrays.asList(
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.build()
))
.build();
// Initiate a purchasing flow.
mBillingClient.launchBillingFlow(
YourSDKIntegrationActivity.this, billingFlowParams
);
} else {
Log.e(TAG,
"Received an invalid product details response: " +
billingResult.getResponseCode()
);
}
}
}
);
} else {
Log.e(TAG, "Failed to connect.");
}
}
});
}
}