Recordatorio: A partir del 2 de agosto de 2022, todas las apps nuevas deben usar la Biblioteca de Facturación 4 o versiones posteriores. A partir del 1 de noviembre de 2022, todas las actualizaciones de apps existentes deberán usar la versión 4 o posterior de la Biblioteca de Facturación. Más información.

Cómo integrar la Biblioteca de Facturación Google Play a tu app

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

En este tema, se describe cómo integrar la Biblioteca de Facturación Google Play a tu app para comenzar a vender productos.

En este tema, se incluyen ejemplos de código basados en las apps de muestra oficiales en GitHub. Consulta los recursos adicionales para obtener una lista completa de las apps de muestra y otros recursos que puedes usar durante la integración.

Duración de una compra

Este es un flujo de compra típico para una compra única o una suscripción.

  1. Muéstrale al usuario lo que puede comprar.
  2. Inicia el flujo de compra para que el usuario acepte la compra.
  3. Verifica la compra en tu servidor.
  4. Proporciona contenido al usuario.
  5. Confirma la entrega del contenido. En el caso de productos para usuarios finales, consume la compra de modo que el usuario pueda volver a comprar.

Las suscripciones se renuevan automáticamente hasta que se cancelan. Una suscripción puede pasar por los siguientes estados:

  • Activa: El usuario está en regla y tiene acceso a la suscripción.
  • Cancelada: El usuario la canceló, pero aún tiene acceso hasta el vencimiento.
  • En período de gracia: El usuario tuvo un problema con el pago, pero aún tiene acceso. Mientras tanto, Google vuelve a intentar procesar la forma de pago.
  • En espera: El usuario tuvo un problema con el pago y ya no tiene acceso. Mientras tanto, Google vuelve a intentar procesar la forma de pago.
  • Detenida: El usuario detuvo el acceso y no podrá acceder hasta que lo reanude.
  • Vencida: El usuario canceló la suscripción y perdió el acceso a ella. Se considera que el usuario desertó luego del vencimiento.

Cómo inicializar una conexión con Google Play

El primer paso para integrar el sistema de facturación de Google Play es agregar la Biblioteca de Facturación Google Play a tu app e inicializar una conexión.

Cómo agregar la dependencia de la Biblioteca de Facturación Google Play

Agrega la dependencia de la biblioteca de Facturación Google Play al archivo build.gradle de la app como se muestra a continuación:

Groovy

