Cómo implementar facturación integrada

La facturación integrada en Google Play tiene una interfaz simple y directa para enviar solicitudes de facturación integrada y gestionar transacciones de facturación integrada a través de Google Play. En la siguiente información se abarcan aspectos básicos sobre la manera de realizar llamadas de tu aplicación al servicio de facturación integrada con la Version 3 API.

Nota: Para ver una implementación completa y aprender a probar tu aplicación, consulta la clase de capacitación Venta de productos integrados en la aplicación . En esta clase capacitación se ofrece un ejemplo completo de aplicación con facturación integrada, que incluye clases de conveniencia para poder realizar tareas claves relacionadas con la configuración de tu conexión, el envío de solicitudes de facturación y el procesamiento de las respuestas de Google Play y el manejo de subprocesos en segundo plano para que puedas hacer llamadas de facturación integrada desde tu actividad principal.

Antes de comenzar, asegúrate de leer la sección Información general sobre facturación integrada para familiarizarte con los conceptos que te ayudarán a implementar la facturación integrada más fácilmente.

Para implementar la facturación integrada en tu aplicación, debes hacer lo siguiente:

  1. Agrega la biblioteca de facturación integrada a tu proyecto.
  2. Actualiza tu archivo AndroidManifest.xml.
  3. Crea una ServiceConnection y vincúlala con IInAppBillingService.
  4. Envía solicitudes de facturación integrada desde tu aplicación a IInAppBillingService.
  5. Gestiona las respuestas de facturación integrada desde Google Play.

Agregar el archivo AIDL a tu proyecto

El IInAppBillingService.aidl es un archivo de lenguaje de definición de la interfaz de Android (AIDL) que define la interfaz para el servicio de facturación integrada versión 3. Usarás esta interfaz para realizar solicitudes de facturación invocando llamadas al método de IPC.

Para obtener el archivo AIDL:

  1. Abre Android SDK Manager.
  2. En SDK Manager, expande la sección Extras.
  3. Selecciona Google Play Billing Library.
  4. Haz clic en Install packages para completar la descarga.

El archivo IInAppBillingService.aidl se instalará en <sdk>/extras/google/play_billing/.

Para agregar el AIDL a tu proyecto:

  1. Primero, descarga la biblioteca de facturación de Google Play a tu proyecto de Android:
    1. Selecciona Tools > Android > SDK Manager.
    2. Dentro de Appearance & Behavior > System Settings > Android SDK, selecciona la pestaña SDK Tools para elegir y descargar Google Play Billing Library.
  2. A continuación, copia el archivo IInAppBillingService.aidl a tu proyecto.
    • Si usas Android Studio:
      1. Dirígete a src/main en la ventana de herramientas Project.
      2. Selecciona File > New > Directory, escribe aidl en la ventana New Directory y luego selecciona OK.
      3. Selecciona File > New > Package, escribe com.android.vending.billing en la ventana New Package y luego selecciona OK.
      4. En el explorador de archivos de tu sistema operativo, dirígete a <sdk>/extras/google/play_billing/, copia el archivo IInAppBillingService.aidl y pégalo dentro del paquete com.android.vending.billing en tu proyecto.
    • Si realizas desarrollos en un entorno distinto a Android Studio: Crea el siguiente directorio /src/com/android/vending/billing y copia el archivo IInAppBillingService.aidl a este directorio. Dispón el archivo AIDL en tu proyecto y usa la herramienta Gradle para compilar tu proyecto, de modo que se genere el archivo IInAppBillingService.java.
  3. Crea tu aplicación. Verás un archivo generado con el nombre IInAppBillingService.java en el directorio /gen de tu proyecto.

Actualizar el manifiesto de tu app

La facturación integrada depende de la aplicación de Google Play, que gestiona todas las comunicaciones entre tu aplicación y el servidor de Google Play. Para usar la aplicación de Google Play, tu aplicación debe solicitar el permiso correspondiente. Puedes hacer esto agregando el permiso com.android.vending.BILLING a tu archivo AndroidManifest.xml. Si tu aplicación no declara el permiso de facturación integrada, pero intenta enviar solicitudes de facturación, Google Play rechazará las solicitudes y responderá con un error.

Para dar el permiso necesario a tu app, agrega la siguiente línea en el archivo AndroidManifest.xml:

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

