Compras en aplicacion en Android

Godot ofrece un plugin de Android de primera parte llamado GodotGooglePlayBilling desde Godot 3.2.2. El nuevo plugin utiliza la biblioteca Google Play Billing en lugar de la implementación AIDL de IAP que ahora está en desuso.

Si aprende mejor mirando un ejemplo, puede encontrar el proyecto de demostración aquí.

Migración desde Godot 3.2.1 y versiones anteriores (GodotPaymentsV3)

La nueva API de GodotGooglePlayBilling no es compatible con su predecesor GodotPaymentsV3.

Cambios

  • Debes habilitar la opción de compilación personalizada en la configuración de exportación de Android y luego instalar manualmente el plugin GodotGooglePlayBilling (ver más detalles a continuación)

  • Todas las compras deben ser confirmadas por tu aplicación. Esto es un requisito de Google. Las compras que no sean confirmadas por tu aplicación serán reembolsadas.

  • Soporte para suscripciones

  • Señales (sin sondeo ni objetos de devolución de llamada)

Uso

Primeros pasos

Si aún no lo has hecho, asegúrate de haber habilitado y configurado correctamente Compilaciones personalizadas de Android. Obtén el archivo binario y la configuración del plugin GodotGooglePlayBilling desde la página de lanzamientos y coloca ambos en el directorio res://android/plugins. El complemento debería aparecer ahora en la configuración de exportación de Android, donde podrás habilitarlo.

Primeros pasos

Para utilizar la API de GodotGooglePlayBilling, primero debes obtener el singleton de GodotGooglePlayBilling y comenzar la conexión:

var payment

func _ready():
    if Engine.has_singleton("GodotGooglePlayBilling"):
        payment = Engine.get_singleton("GodotGooglePlayBilling")

        # These are all signals supported by the API
        # You can drop some of these based on your needs
        payment.connect("connected", self, "_on_connected") # No params
        payment.connect("disconnected", self, "_on_disconnected") # No params
        payment.connect("connect_error", self, "_on_connect_error") # Response ID (int), Debug message (string)
        payment.connect("purchases_updated", self, "_on_purchases_updated") # Purchases (Dictionary[])
        payment.connect("purchase_error", self, "_on_purchase_error") # Response ID (int), Debug message (string)
        payment.connect("sku_details_query_completed", self, "_on_sku_details_query_completed") # SKUs (Dictionary[])
        payment.connect("sku_details_query_error", self, "_on_sku_details_query_error") # Response ID (int), Debug message (string), Queried SKUs (string[])
        payment.connect("purchase_acknowledged", self, "_on_purchase_acknowledged") # Purchase token (string)
        payment.connect("purchase_acknowledgement_error", self, "_on_purchase_acknowledgement_error") # Response ID (int), Debug message (string), Purchase token (string)
        payment.connect("purchase_consumed", self, "_on_purchase_consumed") # Purchase token (string)
        payment.connect("purchase_consumption_error", self, "_on_purchase_consumption_error") # Response ID (int), Debug message (string), Purchase token (string)

        payment.startConnection()
    else:
        print("Android IAP support is not enabled. Make sure you have enabled 'Custom Build' and the GodotGooglePlayBilling plugin in your Android export settings! IAP will not work.")

Todos los métodos de la API solo funcionan si la API está conectada. Puedes usar payment.isReady() para verificar el estado de conexión.

Consultar los artículos disponibles

Tan pronto como la API esté conectada, puedes consultar los SKUs utilizando querySkuDetails.

Ejemplo completo:

func _on_connected():
  payment.querySkuDetails(["my_iap_item"], "inapp") # "subs" for subscriptions

func _on_sku_details_query_completed(sku_details):
  for available_sku in sku_details:
    print(available_sku)

Compra de un artículo

Para iniciar el proceso de compra de un artículo, llama a purchase. Debes consultar los detalles del SKU de un artículo antes de poder iniciar el proceso de compra para él.

payment.purchase("my_iap_item")

Luego, espera la devolución de llamada _on_purchases_updated y maneja el resultado de la compra:

func _on_purchases_updated(purchases):
    for purchase in purchases:
        if purchase.purchase_state == 1: # 1 means "purchased", see https://developer.android.com/reference/com/android/billingclient/api/Purchase.PurchaseState#constants_1
            # enable_premium(purchase.sku) # unlock paid content, add coins, save token on server, etc. (you have to implement enable_premium yourself)
            if not purchase.is_acknowledged:
                payment.acknowledgePurchase(purchase.purchase_token) # call if non-consumable product
                if purchase.sku in list_of_consumable_products:
                    payment.consumePurchase(purchase.purchase_token) # call if consumable product

Verifica si el usuario compró un artículo

Para obtener todas las compras, llama a queryPurchases. A diferencia de la mayoría de las otras funciones, queryPurchases es una operación síncrona y devuelve un Dictionary con un código de estado y ya sea un arreglo de compras o un mensaje de error. Solo se devuelven suscripciones activas y compras únicas no consumidas.

Ejemplo completo:

var query = payment.queryPurchases("inapp") # Or "subs" for subscriptions
if query.status == OK:
    for purchase in query.purchases:
        if purchase.sku == "my_iap_item" and purchase.purchase_state == 1:
            # enable_premium(purchase.sku) # unlock paid content, save token on server, etc.
            if !purchase.is_acknowledged:
                payment.acknowledgePurchase(purchase.purchase_token)
                # Or wait for the _on_purchase_acknowledged callback before giving the user what they bought

Consumibles

Si tu artículo de compra dentro de la aplicación no es una compra única, sino un artículo consumible (por ejemplo, monedas) que se puede comprar varias veces, puedes consumir un artículo llamando a consumePurchase con un token de compra. Llama a queryPurchases para obtener el token de compra. Llamar a consumePurchase automáticamente confirma una compra. Consumir un producto permite al usuario comprarlo nuevamente y evita que aparezca en las siguientes llamadas a queryPurchases.

var query = payment.queryPurchases("inapp") # Or "subs" for subscriptions
if query.status == OK:
    for purchase in query.purchases:
        if purchase.sku == "my_consumable_iap_item" and purchase.purchase_state == 1:
            # enable_premium(purchase.sku) # add coins, save token on server, etc.
            payment.consumePurchase(purchase.purchase_token)
            # Or wait for the _on_purchase_consumed callback before giving the user what they bought

Suscripciones

Las suscripciones no funcionan de manera muy diferente a los artículos regulares dentro de la aplicación. Simplemente usa "subs" como segundo argumento en querySkuDetails para obtener los detalles de la suscripción. Verifica is_auto_renewing en los resultados de queryPurchases() para ver si un usuario ha cancelado una suscripción de renovación automática