Lembrete: a partir de 2 de agosto de 2021, todos os novos apps precisarão usar a versão 3 ou mais recente da Biblioteca Play Faturamento. A partir do dia 1º de novembro de 2021, todas as atualizações de apps existentes precisarão usar a versão 3 ou mais recente da Biblioteca Play Faturamento. Saiba mais.

Guia de migração da AIDL para a Google Play Billing Library

Este tópico descreve como migrar de uma integração de faturamento que usa a Linguagem de definição de interface do Android (AIDL). O acesso ao sistema de faturamento do Google Play por meio da AIDL está suspenso. Todas as integrações passarão a usar a biblioteca Google Play Billing no futuro.

Etapas da migração

Importar a Biblioteca do Google Play Faturamento

Primeiro, adicione uma dependência à Biblioteca do Google Play Faturamento. Se você estiver usando o Gradle, é possível adicionar o seguinte ao arquivo build.gradle do seu app:

dependencies {
    def billing_version = "3.0.0"

    implementation "com.android.billingclient:billing:$billing_version"
}

Você pode excluir qualquer código "agrupador", como IabHelper, que pode ter sido copiado do código de referência anterior. A funcionalidade oferecida pelo IabHelper agora faz parte da Biblioteca do Google Play Faturamento.

Remover a permissão com.android.vending.BILLING

A Biblioteca do Google Play Faturamento inclui a permissão com.android.vending.BILLING no manifesto. Não é mais necessário adicionar essa permissão explicitamente no manifesto do seu app.

Conectar-se ao Google Play Faturamento

O BillingClient da Biblioteca do Google Play Faturamento processa o gerenciamento de conexão para você. Para migrar, faça as seguintes mudanças no seu app:

Os exemplos a seguir mostram a possível aparência do app antes e depois dessas mudanças:

Antes

mServiceConn = new ServiceConnection() {
    @Override
    public void onServiceDisconnected(ComponentName name) {
      ...
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      ...
    }
};

Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
List<ResolveInfo> intentServices = mContext.getPackageManager()
    .queryIntentServices(serviceIntent, 0);
if (intentServices != null && !intentServices.isEmpty()) {
    mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
} else {
    // Handle errors.
    ...
}

...

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    IabResult result;
    if (requestCode != mRequestCode || data == null) {
        // Handle errors.
        ...
    }

    int responseCode = getResponseCodeFromIntent(data);
    String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA);
    String dataSignature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE);

    if (resultCode != Activity.RESULT_OK || responseCode != BILLING_RESPONSE_RESULT_OK) {
        // Handle errors.
        ...
    }

    // Process successful purchase.
    ...

    return true;
}

Depois

Kotlin

class MyBillingImpl(private var billingClient: BillingClient) : PurchasesUpdatedListener {

    init {
        billingClient = BillingClient.newBuilder(activity).setListener(this).build()
        billingClient.startConnection(object : BillingClientStateListener {
            override fun onBillingSetupFinished(billingResult: BillingResult?) {
                // Logic from ServiceConnection.onServiceConnected should be moved here.
            }

            override fun onBillingServiceDisconnected() {
                // Logic from ServiceConnection.onServiceDisconnected should be moved here.
            }
        })
    }

    override fun onPurchasesUpdated(
        billingResult: BillingResult?,
        purchases: MutableList<Purchase>?
    ) {
        // Logic from onActivityResult should be moved here.
    }
}

Java

public class MyBillingImpl implements PurchasesUpdatedListener {
    private BillingClient billingClient;
    ...

    public void initialize() {
        billingClient = BillingClient.newBuilder(activity).setListener(this).build();
        billingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                // Logic from ServiceConnection.onServiceConnected should be moved here.
            }

            @Override
            public void onBillingServiceDisconnected() {
                // Logic from ServiceConnection.onServiceDisconnected should be moved here.
            }
        });
    }

    @Override
    public void onPurchasesUpdated(
        @BillingResponse int responseCode, @Nullable List<Purchase> purchases) {
        // Logic from onActivityResult should be moved here.
    }
}

Fazer uma compra

Para iniciar a caixa de diálogo de compras, faça o seguinte:

Os exemplos a seguir mostram a possível aparência do app antes e depois dessas mudanças:

Antes

// Query Skus
String skuToSell = "premium_upgrade";
ArrayList<String> skus = new Arraylist<>();
skus.add(skuToSell);
Bundle querySkus = new Bundle();
querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skus);
Bundle skuDetails = mService.getSkuDetails(3,
                                           mContext.getPackageName(),
                                           itemType,
                                           querySkus);

if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) {
    // Handle errors.
    ...
}

// Launch Buy Flow
Bundle buyIntentBundle = mService.getBuyIntent(3,
                                               mContext.getPackageName(),
                                               skuToSell,
                                               "Inapp",
                                               "");

int response = getResponseCodeFromBundle(buyIntentBundle);
if (response != BILLING_RESPONSE_RESULT_OK) {
    // Handle errors.
    ...
}

PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT);
act.startIntentSenderForResult(pendingIntent.getIntentSender(),
                               requestCode,
                               new Intent(),
                               Integer.valueOf(0),
                               Integer.valueOf(0),
                               Integer.valueOf(0));