Crear una ServiceConection

Tu aplicación debe tener una ServiceConnection para facilitar los mensajes entre esta y Google Play. Como mínimo, tu aplicación debe hacer lo siguiente:

  • Vincular con IInAppBillingService.
  • Enviar solicitudes de facturación (cómo llamadas al método de IPC) a la aplicación de Google Play.
  • Gestionar los mensajes sincrónicos de respuestas que se muestran con cada solicitud de facturación.

Vincular con IInAppBillingService

Para establecer una conexión con el servicio de facturación integrada en Google Play, implementa una ServiceConnection a fin de vincular tu actividad con el IInAppBillingService. Anula los métodos onServiceDisconnected y onServiceConnected para obtener una referencia a la instancia IInAppBillingService luego de que se haya establecido una conexión.

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);
   }
};

En el método onCreate de tu actividad, realiza la vinculación con una llamada al método bindService. Pasa al método una Intent que haga referencia al servicio de facturación integrada y una instancia de la ServiceConnection que creaste, y como nombre del paquete de destino de la intent establece com.android.vending de manera explícita (el nombre de paquete de la aplicación de Google Play).

Advertencia: Para proteger la seguridad de las transacciones de facturación, asegúrate siempre de fijar de manera explícita el nombre del paquete de destino de la intent en com.android.vending usando setPackage(), como se muestra en el siguiente ejemplo. Fijar el nombre del paquete de manera explícita garantiza que solo Google Play pueda gestionar las solicitudes de facturación desde tu app, lo cual evita que otras apps intercepten esas solicitudes.

@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);
}

Ahora puedes usar la referencia mService para la comunicación con el servicio de Google Play.

Importante: Recuerda realizar la desvinculación del servicio de facturación integrada cuando termines con Activity. Si no realizas la desvinculación, la conexión abierta del servicio podría perjudicar el rendimiento de tu dispositivo. En este ejemplo se muestra la manera de realizar la operación de desvinculación de una conexión de servicio a la facturación integrada llamada mServiceConn sobrescribiendo el método onDestroy de la actividad.

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

Para ver una implementación completa de una conexión de servicio que realice la vinculación con el IInAppBillingService, consulta la capacitación Venta de productos integrados en la aplicación y el ejemplo respectivo.

Realizar una solicitud de facturación integrada

Una vez que tu aplicación esté conectada a Google Play, puedes iniciar solicitudes de compra para productos integrados en la aplicación. Google Play ofrece una interfaz en el proceso de finalización de compra para que los usuarios ingresen el método de pago, por lo cual tu aplicación no necesita gestionar operaciones de pago directamente. Cuando se compra un artículo, Google Play reconoce que el usuario es propietario de ese artículo y evita que compre otro con el mismo ID de producto hasta que lo consuma. Puedes controlar la manera en que se consume el artículo en tu aplicación y notificar a Google Play a fin de que se restablezca la disponibilidad del artículo para la compra. También puedes enviar una consulta a Google Play para obtener rápidamente la lista de compras que realizó el usuario. Esto resulta útil, por ejemplo, al buscar restablecer las compras del usuario cuando este inicia tu app.

Consultar artículos disponibles para la compra

En tu aplicación, puedes consultar la información del artículo desde Google Play usando la In-app Billing Version 3 API. Para pasar una solicitud al servicio de facturación integrada, primero crea un Bundle que contenga una ArrayList de strings de ID de producto con la clave "ITEM_ID_LIST", donde cada string es un ID de producto para un artículo comprable.

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

Para obtener esta información de Google Play, llama al método getSkuDetails en la In-app Billing Version 3 API, y pasa al método la versión ("3") de la In-app Billing API, el nombre de paquete de la app que haga la llamada, el tipo de compra ("inapp"), y el Bundle que creaste.

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

Si se aprueba la solicitud, el Bundle que se muestra tiene un código de respuesta de BILLING_RESPONSE_RESULT_OK (0).

Advertencia: No llames al método getSkuDetails en el subproceso principal. Si lo haces, se desencadenará una solicitud de red que podría bloquear tu subproceso principal. Como alternativa, crea un subproceso separado y llama al método getSkuDetails desde ese subproceso.

Para ver todos los códigos de respuesta posibles de Google Play, consulta Referencia sobre facturación integrada.

