Android Dev Summit, October 23-24: two days of technical content, directly from the Android team. Sign-up for livestream updates.

Implementar faturamento no aplicativo

O faturamento no aplicativo no Google Play fornece uma interface simples e direta para enviar solicitações e gerenciar transações de faturamento no aplicativo usando o Google Play. As informações abaixo tratam dos fundamentos de como fazer chamadas do serviço de faturamento no aplicativo pelo seu aplicativo usando a versão 3 da API.

Observação: Para ver uma implementação completa e saber como testar seu aplicativo, consulte a aula de treinamento Como vender produtos no aplicativo. A aula oferece uma amostra completa de aplicativo com faturamento no aplicativo, inclusive aulas adicionais sobre como lidar com tarefas chave relacionadas a configuração de conexão, envio de solicitações de faturamento e processamento de respostas do Google Play, além de gerenciamento do encadeamento de segundo plano para que seja possível fazer chamadas de Faturamento no aplicativo a partir da atividade principal.

Antes de começar, não deixe de ler a Visão geral do faturamento no aplicativo para conhecer melhor os conceitos que facilitarão a implementação do Faturamento no aplicativo.

Para implementar o Faturamento no aplicativo no seu aplicativo, você deve fazer o seguinte:

  1. Adicione a biblioteca do Faturamento no aplicativo ao seu projeto.
  2. Atualize o arquivo AndroidManifest.xml.
  3. Crie um ServiceConnection e vincule-o a IInAppBillingService.
  4. Envie solicitações de faturamento no aplicativo pelo aplicativo a IInAppBillingService.
  5. Trate as respostas de faturamento no aplicativo do Google Play.

Adicionar o arquivo AIDL ao projeto

IInAppBillingService.aidl é um arquivo de Linguagem de definição de interface Android (AIDL, na sigla em inglês) que define a interface para o serviço da versão 3 do Faturamento no aplicativo. Você usará essa interface para fazer solicitações de faturamento invocando chamadas ao método IPC.

Para obter o arquivo AIDL:

  1. Abra o Android SDK Manager.
  2. No SDK Manager, expanda a seção Extras.
  3. Selecione Google Play Billing Library.
  4. Clique em Install packages para baixar.

O arquivo IInAppBillingService.aidl será instalado em <sdk>/extras/google/play_billing/.

Para adicionar o AIDL ao projeto:

  1. Baixe a Google Play Billing Library para o projeto Android:
    1. Selecione Tools > Android > SDK Manager.
    2. Em Appearance & Behavior > System Settings > Android SDK, selecione a guia SDK Tools para selecionar e baixar a Google Play Billing Library.
  2. Em seguida, copie o arquivo IInAppBillingService.aidl para o projeto.
    • Se estiver usando Android Studio:
      1. Navegue para src/main na janela de ferramentas do projeto.
      2. Selecione File > New > Directory, digite aidl na janela New Directory e clique em OK.
      3. Selecione File > New > Package, digite com.android.vending.billing na janela New Package e selecione OK.
      4. Usando o explorador de arquivos do seu sistema operacional, navegue para <sdk>/extras/google/play_billing/, copie o arquivo IInAppBillingService.aidl e cole-o no pacote com.android.vending.billing do projeto.
    • Se estiver desenvolvendo em um ambiente diferente do Android Studio: Crie a pasta /src/com/android/vending/billing e copie o arquivo IInAppBillingService.aidl para dentro dela. Coloque o arquivo AIDL no projeto e use a ferramenta Gradle para compilar o projeto de forma que o arquivo IInAppBillingService.java seja gerado.
  3. Compile o aplicativo. Você verá um arquivo gerado com nome de IInAppBillingService.java na pasta /gen do projeto.

Atualizar o manifesto do aplicativo

O faturamento no aplicativo depende do aplicativo Google Play, que lida com toda a comunicação entre o aplicativo e o servidor do Google Play. Para usar o aplicativo Google Play, o seu aplicativo deve solicitar a permissão correta. É possível fazer isso adicionando a permissão com.android.vending.BILLING ao arquivo AndroidManifest.xml. Se o aplicativo não declarar a permissão do Faturamento no aplicativo, mas tentar enviar solicitações de faturamento, o Google Play as rejeitará e responderá com um erro.