dependencies {
    def billing_version = "5.0.0"

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

Kotlin

dependencies {
    val billing_version = "5.0.0"

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

Si usas Kotlin, el módulo KTX de la Biblioteca de Facturación Google Play es compatible con las extensiones y corrutinas de Kotlin, y permite la escritura de Kotlin cuando usas la Biblioteca de Facturación Google Play. Para incluir estas extensiones en tu proyecto, agrega la siguiente dependencia al archivo build.gradle de la app como se muestra a continuación:

Groovy

dependencies {
    def billing_version = "5.0.0"

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

Kotlin

dependencies {
    val billing_version = "5.0.0"

    implementation("com.android.billingclient:billing-ktx:$billing_version")
}

Cómo inicializar un BillingClient

Una vez que agregues una dependencia en la Biblioteca de Facturación Google Play, deberás inicializar una instancia de BillingClient. BillingClient es la interfaz principal para la comunicación entre la biblioteca de Facturación Google Play y el resto de la app. BillingClient proporciona métodos de conveniencia, tanto síncronos como asíncronos, para muchas operaciones de facturación comunes. Te recomendamos tener una conexión BillingClient activa a la vez a fin de evitar varias devoluciones de llamada PurchasesUpdatedListener para un solo evento.

Para crear un BillingClient, usa newBuilder(). Puedes pasar cualquier contexto a newBuilder(), y BillingClient lo usará para obtener un contexto de aplicación. Eso significa que no debes preocuparte por las fugas de memoria. Para recibir actualizaciones sobre compras, también debes llamar a setListener() y pasar una referencia a PurchasesUpdatedListener. Este objeto de escucha recibe actualizaciones de todas las compras que se realizan en tu app.

Kotlin

private val purchasesUpdatedListener =
   PurchasesUpdatedListener { billingResult, purchases ->
       // To be implemented in a later section.
   }

private var billingClient = BillingClient.newBuilder(context)
   .setListener(purchasesUpdatedListener)
   .enablePendingPurchases()
   .build()

Java

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        // To be implemented in a later section.
    }
};

private BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .build();

Cómo conectarse a Google Play

Después de crear un BillingClient, debes establecer una conexión con Google Play.

Para conectarte a Google Play, llama a startConnection(). El proceso de conexión es asíncrono. Debes implementar un BillingClientStateListener para recibir una devolución de llamada una vez que se complete la configuración del cliente y esté lista para realizar más solicitudes.

También debes implementar la lógica de reintento a fin de controlar las pérdidas de conexión con Google Play. Para implementar la lógica de reintento, anula el método de devolución de llamada onBillingServiceDisconnected() y asegúrate de que BillingClient llame al método startConnection() para volver a conectarse a Google Play antes de realizar más solicitudes.

En el siguiente ejemplo, se muestra cómo iniciar una conexión y probar que esté lista para usarse:

Kotlin

billingClient.startConnection(object : BillingClientStateListener {
    override fun onBillingSetupFinished(billingResult: BillingResult) {
        if (billingResult.responseCode ==  BillingResponseCode.OK) {
            // The BillingClient is ready. You can query purchases here.
        }
    }
    override fun onBillingServiceDisconnected() {
        // Try to restart the connection on the next request to
        // Google Play by calling the startConnection() method.
    }
})

Java

billingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(BillingResult billingResult) {
        if (billingResult.getResponseCode() ==  BillingResponseCode.OK) {
            // The BillingClient is ready. You can query purchases here.
        }
    }
    @Override
    public void onBillingServiceDisconnected() {
        // Try to restart the connection on the next request to
        // Google Play by calling the startConnection() method.
    }
});

Cómo mostrar productos disponibles para comprar

Después de establecer una conexión con Google Play, podrás buscar los productos disponibles y mostrarlos a los usuarios.

La búsqueda de detalles de productos es un paso importante antes de mostrar los productos a los usuarios, ya que muestra información localizada sobre los productos. En el caso de suscripciones, asegúrate de que la visualización de tus productos cumpla con todas las políticas de Play.

Para buscar detalles de productos integrados en la app, llama a queryProductDetailsAsync().

Para administrar el resultado de la operación asíncrona, también debes especificar un objeto de escucha que implemente la interfaz de ProductDetailsResponseListener. Luego, puedes anular onProductDetailsResponse(), que notifica al objeto de escucha cuando finaliza la consulta, como se muestra en el siguiente ejemplo:

Kotlin

val queryProductDetailsParams =
    QueryProductDetailsParams.newBuilder()
        .setProductList(
            ImmutableList.of(
                Product.newBuilder()
                    .setProductId("product_id_example")
                    .setProductType(ProductType.SUBS)
                    .build()))
        .build()

billingClient.queryProductDetailsAsync(queryProductDetailsParams) {
    billingResult,
    productDetailsList ->
      // check billingResult
      // process returned productDetailsList
}
)

Java

QueryProductDetailsParams queryProductDetailsParams =
    QueryProductDetailsParams.newBuilder()
        .setProductList(
            ImmutableList.of(
                Product.newBuilder()
                    .setProductId("product_id_example")
                    .setProductType(ProductType.SUBS)
                    .build()))
        .build();

billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
        public void onProductDetailsResponse(BillingResult billingResult,
                List<ProductDetails> productDetailsList) {
            // check billingResult
            // process returned productDetailsList
        }
    }
)

Cuando busques detalles de productos, pasa una instancia de QueryProductDetailsParams que especifique una lista de strings del ID del producto creadas en Google Play Console junto con un ProductType. El objeto ProductType puede ser ProductType.INAPP para productos únicos o ProductType.SUBS para suscripciones.

