Analiza las interrupciones de compras de productos en la Facturación Play

1. Introducción

En este codelab, te enfocarás en crear un producto único, integrar tu app con la Biblioteca de Play Billing (PBL) y analizar los motivos de las interrupciones en las compras.

Público

Este codelab está dirigido a desarrolladores de apps para Android que usan la Biblioteca de Facturación Play (PBL) o desean usarla para monetizar sus productos únicos.

Qué aprenderás

  • Cómo crear productos únicos en Google Play Console
  • Cómo integrar tu app con la PBL
  • Cómo procesar las compras de productos únicos consumibles y no consumibles en PBL
  • Cómo analizar los abandonos de compras

Qué necesitarás

2. Compila la app de ejemplo

La app de ejemplo está diseñada para ser una app para Android completamente funcional que tiene el código fuente completo que muestra los siguientes aspectos:

  • Integra la app con PBL
  • Recupera productos únicos
  • Inicia flujos de compra para los productos únicos
  • Situaciones de compra que generan las siguientes respuestas de facturación:
    • BILLING_UNAVAILABLE
    • USER_CANCELLED
    • OK
    • ITEM_ALREADY_OWNED

En el siguiente video de demostración, se muestra cómo se verá y se comportará la app de ejemplo después de que se implemente y ejecute.

Requisitos previos

Antes de compilar e implementar la app de ejemplo, haz lo siguiente:

Compilación

El objetivo de este paso de compilación es generar un archivo de Android App Bundle firmado de la app de ejemplo.

Para generar el paquete de aplicación para Android, sigue estos pasos:

  1. Descarga la app de ejemplo desde GitHub.
  2. Compila la app de ejemplo. Antes de compilarla, cambia el nombre del paquete y, luego, compílala. Si tienes paquetes de otras apps en Play Console, asegúrate de que el nombre del paquete que proporciones para la app de ejemplo sea único.

    Nota: Cuando compilas la app de ejemplo, solo se crea un archivo APK que puedes usar para las pruebas locales. Sin embargo, ejecutar la app no recupera productos ni precios porque los productos no se configuraron en Play Console, lo que harás más adelante en este codelab.
  3. Genera un Android App Bundle firmado.
    1. Genera una clave de carga y un almacén de claves.
    2. Firma la app con la clave de carga.
    3. Cómo configurar la firma de apps de Play

El siguiente paso es subir el paquete de aplicación para Android a Google Play Console.

3. Crea un producto único en Play Console

Para crear productos únicos en Google Play Console, debes tener una app en Play Console. Crea una app en Play Console y, luego, sube el paquete de aplicación firmado que creaste anteriormente.

Crea una app

Para crear una app, haz lo siguiente:

  1. Accede a Google Play Console con tu cuenta de desarrollador.
  2. Haz clic en Crear app. Se abrirá la página Crear app.
  3. Ingresa el nombre de la app, selecciona el idioma predeterminado y otros detalles relacionados con la app.
  4. Haz clic en Crear app. Esto creará una app en Google Play Console.

Ahora puedes subir el paquete de aplicación firmado de la app de ejemplo.

Sube el paquete de aplicación firmado

  1. Sube el paquete de aplicación firmado al segmento de prueba interna de Play Console de Google Play. Solo después de subir la app, podrás configurar las funciones relacionadas con la monetización en Play Console.
  2. Haz clic en Prueba y lanza > Pruebas > Versión interna > Crear una versión nueva.
  3. Ingresa un nombre de versión y sube el archivo del paquete de aplicación firmado.
  4. Haz clic en Siguiente y, luego, en Guardar y publicar.

Ahora puedes crear tus productos únicos.

Crea un producto único

Para crear un producto único, sigue estos pasos:

  1. En Google Play Console, en el menú de navegación de la izquierda, ve a Monetiza con Play > Productos > Productos únicos.
  2. Haz clic en Crear un producto único.
  3. Ingresa los siguientes detalles del producto:
    • ID del producto: Ingresa un ID del producto único. Ingresa one_time_product_01.
    • (Opcional) Etiquetas: Agrega etiquetas pertinentes.
    • Nombre: Ingresa un nombre de producto. Por ejemplo, Product name
    • Descripción: Ingresa una descripción del producto. Por ejemplo, Product description
    • (Opcional) Agrega una imagen de ícono: Sube un ícono que represente tu producto.
    Nota: Para los fines de este codelab, puedes omitir la configuración de la sección Impuestos, cumplimiento y programas.
  4. Haz clic en Siguiente.
  5. Agrega una opción de compra y configura su disponibilidad regional. Un producto único necesita al menos una opción de compra, que define cómo se otorga el derecho, su precio y la disponibilidad regional. En este codelab, agregaremos la opción estándar Comprar para el producto.En la sección Opción de compra, ingresa los siguientes detalles:
    • ID de opción de compra: Ingresa un ID de opción de compra. Por ejemplo, buy
    • Tipo de compra: Selecciona Comprar.
    • (Opcional) Etiquetas: Agrega etiquetas específicas para esta opción de compra.
    • Haz clic en Opciones avanzadas para configurar las opciones avanzadas (opcional). Para los fines de este codelab, puedes omitir la configuración de las opciones avanzadas.
  6. En la sección Disponibilidad y precios, haz clic en Establecer precios > Editar los precios de forma masiva.
  7. Selecciona la opción País o región. De esta forma, se seleccionan todas las regiones.
  8. Haz clic en Continuar. Se abrirá un diálogo para ingresar un precio. Ingresa USD 10 y, luego, haz clic en Aplicar.
  9. Haz clic en Guardar y, luego, en Activar. Esto crea y activa la opción de compra.