Para dar ao aplicativo a permissão necessária, adicione esta linha no arquivo AndroidManifest.xml:

<uses-permission android:name="com.android.vending.BILLING" />

Criar um ServiceConnection

Seu aplicativo deve ter um ServiceConnection para facilitar a troca de mensagens entre ele e o Google Play. No mínimo, seu aplicativo deve fazer o seguinte:

  • Vincular-se a IInAppBillingService.
  • Enviar solicitações de faturamento (na forma de chamadas ao método IPC) ao aplicativo Google Play.
  • Lidar com mensagens de resposta síncronas retornadas para cada solicitação de faturamento.

Vincular a IInAppBillingService

Para estabelecer conexão com o serviço de Faturamento no aplicativo no Google Play, implemente um ServiceConnection para vincular sua atividade a IInAppBillingService. Modifique os métodos onServiceDisconnected e onServiceConnected para obter uma referência à instância IInAppBillingService depois de estabelecida a conexão.

IInAppBillingService mService;

ServiceConnection mServiceConn = new ServiceConnection() {
   @Override
   public void onServiceDisconnected(ComponentName name) {
       mService = null;
   }

   @Override
   public void onServiceConnected(ComponentName name,
      IBinder service) {
       mService = IInAppBillingService.Stub.asInterface(service);
   }
};

No método onCreate da sua atividade, realize a vinculação chamando o método bindService. Passe ao método uma Intent que referencie o serviço de Faturamento no aplicativo e uma instância de ServiceConnection que você criou e defina, explicitamente, o nome do pacote de destino do intent como com.android.vending — o nome do pacote do aplicativo Google Play.

Atenção: Para proteger a segurança das transações de faturamento, sempre certifique-se de definir o nome do pacote de destino do intent explicitamente como com.android.vending usando setPackage(), conforme exibido no exemplo abaixo. Definir o nome do pacote explicitamente garante que somente o aplicativo Google Play possa gerenciar as solicitações de faturamento do seu aplicativo, evitando que outros aplicativos as interceptem.

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  Intent serviceIntent =
      new Intent("com.android.vending.billing.InAppBillingService.BIND");
  serviceIntent.setPackage("com.android.vending");
  bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
}

Agora você pode usar a referência a mService para se comunicar com o serviço do Google Play.

Importante: Lembre-se de se desvincular do serviço de Faturamento no aplicativo quando terminar tudo na Activity. Se você não desvincular, a conexão aberta ao serviço pode fazer o desempenho do seu dispositivo cair muito. Este exemplo mostra como realizar a operação de desvinculação em uma conexão de serviço a Faturamento no aplicativo chamada mServiceConn modificando o método onDestroy da atividade.

@Override
public void onDestroy() {
    super.onDestroy();
    if (mService != null) {
        unbindService(mServiceConn);
    }
}

Para ver uma implementação completa de uma conexão de serviço que vincule-se a IInAppBillingService, consulte a aula Vender produtos no aplicativo e o exemplo associado.

Fazer solicitações de faturamento no aplicativo

Quando o aplicativo está conectado ao Google Play, é possível dar início a solicitações de compra de produtos internos do aplicativo. O Google Play fornece uma interface de finalização da compra para que os usuários insiram o método de pagamento, assim o seu aplicativo não precisa lidar diretamente com transações de pagamento. Quando se compra um item, o Google Play reconhece que o usuário detém esse item e impede-o de comprar outro item como o mesmo ID de produto até consumir o já comprado. É possível controlar como o item é consumido no aplicativo e notificar o Google Play para disponibilizar o item para compra novamente. Você ainda pode consultar o Google Play para recuperar rapidamente a lista de compras que foram feitas pelo usuário. Isso é útil, por exemplo, quando se quer restaurar as compras do usuário assim que ele inicializa o aplicativo.

Consultar itens disponíveis para compra