Cómo hacer búsquedas con extensiones de Kotlin

Si usas extensiones de Kotlin, puedes llamar a la función de extensión queryProductDetails() para buscar los detalles del producto integrado en la app.

queryProductDetails() aprovecha las corrutinas de Kotlin para que no tengas que definir un objeto de escucha independiente. En cambio, la función se suspende hasta que se completa la consulta, y después puedes procesar el resultado:

suspend fun processPurchases() {
    val productList = ArrayList<String>()
    productList.add("product_id_example")

    val params = QueryProductDetailsParams.newBuilder()
    params.setProductList(productList)
        .setType(ProductType.SUBS)

    // leverage queryProductDetails Kotlin extension function
    val productDetailsResult = withContext(Dispatchers.IO) {
        billingClient.queryProductDetails(params.build())
    }

    // Process the result.
}

Cómo procesar el resultado

La Biblioteca de Facturación Google Play almacena los resultados de la búsqueda en un List de objetos ProductDetails. Luego, puedes llamar a diferentes métodos de cada objeto ProductDetails de la lista para ver información relevante de un producto integrado en la app, como el precio o la descripción. Para ver información detallada del producto disponible, consulta la lista de métodos de la clase ProductDetails.

Antes de poner un artículo en venta, verifica que el usuario no lo tenga. Si el usuario todavía tiene un producto consumible en su biblioteca de artículos, debe consumirlo antes de volver a comprarlo.

Antes de ofrecer una suscripción, verifica que el usuario no esté suscrito. Además, ten en cuenta lo siguiente:

  • queryProductDetailsAsync() muestra los detalles del producto de suscripción, y se permite un máximo de 50 ofertas por suscripción.
  • queryProductDetailsAsync() solo muestra ofertas para las que el usuario es apto. Si el usuario intenta comprar una oferta para la que no es apto (por ejemplo, si la app muestra una lista desactualizada de ofertas aptas), Play informa al usuario que no es apto, y el usuario puede optar por comprar el plan básico.

Cómo iniciar el flujo de compra

Para iniciar una solicitud de compra desde la app, llama al método launchBillingFlow() del subproceso principal de la app. Este método toma una referencia para un objeto BillingFlowParams que contiene el objeto ProductDetails relevante obtenido de la llamada a queryProductDetailsAsync(). Para crear un objeto BillingFlowParams, usa la clase BillingFlowParams.Builder.

Kotlin

// An activity reference from which the billing flow will be launched.
val activity : Activity = ...;

val productDetailsParamsList = listOf(
    BillingFlowParams.ProductDetailsParams.newBuilder()
        // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
        .setProductDetails(productDetails)
        // to get an offer token, call ProductDetails.subscriptionOfferDetails()
        // for a list of offers that are available to the user
        .setOfferToken(selectedOfferToken)
        .build()
)

val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build()

// Launch the billing flow
val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

Java

// An activity reference from which the billing flow will be launched.
Activity activity = ...;

ImmutableList productDetailsParamsList =
    ImmutableList.of(
        ProductDetailsParams.newBuilder()
             // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
            .setProductDetails(productDetails)
            // to get an offer token, call ProductDetails.getSubscriptionOfferDetails()
            // for a list of offers that are available to the user
            .setOfferToken(selectedOfferToken)
            .build()
    );

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build();

// Launch the billing flow
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

El método launchBillingFlow()BillingClient.BillingResponseCode muestra uno de los códigos de respuesta que se indican en . Asegúrate de verificar este resultado para garantizar que no haya errores al iniciar el flujo de compra. Un BillingResponseCode de OK indica un inicio exitoso.

En una llamada exitosa a launchBillingFlow(), el sistema muestra la pantalla de compra de Google Play. En la Figura 1, se muestra la pantalla de compra de una suscripción:

En la pantalla de compra de Google Play, se muestra una suscripción que está disponible para su compra
Figura 1: En la pantalla de compra de Google Play, se muestra una suscripción que está disponible para su compra.