// Purchase is handled in onActivityResult illustrated in the previous section.

Depois

Kotlin

val skuToSell = "premium_upgrade"
val skuList = mutableListOf<String>()
skuList.add(skuToSell)
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
billingClient.querySkuDetailsAsync(params.build(),
  object : SkuDetailsResponseListener {
    override fun onSkuDetailsResponse(
      billingResult: BillingResult?, skuDetailsList: MutableList<SkuDetails>?) {
        // Process the result.
        }
    })

// SkuDetails object obtained above.
val skuDetails = ...
val purchaseParams = BillingFlowParams.newBuilder()
  .setSkuDetails(skuDetails)
   .build()

billingClient.launchBillingFlow(activity, purchaseParams)

// Purchase is handled in onPurchasesUpdated illustrated in the previous section

Java

String skuToSell = "premium_upgrade";
List<String> skuList = new ArrayList<> ();
skuList.add(skuToSell);
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
    new SkuDetailsResponseListener() {
        @Override
        public void onSkuDetailsResponse(BillingResult billingResult,
                                         List<SkuDetails> skuDetailsList) {
            // Process the result.
            ...
        }
    });

// SkuDetails object obtained above.
SkuDetails skuDetails = ...;

BillingFlowParams purchaseParams =
    BillingFlowParams.newBuilder()
            .setSkuDetails(skuDetails)
            .build();

mBillingClient.launchBillingFlow(mActivity, purchaseParams);

// Purchase is handled in onPurchasesUpdated illustrated in the previous section.

Consumir compras

Para consumir compras usando a Google Play Billing Library, faça o seguinte:

Os exemplos a seguir mostram a possível aparência do app antes e depois dessas mudanças:

Antes

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    int responseCode = data.getIntExtra(RESPONSE_CODE);
    JSONObject purchaseData =
        new JSONObject(data.getStringExtra("INAPP_PURCHASE_DATA"));

    String token = purchaseData.get("purchaseToken");

    ...

    // Consume purchase
    int response = mService.consumePurchase(3, mContext.getPackageName(), token);
    if (response != BILLING_RESPONSE_RESULT_OK) {
        // Handle errors.
        ...
    }

    // Handle successful consumption.
}

Depois

Kotlin

class MyBillingImpl(private val billingClient: BillingClient) :
        ... , ConsumeResponseListener {

  fun consumePurchase(purchaseToken: String) {
    val consumeParams = ConsumeParams
      .newBuilder()
      .setPurchaseToken(purchaseToken)
      .build()
  }

  override fun onConsumeResponse(
    billingResult: BillingResult?,
    purchaseToken: String?) {
      // Handle consumption
    }
 }

Java

public class MyBillingImpl implements ..., ConsumeResponseListener {
    private BillingClient billingClient;
    ...

    public void consumePurchase(String purchaseToken) {
        ConsumeParams consumeParams =
        ConsumeParams.newBuilder()
                .setPurchaseToken(purchaseToken)
                .build();
    }

    @Override
    void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
        // Handle consumption.
        ...
    }
}

Confirmar compras

A partir da versão 2.0 da Biblioteca Google Play Faturamento, o app precisa consumir ou confirmar todas as compras.

Se você não consumir ou confirmar uma compra em até três dias, o Google revogará a compra automaticamente e reembolsará o usuário. Para ver mais informações, consulte Confirmar uma compra.

Reconhecer compras fora do aplicativo

Para migrar o gerenciamento de compras fora do aplicativo para a Biblioteca do Google Play Faturamento, faça o seguinte:

Antes, ao integrar o Google Play Faturamento com a AIDL, o app precisava registrar um listener para receber a intent com.android.vending.billing.PURCHASES_UPDATED para gerenciar compras feitas fora do app.

Com a Biblioteca do Google Play Faturamento, o primeiro passo para garantir que todas as compras fora do app sejam reconhecidas é sempre chamar queryPurchases() no callback onResume(). Enquanto seu app está em execução, a biblioteca detecta automaticamente as compras fora do aplicativo e envia uma notificação por meio do PurchasesUpdatedListener.

Processar transações pendentes

A partir da versão 2.0 da Biblioteca do Google Play Faturamento, o app precisa processar transações pendentes que exigem outras ações após a compra antes de conceder titularidade. Por exemplo, um usuário pode escolher comprar seu produto em uma loja física com dinheiro. Isso significa que a transação será concluída fora do seu app. Em casos como esse, a titularidade só pode ser concedida após o usuário ter concluído a transação.

Para ver mais informações, consulte Compatibilidade com transações pendentes.

Payload do desenvolvedor

Historicamente, o payload do desenvolvedor tem sido usado para várias finalidades, incluindo a prevenção de fraudes e a atribuição de compras ao usuário correto. Considerando que agora a Biblioteca do Google Play Faturamento é compatível com esses casos de uso, o uso do payload do desenvolvedor foi suspenso a partir da versão 2.2 dessa biblioteca. Para ver mais informações, consulte payload do desenvolvedor.

Mensagens de erro detalhadas

A partir da versão 2.0 da Biblioteca do Google Play Faturamento, todos os erros têm mensagens correspondentes relacionadas à depuração. Você pode ver essas mensagens chamando BillingResult.getDebugMessage().