Para los fines de este codelab, crea 3 productos únicos adicionales con los siguientes IDs de producto:

  • consumable_product_01
  • consumable_product_02
  • consumable_product_03

La app de ejemplo está configurada para usar estos IDs de producto. Puedes proporcionar diferentes IDs de producto, en cuyo caso deberás modificar la app de ejemplo para usar el ID de producto que proporcionaste.

Abre la app de ejemplo en Play Console de Google y navega a Monetizar con Play > Productos > Productos únicos. Luego, haz clic en Crear un producto único y repite los pasos del 3 al 9.

Video sobre la creación de productos únicos

En el siguiente video de ejemplo, se muestran los pasos para crear un producto único que se describieron anteriormente.

4. Integración con PBL

Ahora, veremos cómo integrar tu app con la Biblioteca de Facturación Play (PBL). En esta sección, se describen los pasos generales para la integración y se proporciona un fragmento de código para cada uno de ellos. Puedes usar estos fragmentos como guía para implementar tu integración real.

Para integrar tu app en la PBL, sigue estos pasos:

  1. Agrega la dependencia de la Biblioteca de Facturación Play a la app de ejemplo.
    dependencies {
    val billing_version = "8.0.0"
    
    implementation("com.android.billingclient:billing-ktx:$billing_version")
    }
    
  2. Inicializa el objeto BillingClient. BillingClient es el SDK del cliente que reside en tu app y se comunica con la Biblioteca de Facturación Play. En el siguiente fragmento de código, se muestra cómo inicializar el cliente de facturación.
    protected BillingClient createBillingClient() {
    return BillingClient.newBuilder(activity)
        .setListener(purchasesUpdatedListener)
        .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build())
        .enableAutoServiceReconnection()
        .build();
    }
    
  3. Conéctate a Google Play.En el siguiente fragmento de código, se muestra cómo conectarse a Google Play.
    public void startBillingConnection(ImmutableList<Product> productList) {
    Log.i(TAG, "Product list sent: " + productList);
    Log.i(TAG, "Starting connection");
    billingClient.startConnection(
        new BillingClientStateListener() {
          @Override
          public void onBillingSetupFinished(BillingResult billingResult) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
              // Query product details to get the product details list.
              queryProductDetails(productList);
            } else {
              // BillingClient.enableAutoServiceReconnection() will retry the connection on
              // transient errors automatically.
              // We don't need to retry on terminal errors (e.g., BILLING_UNAVAILABLE,
              // DEVELOPER_ERROR).
              Log.e(TAG, "Billing connection failed: " + billingResult.getDebugMessage());
              Log.e(TAG, "Billing response code: " + billingResult.getResponseCode());
            }
          }
    
          @Override
          public void onBillingServiceDisconnected() {
            Log.e(TAG, "Billing Service connection lost.");
          }
        });
    }
    
  4. Recupera los detalles del producto único.Después de integrar tu app con PBL, debes recuperar los detalles del producto único en tu app. En el siguiente fragmento de código, se muestra cómo recuperar los detalles del producto único en tu app.
    private void queryProductDetails(ImmutableList<Product> productList) {
    Log.i(TAG, "Querying products for: " + productList);
    QueryProductDetailsParams queryProductDetailsParams =
        QueryProductDetailsParams.newBuilder().setProductList(productList).build();
    billingClient.queryProductDetailsAsync(
        queryProductDetailsParams,
        new ProductDetailsResponseListener() {
          @Override
          public void onProductDetailsResponse(
              BillingResult billingResult, QueryProductDetailsResult productDetailsResponse) {
            // check billingResult
            Log.i(TAG, "Billing result after querying: " + billingResult.getResponseCode());
            // process returned productDetailsList
            Log.i(
                TAG,
                "Print unfetched products: " + productDetailsResponse.getUnfetchedProductList());
            setupProductDetailsMap(productDetailsResponse.getProductDetailsList());
            billingServiceClientListener.onProductDetailsFetched(productDetailsMap);
          }
        });
    }
    
    La recuperación de ProductDetails te brinda una respuesta similar a la siguiente:
    {
        "productId": "consumable_product_01",
        "type": "inapp",
        "title": "Shadow Coat (Yolo's Realm | Play Samples)",
        "name": "Shadow Coat",
        "description": "A sleek, obsidian coat for stealth and ambushes",
        "skuDetailsToken": "<---skuDetailsToken--->",
        "oneTimePurchaseOfferDetails": {},
        "oneTimePurchaseOfferDetailsList": [
            {
                "priceAmountMicros": 1990000,
                "priceCurrencyCode": "USD",
                "formattedPrice": "$1.99",
                "offerIdToken": "<--offerIdToken-->",
                "purchaseOptionId": "buy",
                "offerTags": []
            }
        ]
    },
    {
        "productId": "consumable_product_02",
        "type": "inapp",
        "title": "Emperor Den (Yolo's Realm | Play Samples)",
        "name": "Emperor Den",
        "description": "A fair lair glowing with molten rock and embers",
        "skuDetailsToken": "<---skuDetailsToken--->",
        "oneTimePurchaseOfferDetails": {},
        "oneTimePurchaseOfferDetailsList": [
            {
                "priceAmountMicros": 2990000,
                "priceCurrencyCode": "USD",
                "formattedPrice": "$2.99",
                "offerIdToken": "<--offerIdToken-->",
                "purchaseOptionId": "buy",
                "offerTags": []
            }
        ]
    }
    
  5. Inicia el flujo de facturación.
    public void launchBillingFlow(String productId) {
    ProductDetails productDetails = productDetailsMap.get(productId);
    if (productDetails == null) {
      Log.e(
          TAG, "Cannot launch billing flow: ProductDetails not found for productId: " + productId);
      billingServiceClientListener.onBillingResponse(
          BillingResponseCode.ITEM_UNAVAILABLE,
          BillingResult.newBuilder().setResponseCode(BillingResponseCode.ITEM_UNAVAILABLE).build());
      return;
    }
    ImmutableList<ProductDetailsParams> productDetailsParamsList =
        ImmutableList.of(
            ProductDetailsParams.newBuilder().setProductDetails(productDetails).build());
    
    BillingFlowParams billingFlowParams =
        BillingFlowParams.newBuilder()
            .setProductDetailsParamsList(productDetailsParamsList)
            .build();
    
    billingClient.launchBillingFlow(activity, billingFlowParams);
    }
    
  6. Detectar y procesar compras Como parte de este paso, debes hacer lo siguiente:
    1. Verifica la compra.
    2. Otorga derechos al usuario
    3. Notifica al usuario
    4. Notifica a Google sobre el proceso de compra
    De estos, los pasos a, b y c se deben realizar en tu backend y, por lo tanto, están fuera del alcance de este codelab.En el siguiente fragmento, se muestra cómo notificar a Google sobre un producto único consumible:
    private void handlePurchase(Purchase purchase) {
    // Step 1: Send the purchase to your secure backend to verify the purchase following
    // https://developer.android.com/google/play/billing/security#verify
    
    // Step 2: Update your entitlement storage with the purchase. If purchase is
    // in PENDING state then ensure the entitlement is marked as pending and the
    // user does not receive benefits yet. It is recommended that this step is
    // done on your secure backend and can combine in the API call to your
    // backend in step 1.
    
    // Step 3: Notify the user using appropriate messaging.
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
      for (String product : purchase.getProducts()) {
        Log.d(TAG, product + " purchased successfully! ");
      }
    }
    
    // Step 4: Notify Google the purchase was processed.
    // For one-time products, acknowledge the purchase.
    // This sample app (client-only) uses billingClient.acknowledgePurchase().
    // For consumable one-time products, consume the purchase
    // This sample app (client-only) uses billingClient.consumeAsync()
    // If you have a secure backend, you must acknowledge purchases on your server using the
    // server-side API.
    // See https://developer.android.com/google/play/billing/security#acknowledge
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED && !purchase.isAcknowledged()) {
    
      if (shouldConsume(purchase)) {
        ConsumeParams consumeParams =
            ConsumeParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();
        billingClient.consumeAsync(consumeParams, consumeResponseListener);
    
      } else {
        AcknowledgePurchaseParams acknowledgePurchaseParams =
            AcknowledgePurchaseParams.newBuilder()
                .setPurchaseToken(purchase.getPurchaseToken())
                .build();
        billingClient.acknowledgePurchase(
            acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
      }
     }
    }
    