Google Play llama a onPurchasesUpdated() para enviar el resultado de la operación de compra a un objeto de escucha que implementa la interfaz PurchasesUpdatedListener. El objeto de escucha se especifica con el método setListener() cuando inicializas a tu cliente.

Debes implementar onPurchasesUpdated() para controlar los códigos de respuesta posibles. En el siguiente ejemplo, se muestra cómo anular onPurchasesUpdated():

Kotlin

override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
   if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) {
       for (purchase in purchases) {
           handlePurchase(purchase)
       }
   } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) {
       // Handle an error caused by a user cancelling the purchase flow.
   } else {
       // Handle any other error codes.
   }
}

Java

@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
    if (billingResult.getResponseCode() == BillingResponseCode.OK
        && purchases != null) {
        for (Purchase purchase : purchases) {
            handlePurchase(purchase);
        }
    } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {
        // Handle an error caused by a user cancelling the purchase flow.
    } else {
        // Handle any other error codes.
    }
}

Si la compra es exitosa, se generará una pantalla de compra exitosa de Google Play similar a la figura 2.

Pantalla de compra exitosa de Google Play
Figura 2: Pantalla de compra exitosa de Google Play

Una compra exitosa también genera un token de compra, es decir, un identificador único que representa al usuario y al ID del producto integrado en la aplicación que compró. Las apps pueden almacenar el token de compra de forma local, aunque recomendamos pasarlo a tu servidor de backend seguro, donde podrás verificar la compra y protegerte contra el fraude. Este proceso se describe más detalladamente en la siguiente sección.

Además, el usuario recibe un correo electrónico con un comprobante de la operación, que incluye un ID de pedido o ID único de la transacción. Los usuarios reciben un correo electrónico con un ID de pedido único por cada compra de producto único, así como por la compra de la suscripción inicial y las renovaciones automáticas posteriores. Puedes usar el ID de pedido para administrar los reembolsos en Google Play Console.

Cómo indicar un precio personalizado

Si tu app puede distribuirse a usuarios de la Unión Europea, usa el método setIsOfferPersonalized() para informar a los usuarios que el precio de un artículo se personalizó mediante la toma de decisiones automatizada.

La pantalla de compra de Google Play que indica que el precio se personalizó para el usuario.
Figura 3. La pantalla de compra de Google Play indica que el precio se personalizó para el usuario.

Debes consultar el artículo 6 (1) (ea) CRD de la Directiva de Derechos de los Consumidores (2011/83/UE) para determinar si el precio que ofreces a los usuarios es personalizado.

setIsOfferPersonalized() toma una entrada booleana. Cuando se establece en true, la IU de Play incluye la divulgación. Cuando es false, la IU omite la divulgación. El valor predeterminado es false.

Para obtener más información, consulta al Centro de ayuda al consumidor.

Cómo procesar las compras

Una vez que un usuario completa una compra, tu app debe procesarla. En la mayoría de los casos, la app recibe notificaciones de las compras realizadas a través del PurchasesUpdatedListener, pero hay casos en los que la app llama a BillingClient.queryPurchasesAsync() para obtener la información, como se describe en Cómo buscar compras.

Tu app debe procesar una compra de la siguiente manera:

  1. Verifica la compra.
  2. Proporciona contenido al usuario y confirma la transmisión del contenido. Opcionalmente, marca el artículo como consumido para que el usuario pueda volver a comprarlo.

Para verificar una compra, primero confirma que el estado de compra sea PURCHASED. Si la compra figura como PENDING, debes procesarla según se describe en Cómo administrar transacciones pendientes. En el caso de las compras recibidas de onPurchasesUpdated() o queryPurchasesAsync(), también debes verificar la compra para asegurarte de que sea legítima antes de que la app otorgue los derechos. Para obtener información sobre cómo verificar correctamente una compra, consulta Cómo verificar las compras antes de otorgar derechos.