Los resultados de la consulta se almacenan en una ArrayList de string con la clave DETAILS_LIST. La información de la compra se almacena en la string en formato JSON. Para ver los tipos de información sobre detalles de productos que se muestran, visita Referencia sobre facturación integrada.

En este ejemplo, se obtienen los precios para tus artículos integrados en la aplicación desde el Bundle de skuDetails mostrado del fragmento de código 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 un artículo

Para iniciar la solicitud de compra desde tu app, llama al método getBuyIntent en el servicio de facturación integrada. Pasa al método la versión ("3") de la In-app Billing API, el nombre de paquete de tu app que realiza la llamada, el ID de producto para el artículo que se comprará, el tipo de compra (“inapp” o “subs”) y una string developerPayload. La string developerPayload se usa para especificar cualquier argumento adicional que desees que Google Play envíe junto con la información de compra.

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

Si se aprueba la solicitud, el Bundle que se muestra tiene un código de respuesta de BILLING_RESPONSE_RESULT_OK (0) y un PendingIntent que puedes usar para iniciar el flujo de compra. Para ver todos los códigos de respuesta posibles de Google Play, consulta Referencia sobre facturación integrada. Luego, extrae un PendingIntent del Bundle de respuesta con la clave BUY_INTENT.

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

Para completar la operación de compra, llama al método startIntentSenderForResult y usa el PendingIntent que creaste. En este ejemplo, se usa un valor arbitrario de 1001 para el código de solicitud.

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

Google Play envía una respuesta de PendingIntent al método onActivityResult de tu aplicación. El método onActivityResult tendrá un código de resultado de Activity.RESULT_OK (1) o Activity.RESULT_CANCELED (0). Para ver los tipos de información de pedido que se muestran en el Intent de respuesta, consulta Referencia sobre facturación integrada.

La información de compra del pedido es una string en formato JSON que se asigna a la clave INAPP_PURCHASE_DATA en el Intent de respuesta. Por ejemplo:

'{
   "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"
 }'

Nota: Google Play genera un token para la compra. Este token es una secuencia de caracteres opacos que podría tener hasta 1000 caracteres de largo. Pasa este token completo a otros métodos, del mismo modo que cuando concretas el consumo de la compra, tal como se describe en Concretar el consumo de una compra. No abrevies ni trunques este token; debes guardar y mostrar el token completo.

Siguiendo con el ejemplo anterior, obtienes el código de respuesta, la información de compra y la firma del Intent de respuesta.

@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();
          }
      }
   }
}

Recomendación de seguridad: Cuando envíes una solicitud de compra, crea un token de string que identifique exclusivamente a esta solicitud de compra y que incluya a este token en el developerPayload. Puedes usar strings generadas aleatoriamente como token. Cuando recibas la respuesta de compra de Google Play, asegúrate de controlar la firma de la información mostrada, la orderId y la string de developerPayload. Para mayor seguridad, debes realizar el control en tu propio servidor seguro. Asegúrate de verificar que orderId sea un valor único que no hayas procesado anteriormente, y que la string de developerPayload concuerde con el token que enviaste anteriormente con la solicitud de compra.

Consultar artículos comprados

Para recuperar información sobre las compras realizadas por un usuario desde tu app, llama al método getPurchases en la versión 3 del servicio de facturación integrada. Pasa al método la versión (“3”) de la In-app Billing API, el nombre de paquete de la app que hace la llamada, y el tipo de compra (“inapp” o “subs”).

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

El servicio de Google Play muestra únicamente las compras realizadas por la cuenta del usuario con sesión activa en el dispositivo. Si se aprueba la solicitud, el Bundle mostrado tiene un código de respuesta de 0. El Bundle de respuesta también contiene una lista de los ID de producto, una lista de los detalles de pedido para cada compra y las firmas para cada compra.

Para mejorar el rendimiento, el servicio de facturación integrada muestra únicamente hasta 700 productos adquiridos por el usuario cuando se llama a getPurchase por primera vez. Si el usuario posee una gran cantidad de productos, Google Play incluye un token de string asignado a la clave INAPP_CONTINUATION_TOKEN en el Bundle de respuesta para indicar que se pueden recuperar más productos. Tu aplicación puede hacer una llamada posterior de getPurchases y pasar este token como un argumento. Google Play sigue mostrando un token de continuación en el Bundle de respuesta hasta que todos los productos que posea el usuario se envíen a tu app.