5. Analiza los abandonos de compras

Hasta ahora, en el codelab, las respuestas de Facturación Play se enfocaron en situaciones limitadas, como las respuestas USER_CANCELLED, BILLING_UNAVAILABLE, OK y ITEM_ALREADY_OWNED. Sin embargo, Play Billing puede devolver 13 códigos de respuesta diferentes que se pueden activar por diversos factores del mundo real.

En esta sección, se detallan las causas de las respuestas de error USER_CANCELLED y BILLING_UNAVAILABLE, y se sugieren posibles acciones correctivas que puedes implementar.

Código de error de respuesta USER_CANCELED

Este código de respuesta indica que el usuario abandonó la IU del flujo de compra antes de completar la compra.

Causas probables

¿Qué acciones puedes realizar?

  • Podría indicar que los usuarios tienen una intención baja y son sensibles a los precios.
  • La compra está pendiente o se rechazó el pago.

Código de error de respuesta BILLING_UNAVAILABLE

Este código de respuesta significa que no se pudo completar la compra debido a un problema con el proveedor de pagos del usuario o la forma de pago que eligió. Por ejemplo, la tarjeta de crédito del usuario venció o el usuario se encuentra en un país no admitido. Este código no indica un error con el sistema de facturación de Play en sí.

Causas probables