Una vez que verifiques la compra, tu app estará lista para otorgarle derechos al usuario. Después de otorgar los derechos, la app debe confirmar la compra. Esta confirmación le informa a Google Play que otorgaste derechos para la compra.

El proceso para otorgar derechos y confirmar la compra depende de si la compra es por un producto no consumible, por uno consumible o por una suscripción.

En el caso de los consumibles, el método consumeAsync() cumple con el requisito de confirmación e indica que tu app le otorgó derechos al usuario. Este método también permite que la app vuelva a habilitar el producto único para la compra.

Para indicar que se consumió un producto único, llama a consumeAsync() e incluye el token de compra que Google Play debe poner a disposición para volver a comprar. También debes pasar un objeto que implemente la interfaz de ConsumeResponseListener. Este objeto controla el resultado de la operación de consumo. Puedes anular el método onConsumeResponse(), que la biblioteca de Facturación Google Play llama cuando la operación finaliza.

El siguiente ejemplo ilustra el consumo de un producto usando el token de compra asociado:

Kotlin

suspend fun handlePurchase(purchase: Purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    val purchase : Purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant entitlement to the user.

    val consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.getPurchaseToken())
            .build()
    val consumeResult = withContext(Dispatchers.IO) {
        client.consumePurchase(consumeParams)
    }
}

Java

void handlePurchase(Purchase purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    Purchase purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant entitlement to the user.

    ConsumeParams consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.getPurchaseToken())
            .build();

    ConsumeResponseListener listener = new ConsumeResponseListener() {
        @Override
        public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // Handle the success of the consume operation.
            }
        }
    };

    billingClient.consumeAsync(consumeParams, listener);
}

Para confirmar las compras de productos no consumibles, usa BillingClient.acknowledgePurchase() de la Biblioteca de Facturación Google Play o Product.Purchases.Acknowledge de la API de Google Play Developer. Antes de confirmar una compra, la app debe verificar si ya se confirmó mediante el método isAcknowledged() en la Biblioteca de Facturación Google Play o el campo acknowledgementState en la API de Google Developers.

En el siguiente ejemplo, se muestra la confirmación de una compra mediante la Biblioteca de Facturación Google Play:

Kotlin

val client: BillingClient = ...
val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ...

suspend fun handlePurchase() {
    if (purchase.purchaseState === PurchaseState.PURCHASED) {
        if (!purchase.isAcknowledged) {
            val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.purchaseToken)
            val ackPurchaseResult = withContext(Dispatchers.IO) {
               client.acknowledgePurchase(acknowledgePurchaseParams.build())
            }
        }
     }
}

Java

BillingClient client = ...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...

void handlePurchase(Purchase purchase) {
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
        if (!purchase.isAcknowledged()) {
            AcknowledgePurchaseParams acknowledgePurchaseParams =
                AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.getPurchaseToken())
                    .build();
            client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
        }
    }
}

Las suscripciones se controlan de manera similar a como se controlan los productos no consumibles. Puedes corroborar la confirmación de una suscripción mediante BillingClient.acknowledgePurchase() de la Biblioteca de Facturación Google Play o Purchases.Subscriptions.Acknowledge de la API de Google Play Developer. Se deben confirmar todas las compras de suscripciones iniciales. Las renovaciones de suscripciones no necesitan confirmarse. Para obtener más información sobre cuándo se deben confirmar las suscripciones, consulta el tema Cómo vender suscripciones.

Cómo buscar las compras

Utilizar objetos de escucha para las actualizaciones de compra con un PurchasesUpdatedListener no es suficiente para garantizar que tu app procese todas las compras. Es posible que la app no esté al tanto de todas las compras que realizó un usuario. A continuación, se indican algunas situaciones en las que la app podría perder el registro de las compras o desconocerlas:

  • Problemas de red durante la compra: Un usuario realiza una compra exitosa y recibe la confirmación de Google, pero su dispositivo pierde la conexión de red antes de recibir la notificación de la compra a través del PurchasesUpdatedListener.
  • Varios dispositivos: Un usuario compra un artículo en un dispositivo y, luego, espera ver el elemento cuando cambia de dispositivo.
  • Administración de compras realizadas fuera de la app: Algunas compras, como los canjes de promociones, se pueden realizar fuera de la app.