No aplicativo, você pode consultar os detalhes do item no Google Play usando a In-app Billing Version 3 API. Para passar uma solicitação ao serviço de faturamento no aplicativo, crie um Bundle que contenha uma ArrayList de strings de IDs de produto com a chave “ITEM_ID_LIST”, em que cada string é um ID de produto de um item comprável.

ArrayList<String> skuList = new ArrayList<String> ();
skuList.add("premiumUpgrade");
skuList.add("gas");
Bundle querySkus = new Bundle();
querySkus.putStringArrayList(“ITEM_ID_LIST”, skuList);

Para obter essas informações no Google Play, chame o método getSkuDetails na In-app Billing Version 3 API e passe ao método a versão da API de Faturamento no aplicativo (“3”), o nome do pacote do aplicativo chamador, o tipo da compra (“inapp”) e o Bundle que você criou.

Bundle skuDetails = mService.getSkuDetails(3,
   getPackageName(), "inapp", querySkus);

Se a solicitação for bem-sucedida, o Bundle retornado terá um código de resposta de BILLING_RESPONSE_RESULT_OK (0).

Aviso: Não chame o método getSkuDetails no encadeamento principal. Chamar esse método aciona uma solicitação de rede que pode bloquear o encadeamento principal. Em vez disso, crie um encadeamento separado e chame o método getSkuDetails por esse encadeamento.

Para ver todos os códigos de resposta possíveis do Google Play, consulte Referência de Faturamento no aplicativo.

Os resultados da consulta ficam armazenados em uma ArrayList de string com a chave DETAILS_LIST. As informações de compra são armazenadas na String no formato JSON. Para ver os tipos de informação retornados, consulte Referência de Faturamento no aplicativo.

Neste exemplo, você está recuperando o preço dos seus itens internos do aplicativo a partir do Bundle de skuDetails retornado do snippet anterior.

int response = skuDetails.getInt("RESPONSE_CODE");
if (response == 0) {
   ArrayList<String> responseList
      = skuDetails.getStringArrayList("DETAILS_LIST");

   for (String thisResponse : responseList) {
      JSONObject object = new JSONObject(thisResponse);
      String sku = object.getString("productId");
      String price = object.getString("price");
      if (sku.equals("premiumUpgrade")) mPremiumUpgradePrice = price;
      else if (sku.equals("gas")) mGasPrice = price;
   }
}

Comprar um item

Para dar início a uma solicitação de compra no seu aplicativo, chame o método getBuyIntent no serviço de Faturamento no aplicativo. Passe ao método a versão da In-app Billing API (“3”), o nome do pacote do aplicativo chamador, o ID de produto do item que se deseja comprar, o tipo de compra (“inapp” ou “subs”) e uma string developerPayload. A string developerPayload é usada para especificar argumentos adicionais que você eventualmente queira que o Google Play envie de volta com as informações da compra.

Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
   sku, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");

Se a solicitação for bem-sucedida, o Bundle retornado terá um código de resposta de BILLING_RESPONSE_RESULT_OK (0) e uma PendingIntent, que você pode usar para iniciar o fluxo de compra. Para ver todos os códigos de resposta possíveis no Google Play, consulte Referência de Faturamento no aplicativo. Em seguida, extraia uma PendingIntent do Bundle da resposta com a chave BUY_INTENT.

PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");

Para concluir a transação de compra, chame o método startIntentSenderForResult e use a PendingIntent que você criou. Neste exemplo, você está usando um valor arbitrário de 1001 para o código da solicitação.

startIntentSenderForResult(pendingIntent.getIntentSender(),
   1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0),
   Integer.valueOf(0));

O Google Play envia uma resposta à PendingIntent ao método onActivityResult do seu aplicativo. O método onActivityResult terá um código de resultado de Activity.RESULT_OK (1) ou Activity.RESULT_CANCELED (0). Para ver os tipos de informação de pedido retornados na Intent de resposta, consulte Referência de Faturamento no aplicativo.

Os dados de compra do pedido são uma string em formato JSON mapeada para a chave INAPP_PURCHASE_DATA na Intent de resposta, por exemplo:

'{
   "orderId":"GPA.1234-5678-9012-34567",
   "packageName":"com.example.app",
   "productId":"exampleSku",
   "purchaseTime":1345678900000,
   "purchaseState":0,
   "developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
   "purchaseToken":"opaque-token-up-to-1000-characters"
 }'

