Postado por Bruno Oliveira, Developer Relations, Android, Google.

Quando dizemos in-app billing em Android, o que queremos dizer é a venda de itens virtuais e serviços a partir de um aplicativo. Desde que as ferramentas de in-app billing do Android foram lançadas, seu uso vem crescendo constantemente: cada vez mais apps estão implementando modelos flexíveis de monetização, incluindo itens virtuais e assinaturas de serviços.

Naturalmente, nem todo aplicativo tem a rentabilidade como objetivo! Existem aplicativos dos mais variados tipos e com os mais variados propósitos, e não estou de forma alguma afirmando que todo desenvolvedor deve implementar vendas de itens virtuais. Porém, para aqueles onde a rentabilidade é um fator importante, o in-app billing pode ser uma ferramenta incrivelmente efetiva. Aliás, se observarmos uma lista de aplicativos em ordem de rentabilidade, veremos que praticamente todos os apps no topo desse ranking estão utilizando in-app billing.

Quando lançamos esse feature em 2011, adotamos uma API com um modelo assíncrono com múltiplos componentes onde era necessário implementar serviços e broadcast receivers. Porém, numa simplificação significativa da API, lançamos recentemente o in-app billing versão 3, que introduz um modelo síncrono, onde a resposta é recebida imediatamente ao invés de depender de um serviço em background, tornando muito mais fácil escrever uma implementação correta e robusta. Implementar in-app billing no seu aplicativo pode ser mais simples do que você imagina.

Escrever o código de exemplo para o in-app billing versão 3 foi um dos meus projetos recentes, e por isso posso dizer com certo conhecimento que a implementação é bem fácil e até divertida! Esse código de exemplo pode ser encontrado no Android SDK Manager, bastando selecionar Extras, depois Google Play Billing. O código fonte também está publicamente disponível neste repositório.

Então, como começar?

Defina seus itens virtuais

Primeiramente, você deve adicionar itens virtuais ao seu aplicativo no Developer Console (certifique-se de estar utilizando a versão 2, disponível em https://play.google.com/apps/publish/v2, e não a versão antiga). Para isso, basta ir à aba "In-app Products" e adicionar seus itens virtuais. Por exemplo, vamos supor que você quer adicionar um item virtual que é um "upgrade premium" do seu aplicativo, que destrava conteúdo exclusivo. Então, basta adicionar um novo produto clicando Add New Product, inventar um Product ID (usaremos "premium" nesse exemplo) e selecionar "Managed product" como tipo (o in-app billing version 3 só funciona com managed items ou subscriptions). Após configurar o preço, certifique-se que o item está configurado como "Active" na parte superior da tela.

Após fazer isso, o item deverá estar disponível para uso dentro de algumas horas. Enquanto isso, você pode trabalhar no seu código!

Escreva seu código

Baixe o app de exemplo, que se chama TrivialDrive (novamente, isso pode ser feito pelo Android SDK Manager, em Extras | Google Play Billing). Note que o app de exemplo contém uma série de classes fáceis de reutilizar, no pacote com.example.trivialdrivesample.util. Copie esses arquivos para o seu próprio projeto, e, se desejar, mude o package name.

Na sua Activity, inclua o código em onCreate() para inicializar o in-app billing e já aproveitar para obter uma lista dos itens virtuais que o usuário possui:

// objeto "helper" para in-app billing

IabHelper mHelper;

// caixa com spinner para indicar que estamos trabalhando em algo,
// para que o usuário não perca a paciência conosco...

ProgressDialog mProgressDialog;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


   // spinner que fica na tela enquanto inicializamos:
    mProgressDialog = new ProgressDialog();
    mProgressDialog.setMessage("Aguarde...");


   // chave publica do app
    String base64EncodedPublicKey = "SUA_CHAVE_AQUI";


   // cria o objeto auxiliar IabHelper
    mHelper = new IabHelper(this, base64EncodedPublicKey);

   // inicia o setup
    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
   // esse metodo é invocado quando o setup termina
        public void onIabSetupFinished(IabResult result) {
            if (!result.isSuccess()) {

                // (lidar com erro aqui)
            
   // ...
                return;
            }


            // pede lista dos itens que o usuario possui
            mHelper.queryInventoryAsync(this);
        }
    });

}
Substitua SUA_CHAVE_AQUI pela chave pública do seu aplicativo. Você pode obtê-la no Developer Console, na aba Services & APIs, sob o título "Your license key for this application." Num aplicativo de produção, recomendamos não incluir sua chave literalmente, mas construí-la em tempo de execução a partir de pedaços, encriptá-la, usar XOR e outras operações de bits, etc, para tornar a chave menos óbvia no código compilado do seu aplicativo.

Agora, faça com que sua Activity implemente a interface QueryInventoryFinishedListener. Quando a lista dos itens que o usuário possui tiver sido baixada do servidor, o seguinte método da sua Activity será chamado:

public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
    mProgressDialog.dismiss();

    if (result.isFailure()) {
        complain("Erro ao obter lista de itens: " + result);
        return;
    }

    // Temos o upgrade?
    Purchase premiumPurchase = inventory.getPurchase("premium");
    mIsPremium = (premiumPurchase != null
                      && verifyDeveloperPayload(premiumPurchase));
    if (mIsPremium) {
        // destrava conteúdo premium
        // ....

    }
}

(Obs: falaremos do método verifyDeveloperPayload() a seguir)

Ok, até agora o que temos é um app que detecta, ao iniciar, se o usuário tem ou não o item "premium", que dá direito ao conteúdo exclusivo, e destrava o conteúdo em caso afirmativo. Mas falta algo muito importante (e notaríamos que as vendas não iriam muito bem se lançássemos o app assim). O que falta de tão importante?

Exato, falta permitir que o usuário compre o item!

Para isso, faça um elemento de UI apropriado para seu aplicativo que permita ao usuário iniciar o processo. Nesse exemplo, serei inacreditavelmente criativo e usarei... um botão:

<Button
android:onClick="onBuyClicked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Destravar conteúdo exclusivo" />


E agora escrevemos o método:

final static int RC_REQUEST = 12345;
public void onBuyClicked(View unused) {
    mProgressDialog.show();
    String payload = "SEU_DEVELOPER_PAYLOAD_AQUI";
    mHelper.launchPurchaseFlow(this, "premium", RC_REQUEST,
             this, payload);
}

(Obs: novamente, falaremos sobre developer payload a seguir).

O que esse método faz é iniciar a interface que permite que o usuário compre o item. A constante RC_REQUEST é um inteiro arbitrário usado para comunicação entre Activity's (como ocorre com startActivityForResult()).

Agora fazemos com que a Activity implemente a interface OnIabPurchaseFinishedListener e implementamos o seguinte método, que será chamado quando o processo de compra terminar:

public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
    mProgressDialog.dismiss();
    if (result.isFailure()) {

        // (alertar usuário sobre erro na compra)
        // ....
        return;
    }
    if (!verifyDeveloperPayload(purchase)) {

        // (alertar usuário que houve falha de verificação
        // de autenticidade na compra)
        // ....
        return;
    }

    if (purchase.getSku().equals("premium")) {
        // destrava conteúdo exclusivo
        // ...

}
}

Pronto: agora seu app permite que o usuário compre o conteúdo exclusivo, e detecta automaticamente se o usuário tem acesso ao conteúdo ou não ao iniciar.

Resta agora falar rapidamente sobre duas coisas: developer payload e consumption.

Sobre Developer Payload

Developer payload é uma string arbitrária que você pode especificar no ato da compra, e que será devolvida junto com o produto sempre que você recuperar aquela compra daquele usuário. É uma espécie de tag, que fica permanentemente anexada àquela compra daquele usuário. O uso recomendado desse campo é para determinar se uma compra é legítima -- se, no processo de compra, você colocou o tag "pertence a Bruno Oliveira" e a compra vem com um tag diferente disso, você saberá que a compra não é legítima. E difícil falsificar tags porque a compra (que inclui o tag) vem assinada por uma chave privada no servidor, que é verificada pela sua chave pública (a classe IabHelper faz isso para você). Recomendamos criar developer payloads que estejam vinculados ao usuário que fez a compra, para evitar o ataque onde a mesma compra é "transplantada" para outro dispositivo. Então se o meu gêmeo maligno, Onurb Oliveira (todos temos um gêmeo maligno!), entrar nos arquivos do meu Android e conseguir copiar os dados de compra para o aparelho dele, o app iniciará e verá pelo developer payload que aquela compra não pertence a "Onurb Oliveira" e sim a "Bruno Oliveira".

O que é consumption?

Para terminar, vou só mencionar um conceito importante que é o de consumption, que foi introduzido pela versão 3. Consumir uma compra significa simplesmente fazer com que ela desapareça. Isso deve ser feito para itens que são consumíveis pelo usuário, como por exemplo uma poção mágica no seu jogo -- o usuário compra a poção, e, quando a toma, ele não deve mais ser dono daquela poção. Para isso, basta chamar:

mHelper.consumeAsync(purchase, this);

Onde purchase é a compra da poção. Você será notificado do resultado do consumo através do método onConsumeFinished(), que indicará se houve sucesso ou falha.

Como testar?

Para testar seu aplicativo, você pode usar itens de teste como descrito aqui (link em inglês), ou pode fazer testes usando os itens reais e um cartão de crédito real (lembre-se de reembolsar as compras de teste para que o as despesas não sejam lançadas no seu cartão). Em todo caso, lembre de um fato importante ao testar: você não pode comprar um item virtual usando a mesma conta que o está vendendo! Ou seja, se você publicou seu aplicativo como x@gmail.com, então não poderá tentar comprar itens no aplicativo usando a conta x@gmail.com. Outro ponto importante é ter certeza de que você está assinando o seu APK com a mesma chave que usou para publicar seu aplicativo no Developer Console. Usar a chave de debug (ou qualquer outra chave) não funcionará corretamente, por motivos de segurança.

Para saber mais sobre in-app billing, leia nossa documentação online (em inglês) e não deixe de ler nosso guia passo a passo sobre o assunto (em inglês).