Achats intégrés à l’application Android

Depuis la version 3.2.2, Godot propose un plugin Android GodotGooglePlayBilling. Le nouveau plugin utilise la bibliothèque Google Play Billing library au lieu de l'implémentation AIDL IAP qui est maintenant obsolète.

Si vous apprenez mieux en regardant un exemple, vous pouvez trouver le projet de démo ici.

Migrer à partir de Godot 3.2.1 et moins (GodotPaymentsV3)

La nouvelle API GodotGooglePlayBilling n'est pas compatible avec son prédécesseur GodotPaymentsV3.

Modifications

  • Vous devez activer l'option Custom Build dans vos paramètres d'exportation Android et installer le plugin GodotGooglePlayBilling manuellement (voir ci-dessous pour plus de détails)

  • Tous les achats doivent être confirmés par votre application. C'est une exigence de Google. Les achats qui ne sont pas reconnus par votre application seront remboursés.

  • Prise en charge des abonnements

  • Signaux (pas polling ou callback d'objets)

Utilisation

Prise en main

Si ce n'est pas déjà fait, assurez-vous que vous avez activé et configuré avec succès Android Custom Builds. Prenez le binaire et la configuration du plugin GodotGooglePlayBilling sur la page des versions et mettez les deux dans res://android/plugins. Le plugin devrait maintenant apparaître dans les paramètres d'exportation d'Android, où vous pouvez l'activer.

Prise en main

Pour utiliser l'API GodotGooglePlayBilling, vous devez d'abord obtenir le singleton GodotGooglePlayBilling et démarrer la connexion :

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.")

Toutes les méthodes API ne fonctionnent que si l'API est connectée. Vous pouvez utiliser payment.isReady() pour vérifier l'état de la connexion.

Recherche d'articles disponibles

Dès que l'API est connectée, vous pouvez interroger les SKU en utilisant querySkuDetails.

Exemple complet :

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)

Acheter un article

Pour lancer le flux d'achat d'un article, appelez purchase. Vous devez demander les détails du SKU d'un article avant de pouvoir lancer le processus d'achat.

payment.purchase("my_iap_item")

Ensuite, attendez le rappel "on_purchases_updated" et traitez le résultat de la transaction :

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

Vérifier si l'utilisateur a acheté un article

Pour obtenir tous les achats, appelez queryPurchases. Contrairement à la plupart des autres fonctions, queryPurchases est une opération synchrone et retourne un Dictionary avec un code de statut et soit un tableau d'achats soit un message d'erreur. Seuls les abonnements actifs et les achats uniques(one-time purchases) non consommés sont retournés.

Exemple complet :

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

Consommables

Si votre article intégré à l'application n'est pas un achat unique mais un article consommable (par exemple des pièces de monnaie) qui peut être acheté plusieurs fois, vous pouvez consommer un article en appelant consumePurchase avec un jeton d'achat. Appelez queryPurchases pour obtenir le jeton d'achat. Le fait d'appeler consumePurchase confirme automatiquement l'achat.

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

Abonnements

Les abonnements ne sont pas très différents des articles intégrés à l'application. Il suffit d'utiliser "subs" comme deuxième argument à querySkuDetails pour obtenir les détails de l'abonnement. Vérifiez is_auto_renewing dans les résultats de queryPurchases() pour voir si un utilisateur a annulé un abonnement à renouvellement automatique