Observação: O Google Play gera um token para a compra. Esse token é uma sequência de caracteres opaca que pode ter até 1.000 caracteres. Passe todo o token a outros métodos, como quando se consome a compra, conforme descrito em Consumir uma compra. Não abrevie nem trunque esse token: você deve salvar e retornar todo o token.

Continuando o exemplo anterior, você recebe o código de resposta, os dados da compra e a assinatura com a Intent de resposta.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   if (requestCode == 1001) {
      int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
      String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
      String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");

      if (resultCode == RESULT_OK) {
         try {
            JSONObject jo = new JSONObject(purchaseData);
            String sku = jo.getString("productId");
            alert("You have bought the " + sku + ". Excellent choice,
               adventurer!");
          }
          catch (JSONException e) {
             alert("Failed to parse purchase data.");
             e.printStackTrace();
          }
      }
   }
}

Recomendação de segurança: Ao enviar uma solicitação de compra, crie um token de string que identifique exclusivamente essa solicitação de compra e contenha esse token no developerPayload. Você pode usar uma string gerada aleatoriamente como o token. Ao receber a resposta de compra do Google Play, não deixe de verificar a assinatura dos dados retornada, o orderId e a string developerPayload. Para maior segurança, você deve realizar a verificação no seu próprio servidor protegido. Certifique-se de verificar se o orderId é um valor único que você ainda não tenha processado e que a string developerPayload corresponda ao token enviado anteriormente com a solicitação de compra.

Consultar itens comprados

Para obter informações sobre compras feitas por um usuário no seu aplicativo, chame o método getPurchases no serviço da versão 3 do Faturamento no aplicativo. Passe ao método a versão da In-app Billing API (“3”), o nome do pacote do aplicativo chamador e o tipo de compra “inapp” ou “subs”).

Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);

O serviço do Google Play retornará somente as compras feitas pela conta de usuário que está com acesso ativo no dispositivo no momento. Se a solicitação for bem-sucedida, o Bundle retornado terá um código de resposta de 0. O Bundle de resposta também contém uma lista de IDs de produto, uma lista dos detalhes do pedido de cada compra e as assinaturas de cada compra.

Para melhorar o desempenho, o serviço de Faturamento no aplicativo retorna somente até 700 produtos que o usuário detém quando getPurchase é chamado pela primeira vez. Se o usuário possuir um maior número de produtos, o Google Play incluirá um token de string mapeado para a chave INAPP_CONTINUATION_TOKEN no Bundle de resposta, indicando que é possível recuperar mais produtos. Em seguida, o aplicativo pode chamar getPurchases e passar esse token como um argumento. O Google Play continuará retornando um token de continuação no Bundle de resposta até que todos os produtos de posse do usuário sejam enviados ao aplicativo.

Para saber mais sobre os dados retornados por getPurchases, consulte Referência de Faturamento no aplicativo. O exemplo a seguir mostra como recuperar esses dados da resposta.

int response = ownedItems.getInt("RESPONSE_CODE");
if (response == 0) {
   ArrayList<String> ownedSkus =
      ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
   ArrayList<String>  purchaseDataList =
      ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
   ArrayList<String>  signatureList =
      ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
   String continuationToken =
      ownedItems.getString("INAPP_CONTINUATION_TOKEN");

   for (int i = 0; i < purchaseDataList.size(); ++i) {
      String purchaseData = purchaseDataList.get(i);
      String signature = signatureList.get(i);
      String sku = ownedSkus.get(i);

      // do something with this purchase information
      // e.g. display the updated list of products owned by user
   }

   // if continuationToken != null, call getPurchases again
   // and pass in the token to retrieve more items
}

Consumir uma compra

No Google Play, é possível usar a In-app Billing Version 3 API para controlar a posse de produtos comprados no aplicativo. Quando um produto interno de um aplicativo é comprado, considera-se que ele seja “detido” e não possa ser comprado pelo Google Play. É preciso enviar uma solicitação de consumo para o produto interno do aplicativo antes de o Google Play disponibilizá-lo para compra novamente.