Si quieres resolver estas situaciones, asegúrate de que la app llame a BillingClient.queryPurchasesAsync() en el método onResume() a fin de garantizar que todas las compras se procesen correctamente como se describe en el artículo para procesar compras.

En el siguiente ejemplo, se muestra cómo recuperar las compras de suscripción de un usuario. Ten en cuenta que queryPurchasesAsync() solo muestra las suscripciones activas y las compras únicas no consumidas.

Kotlin

val params = QueryPurchasesParams.newBuilder()
               .setProductType(ProductType.SUBS)

// uses queryPurchasesAsync Kotlin extension function
val purchasesResult = billingClient.queryPurchasesAsync(params.build())

// check purchasesResult.billingResult
// process returned purchasesResult.purchasesList, e.g. display the plans user owns

Java

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder()
      .setProductType(ProductType.SUBS)
      .build(),
    new PurchasesResponseListener() {
      public void onQueryPurchasesResponse(BillingResult billingResult, List purchases) {
        // check billingResult
        // process returned purchase list, e.g. display the plans user owns

      }
    }
);

Cómo recuperar el historial de compras

queryPurchaseHistoryAsync() muestra la compra más reciente que hizo el usuario para cada producto, incluso si venció, se canceló o se consumió la compra.

Si utilizas extensiones de Kotlin, puedes usar la función de extensión queryPurchaseHistory().

Kotlin

val params = QueryPurchaseHistoryParams.newBuilder()
               .setProductType(ProductType.SUBS)

// uses queryPurchaseHistory Kotlin extension function
val purchaseHistoryResult = billingClient.queryPurchaseHistory(params.build())

// check purchaseHistoryResult.billingResult
// process returned purchaseHistoryResult.purchaseHistoryRecordList, e.g. display purchase

Java

billingClient.queryPurchaseHistoryAsync(
    QueryPurchaseHistoryParams.newBuilder()
        .setProductType(ProductType.SUBS)
        .build(),
    new PurchaseHistoryResponseListener() {
      public void onPurchaseHistoryResponse(
        BillingResult billingResult, List purchasesHistoryList) {
          // check billingResult
          // process returned purchase history list, e.g. display purchase history
        }
    }
);

Cómo manejar las compras realizadas fuera de la app

Algunas compras, como los canjes de promociones, pueden realizarse fuera de la app. Cuando un usuario realiza una compra fuera de tu app, espera que esta muestre un mensaje dentro de ella o use algún tipo de mecanismo de notificación para informarle que recibió y procesó correctamente la compra. Algunos mecanismos aceptables son los siguientes:

  • Mostrar una ventana emergente en la app.
  • Enviar el mensaje a una casilla de mensajes integrada en la app e indicar claramente que hay un mensaje nuevo en la casilla.
  • Usar un mensaje de notificación del SO.

Ten en cuenta que la app puede estar en cualquier estado cuando reconozca la compra. Incluso es posible que se realice la compra sin que la app esté instalada. Los usuarios esperan recibir la compra cuando reanuden la app, sin importar el estado en el que se encuentre.

Debes poder detectar las compras independientemente del estado en el que se encuentre la app cuando se realice la compra. Sin embargo, hay algunas excepciones en las que es aceptable no notificar de inmediato al usuario que se recibió el elemento. Por ejemplo:

  • Durante la parte de acción de un juego, ya que mostrar un mensaje puede distraer al usuario. En este caso, debes notificar al usuario una vez finalizada la acción.
  • Durante las escenas cinemáticas, ya que mostrar un mensaje puede distraer al usuario. En este caso, debes notificar al usuario después de que termine la escena.
  • Durante el instructivo inicial y las partes de configuración del juego. Te recomendamos notificar a los usuarios nuevos sobre la recompensa inmediatamente después de que abran el juego o durante la configuración inicial del usuario. Sin embargo, es aceptable esperar hasta que la secuencia principal del juego esté disponible para notificar al usuario.