¿Qué acciones puedes realizar?

  • La app de Play Store del dispositivo del usuario está desactualizada.
  • El usuario se encuentra en un país en el que Play no es compatible.
  • El usuario es un usuario empresarial, y su administrador empresarial inhabilitó la opción para que los usuarios realicen compras.
  • Google Play no puede aplicar cargos en la forma de pago del usuario. Por ejemplo, es posible que la tarjeta de crédito del usuario haya vencido.
  • Supervisar las tendencias de los problemas del sistema y en regiones específicas
  • Considera migrar a la versión 8 de la PBL, ya que admite el código de subrespuesta PAYMENT_DECLINED_DUE_TO_INSUFFICIENT_FUNDS más detallado. Si recibes este código de respuesta, considera notificar a los usuarios sobre la falla o sugerir formas de pago alternativas.
  • Este código de respuesta está diseñado para reintentos, lo que te permite implementar estrategias de reintento adecuadas.
    Es poco probable que los reintentos automáticos sean de ayuda en este caso. Sin embargo, un reintento manual puede ser útil si el usuario soluciona la condición que causó el problema. Por ejemplo, si el usuario actualiza su versión de Play Store a una versión admitida, podría funcionar un reintento manual de la operación inicial.

    Si recibes este código de respuesta cuando el usuario no está en una sesión, no tiene sentido volver a intentarlo. Cuando recibes una respuesta `BILLING_UNAVAILABLE` como resultado del flujo de compra, es muy probable que el usuario haya recibido comentarios de Google Play durante el proceso de compra y que esté al tanto de qué problema hubo. En este caso, podrías mostrar un mensaje de error que advierta que hubo un problema junto con el botón "Reintentar" para darle al usuario la opción de volver a intentarlo de forma manual después de resolver el problema.

Estrategias de reintento para códigos de error de respuesta

Las estrategias de reintento eficaces para los errores recuperables de la biblioteca de Play Billing (PBL) varían según el contexto, como las interacciones del usuario en la sesión (por ejemplo, durante una compra) en comparación con las operaciones en segundo plano (por ejemplo, consultar compras al reanudar la app). Es importante implementar estas estrategias porque ciertos valores de BillingResponseCode indican problemas temporales que se pueden resolver con reintentos, mientras que otros son permanentes y no requieren reintentos.

En el caso de los errores que se producen cuando el usuario está en una sesión, se recomienda una estrategia de reintento simple con una cantidad máxima de intentos establecida para minimizar las interrupciones en la experiencia del usuario. Por el contrario, para las operaciones en segundo plano, como el procesamiento de compras nuevas, que no exigen una ejecución inmediata, el enfoque recomendado es la retirada exponencial.

Para obtener información detallada sobre códigos de respuesta específicos y sus correspondientes estrategias de reintento recomendadas, consulta Cómo administrar códigos de respuesta BillingResult.

6. Próximos pasos

Documentos de referencia

7. ¡Felicitaciones!

¡Felicitaciones! Navegaste correctamente por Google Play Console para crear un nuevo producto único, probaste los códigos de respuesta de facturación y analizaste las interrupciones de compras.

Encuesta

Valoramos mucho tus comentarios sobre este codelab. Considera dedicar unos minutos a completar nuestra encuesta.