Para obtener más información sobre los datos que muestra getPurchases, consulta Referencia sobre facturación integrada. En el siguiente ejemplo se muestra la manera en que puedes obtener esta información desde la respuesta.

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
}

Concretar el consumo de una compra

Puedes usar la In-app Billing Version 3 API para realizar en Google Play un seguimiento de la propiedad de los productos integrados en la aplicación. Cuando se compra un producto integrado en la aplicación, este se considera como “adquirido” y no puede comprarse desde Google Play. Debes enviar una solicitud de consumo para el producto integrado en la aplicación para que vuelva a estar disponible la compra en Google Play.

Importante: Los productos integrados en la aplicación gestionados son consumibles, pero las suscripciones no lo son.

La manera de usar el mecanismo de consumo en tu app queda a tu discreción. Normalmente, implementarás el consumo para productos integrados en la aplicación con beneficios temporales que los usuarios deseen adquirir varias veces (por ejemplo, dinero o equipamiento en un juego). En general, no te convendrá implementar el consumo para productos integrados en la aplicación que se compren una única vez y tengan efecto permanente (por ejemplo, una actualización a la categoría premium).

Para registrar el consumo de una compra, envía el método consumePurchase al servicio de facturación integrada y pasa el valor de la string del purchaseToken que identifica a la compra que debe eliminarse. El purchaseToken es parte de la información mostrada en la string de INAPP_PURCHASE_DATA por el servicio de Google Play luego de una solicitud de compra aceptada. En este ejemplo, se registra el consumo de un producto que se identifica con el purchaseToken en la variable del token.

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

Advertencia: No llames al método consumePurchase en el subproceso principal. Si lo haces, se desencadenará una solicitud de red que podría bloquear tu subproceso principal. Como alternativa, crea un subproceso separado y llama al método consumePurchase desde ese subproceso.

Es tu responsabilidad controlar y realizar el seguimiento del suministro del producto integrado en la aplicación al usuario. Por ejemplo, si el usuario compró dinero de un juego, debes actualizar el inventario del jugador con la cantidad de dinero comprada.

Recomendación de seguridad: debes enviar una solicitud de consumo antes de otorgar al usuario el beneficio de la compra directa del producto consumible desde la aplicación. Asegúrate de haber recibido una respuesta de consumo positiva por parte de Google Play antes de suministrar el artículo.

Implementar suscripciones

Iniciar un flujo de compra de una suscripción es similar a iniciar el de un producto; la excepción recae en que el tipo de producto debe estar configurado como “subs”. El resultado de la compra se entrega al método onActivityResult de tu actividad, exactamente como en el caso de los productos integrados en la aplicación.

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 suscripciones activas, usa el método getPurchases, una vez más con el parámetro de tipo de producto fijado en “subs”.

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

La llamada muestra un Bundle con todas las suscripciones activas que posee el usuario. Cuando una suscripción caduque y no haya renovación, dejará de aparecer en el Bundle que se muestra.

Proteger tu aplicación

Para ayudarte a garantizar la integridad de la información de la transacción que se envía a tu aplicación, Google Play firma una string JSON que contiene los datos de respuesta de una orden de compra. Google Play usa la clave privada que está asociada a tu aplicación en la Developer Console para crear esta firma. La Developer Console genera un par de claves RSA para cada aplicación.

Nota: Para encontrar la sección de clave pública de este par de claves, abre la información de tu aplicación en la Developer Console, haz clic en Services & APIs y observa el campo con el título Your License Key for This Application.

La clave pública RSA con codificación Base64 generada por Google Play se encuentra en formato X.509 subjectPublicKeyInfo DER SEQUENCE de codificación binaria. Es la misma clave pública que se usa con las licencias de Google Play.

Cuando tu aplicación recibe esta respuesta firmada, puedes usar la sección de la clave pública de tu par de claves RSA para verificar la firma. Al llevar a cabo la verificación de firmas, puedes detectar respuestas alteradas o falsificadas. Puedes llevar a cabo este paso de verificación de firmas en tu aplicación; sin embargo, si esta se conecta a un servidor seguro remoto, entonces recomendamos que hagas la verificación de firmas en ese servidor.

Para obtener más información sobre las prácticas recomendadas de seguridad y diseño, visita Seguridad y diseño.