Importante: Produtos internos do aplicativo gerenciados são consumíveis, mas assinaturas não.

A forma de usar o mecanismo de consumo no seu aplicativo é você quem decide. Normalmente, implementa-se o consumo para produtos internos do aplicativo com benefícios temporários, que os usuários podem querer comprar diversas vezes (por exemplo, moeda do jogo ou equipamentos). Normalmente não se implementa consumo para produtos internos do aplicativo que sejam comprados uma vez e forneçam efeito permanente (por exemplo, uma melhoria premium).

Para registrar o consumo de uma compra, envie o método consumePurchase para o serviço de Faturamento no aplicativo e passe o valor da string purchaseToken que identifica a compra a remover. O purchaseToken é parte dos dados retornados na string INAPP_PURCHASE_DATA pelo serviço do Google Play após uma solicitação de compra bem-sucedida. Neste exemplo, você está registrando o consumo de um produto identificado com o purchaseToken na variável token.

int response = mService.consumePurchase(3, getPackageName(), token);

Aviso: Não chame o método consumePurchase no encadeamento principal. Chamar esse método aciona uma solicitação de rede que pode bloquear o encadeamento principal. Em vez disso, crie um encadeamento separado e chame o método consumePurchase por esse encadeamento.

É sua responsabilidade controlar e acompanhar como o produto interno do aplicativo é fornecido ao usuário. Por exemplo, se o usuário compra moeda do jogo, você deve atualizar o inventário do jogador com a quantia em moeda comprada.

Recomendação de segurança: Você deve enviar uma solicitação de consumo antes de fornecer o benefício da compra consumível no aplicativo ao usuário. Certifique-se de receber uma resposta de consumo bem-sucedida do Google Play antes de fornecer o item.

Implementar assinaturas

Iniciar um fluxo de compra de uma assinatura é semelhante a iniciar o fluxo de compra de um produto, com a exceção de que o tipo de produto deve ser definido como “subs”. O resultado da compra é fornecido ao método onActivityResult da sua atividade, exatamente como no caso de produtos internos do aplicativo.

Bundle bundle = mService.getBuyIntent(3, "com.example.myapp",
   MY_SKU, "subs", developerPayload);

PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT);
if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) {
   // Start purchase flow (this brings up the Google Play UI).
   // Result will be delivered through onActivityResult().
   startIntentSenderForResult(pendingIntent, RC_BUY, new Intent(),
       Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
}

Para consultar assinaturas ativas, use o método getPurchases novamente com o parâmetro “tipo de produto” definido como “subs”.

Bundle activeSubs = mService.getPurchases(3, "com.example.myapp",
                   "subs", continueToken);

A chamada retorna um Bundle com todas as assinaturas ativas de posse do usuário. Quando uma assinatura expira sem renovação, ela não aparece mais no Bundle retornado.

Proteger seu aplicativo

Para ajudar a garantir a integridade das informações de transação enviadas ao aplicativo, o Google Play assina a string JSON que contém os dados de resposta da ordem de compra. O Google Play usa a chave privada associada ao aplicativo no Developer Console para criar essa assinatura. O Developer Console gera um par de chaves RSA para cada aplicativo.

Observação: para encontrar a parte pública da chave deste par de chaves, acesse os detalhes do seu aplicativo no Developer Console, clique em Services & APIs e procure o campo chamado Your License Key for This Application.

A chave pública RSA codificada com Base64 gerada pelo Google Play está no formato codificado em binário X.509 subjectPublicKeyInfo DER SEQUENCE. É a mesma chave pública usada na licença do Google Play.

Quando o aplicativo recebe essa resposta assinada, é possível usar a parte pública da chave do seu par de chaves RSA para verificar a assinatura. Ao realizar a verificação de assinatura, pode-se detectar respostas adulteradas ou falsificadas. É possível realizar essa etapa de verificação de assinatura no aplicativo, mas, se o aplicativo se conecta a um servidor remoto protegido, recomendamos realizar a verificação nesse servidor.

Para obter mais informações sobre as práticas recomendadas de segurança e projeto, consulte Segurança e projeto.