Siempre ten en cuenta al usuario en el momento de decidir cuándo y cómo notificar sobre las compras realizadas fuera de la app. Cada vez que un usuario no recibe una notificación de inmediato, es posible que se confunda y deje de usar la app, e incluso se comunique con el servicio de atención al usuario o se queje en las redes sociales. Nota: PurchasesUpdatedListener se registra en el contexto de tu aplicación para administrar las actualizaciones de compras, incluidas las compras iniciadas fuera de tu app. Esto significa que, si el proceso de tu aplicación no existe, no se notificará a tu PurchasesUpdatedListener. Es por eso que tu app debe llamar a BillingClient.queryPurchasesAsync() en el método onResume() como se menciona en Cómo buscar las compras.

Cómo administrar transacciones pendientes

Google Play admite transacciones pendientes o que requieran uno o más pasos adicionales entre el momento en que un usuario inicia una compra y el momento en que se procesa la forma de pago de la compra. Tu app no debe otorgar derechos a estos tipos de compras hasta que Google te notifique que la forma de pago del usuario se cobró correctamente.

Por ejemplo, un usuario puede crear una compra PENDING de un elemento integrado en la app si elige la forma de pago en efectivo. Luego, el usuario puede elegir una tienda física en la que completará la transacción y recibirá un código mediante notificación y correo electrónico. Cuando el usuario llega a la tienda física, puede canjear el código con el cajero y pagar en efectivo. Luego, Google les notifica al usuario y a ti que se recibió dinero en efectivo. Posteriormente, la app puede otorgar derechos al usuario.

Tu app debe admitir transacciones pendientes llamando a enablePendingPurchases() como parte de la inicialización.

Cuando la app reciba una compra nueva, ya sea a través del PurchasesUpdatedListener o como resultado de una llamada a queryPurchasesAsync(), usa el método getPurchaseState() para determinar si el estado de compra es PURCHASED o PENDING.

Si la app se está ejecutando cuando el usuario completa la compra, se vuelve a llamar a PurchasesUpdatedListener, y PurchaseState ahora será PURCHASED. En este punto, la app puede procesar la compra con el método estándar para procesar compras únicas. La app también debe llamar a queryPurchasesAsync() en el método onResume() para controlar las compras que pasaron al estado PURCHASED mientras no se estaba ejecutando.

La app también puede usar notificaciones para desarrolladores en tiempo real con compras pendientes mediante objetos de escucha de OneTimeProductNotifications. Cuando la compra pasa de PENDING a PURCHASED, tu app recibe una notificación de ONE_TIME_PRODUCT_PURCHASED. Si se cancela la compra, la app recibe una notificación de ONE_TIME_PRODUCT_CANCELED. Esto puede suceder si el cliente no completa el pago en el plazo requerido. Si recibes estas notificaciones, puedes usar la API de Google Play Developer, que incluye un estado PENDING para Purchases.products.

Puedes encontrar los pasos detallados para probar esta situación en Cómo probar compras pendientes.

Cómo administrar compras de varias cantidades

Google Play, compatible con las versiones 4.0 y posteriores de la Biblioteca de Facturación Google Play, permite que los clientes compren, en una transacción, más artículos de un mismo producto integrado en la aplicación si especifican una cantidad en el carrito de compras. Se espera que la app administre compras de varias cantidades y otorgue derechos en función de la cantidad de compra especificada.

Para admitir las compras de varias cantidades, la lógica de aprovisionamiento de la app debe verificar una cantidad de artículos. Puedes acceder a un campo quantity desde una de las siguientes API:

Una vez que hayas agregado lógica para administrar las compras de varias cantidades, deberás habilitar la función de varias cantidades para el producto correspondiente en la página de administración de productos integrados en la aplicación en Google Play Console.