Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Acquisti in-app su Android
Godot offre un plugin Android proprietario chiamato GodotGooglePlayBilling, compatibile con Godot 4.2+, che utilizza la libreria Google Play Billing.
Utilizzo
Per cominciare
Assicurarsi di aver abilitato e configurato correttamente Android Gradle Build. Seguire le istruzioni di installazione sulla pagina GitHub di GodotGooglePlayBilling.
Inizializzare il plugin
Per utilizzare l'API GodotGooglePlayBilling:
Accedere al
BillingClient.Connettere ai suoi segnali per ricevere i risultati di fatturazione.
Chiamare
start_connection.
Esempio di inizializzazione:
var billing_client: BillingClient
func _ready():
billing_client = BillingClient.new()
billing_client.connected.connect(_on_connected) # No params
billing_client.disconnected.connect(_on_disconnected) # No params
billing_client.connect_error.connect(_on_connect_error) # response_code: int, debug_message: String
billing_client.query_product_details_response.connect(_on_query_product_details_response) # response: Dictionary
billing_client.query_purchases_response.connect(_on_query_purchases_response) # response: Dictionary
billing_client.on_purchase_updated.connect(_on_purchase_updated) # response: Dictionary
billing_client.consume_purchase_response.connect(_on_consume_purchase_response) # response: Dictionary
billing_client.acknowledge_purchase_response.connect(_on_acknowledge_purchase_response) # response: Dictionary
billing_client.start_connection()
L'API deve essere in uno stato "connesso" prima dell'uso. Il segnale connected è inviato quando il processo di connessione avviene con successo. È inoltre possibile utilizzare la funzione is_ready() per verificare se il plugin è pronto per l'uso. La funzione get_connection_state() restituisce lo stato di connessione attuale del plugin.
Valori restituiti per get_connection_state():
# Matches BillingClient.ConnectionState in the Play Billing Library.
# Access in your script as: BillingClient.ConnectionState.CONNECTED
enum ConnectionState {
DISCONNECTED, # This client was not yet connected to billing service or was already closed.
CONNECTING, # This client is currently in process of connecting to billing service.
CONNECTED, # This client is currently connected to billing service.
CLOSED, # This client was already closed and shouldn't be used again.
}
Interrogare gli articoli disponibili
Una volta stabilita la connessione con l'API, è possibile interrogare gli ID prodotto tramite query_product_details(). È necessario completare correttamente una richiesta sui dettagli del prodotto prima di chiamare le funzioni purchase(), purchase_subscription() o update_subscription(), altrimenti verrà restituito un errore. query_product_details() accetta due parametri: un array di stringhe ID prodotto e il tipo di prodotto interrogato. Il tipo di prodotto deve essere BillingClient.ProductType.INAPP per i normali acquisti in-app o BillingClient.ProductType.SUBS per gli abbonamenti. Le stringhe ID nell'array devono corrispondere agli ID prodotto definiti nella voce relativa alla propria app nella Google Play Console.
Esempio d'uso di query_product_details():
func _on_connected():
billing_client.query_product_details(["my_iap_item"], BillingClient.ProductType.INAPP) # BillingClient.ProductType.SUBS for subscriptions.
func _on_query_product_details_response(query_result: Dictionary):
if query_result.response_code == BillingClient.BillingResponseCode.OK:
print("Product details query success")
for available_product in query_result.product_details:
print(available_product)
else:
print("Product details query failed")
print("response_code: ", query_result.response_code, "debug_message: ", query_result.debug_message)
Interrogare gli acquisti utente
Per recuperare gli acquisti di un utente, chiamare la funzione query_purchases() passando il tipo di prodotto da interrogare. Il tipo di prodotto deve essere BillingClient.ProductType.INAPP per i normali acquisti in-app o BillingClient.ProductType.SUBS per gli abbonamenti. Il segnale query_purchases_response viene inviato con il risultato. Il segnale ha un singolo parametro: un Dictionary con un codice di risposta e un array di acquisti o un messaggio di debug. Nell'array degli acquisti sono inclusi solo gli abbonamenti attivi e gli acquisti una tantum non consumati.
Esempio d'uso di query_purchases():
func _query_purchases():
billing_client.query_purchases(BillingClient.ProductType.INAPP) # Or BillingClient.ProductType.SUBS for subscriptions.
func _on_query_purchases_response(query_result: Dictionary):
if query_result.response_code == BillingClient.BillingResponseCode.OK:
print("Purchase query success")
for purchase in query_result.purchases:
_process_purchase(purchase)
else:
print("Purchase query failed")
print("response_code: ", query_result.response_code, "debug_message: ", query_result.debug_message)
Acquistare un articolo
Per avviare la procedura di fatturazione per un articolo: usare purchase() per i prodotti in-app, passando la stringa ID del prodotto. Usare purchase_subscription() per gli abbonamenti, passando l'ID del prodotto e l'ID del piano base. È inoltre possibile fornire, facoltativamente, un ID offerta.
Per entrambi purchase() e purchase_subscription(), è possibile passare facoltativamente un valore booleano per indicare se le offerte sono personalizzate
Promemoria: è necessario interrogare i dettagli del prodotto per un articolo prima di poterlo passare a purchase(). Questo metodo restituisce un dizionario che indica se il flusso di fatturazione è stato avviato correttamente. Include un codice di risposta e un array di acquisti o un messaggio di debug.
Esempio d'uso di purchase():
var result = billing_client.purchase("my_iap_item")
if result.response_code == BillingClient.BillingResponseCode.OK:
print("Billing flow launch success")
else:
print("Billing flow launch failed")
print("response_code: ", result.response_code, "debug_message: ", result.debug_message)
L'esito dell'acquisto sarà inviato tramite il segnale on_purchases_updated.
func _on_purchases_updated(result: Dictionary):
if result.response_code == BillingClient.BillingResponseCode.OK:
print("Purchase update received")
for purchase in result.purchases:
_process_purchase(purchase)
else:
print("Purchase update error")
print("response_code: ", result.response_code, "debug_message: ", result.debug_message)
Elaborare un articolo acquistato
I segnali query_purchases_response e on_purchases_updated forniscono un array di acquisti in formato Dictionary. Il dizionario degli acquisti include chiavi che corrispondono ai valori della classe Purchase di Google Play Billing.
Campi di acquisto:
order_id: String
purchase_token: String
package_name: String
purchase_state: int
purchase_time: int (milliseconds since the epoch (Jan 1, 1970))
original_json: String
is_acknowledged: bool
is_auto_renewing: bool
quantity: int
signature: String
product_ids: PackedStringArray
Verificare lo stato dell'acquisto
Verificare il valore di purchase_state di un acquisto per determinare se è stato completato o è ancora in sospeso.
Valori di PurchaseState:
# Matches Purchase.PurchaseState in the Play Billing Library
# Access in your script as: BillingClient.PurchaseState.PURCHASED
enum PurchaseState {
UNSPECIFIED,
PURCHASED,
PENDING,
}
Se un acquisto si trova nello stato PENDING (in sospeso), non è consigliabile assegnare il contenuto dell'acquisto né procedere ulteriormente con l'elaborazione finché non raggiunge lo stato PURCHASED (acquistato). Se si dispone di un'interfaccia per un negozio, è possibile visualizzare informazioni sugli acquisti in sospeso che devono essere completati nel Google Play Store. Per maggiori dettagli sugli acquisti in sospeso, consultare la sezione Handling pending transactions nella documentazione di Google Play Billing Library.
Consumabili
Se un articolo in-app non è un acquisto una tantum ma un oggetto consumabile (ad esempio monete) che può essere acquistato più volte, è possibile consumare un oggetto chiamando consume_purchase() passando il valore purchase_token dal dizionario degli acquisti. La chiamata a consume_purchase() conferma automaticamente l'acquisto. Consumare un prodotto consente all'utente di acquistarlo nuovamente; non apparirà più nelle successive chiamate a query_purchases() a meno che non sia riacquistato.
Esempio d'uso di consume_purchase():
func _process_purchase(purchase):
if "my_consumable_iap_item" in purchase.product_ids and purchase.purchase_state == BillingClient.PurchaseState.PURCHASED:
# Add code to store payment so we can reconcile the purchase token
# in the completion callback against the original purchase
billing_client.consume_purchase(purchase.purchase_token)
func _on_consume_purchase_response(result: Dictionary):
if result.response_code == BillingClient.BillingResponseCode.OK:
print("Consume purchase success")
_handle_purchase_token(result.token, true)
else:
print("Consume purchase failed")
print("response_code: ", result.response_code, "debug_message: ", result.debug_message, "purchase_token: ", result.token)
# Find the product associated with the purchase token and award the
# product if successful
func _handle_purchase_token(purchase_token, purchase_successful):
# check/award logic, remove purchase from tracking list
Confermare gli acquisti
Se un articolo in-app è un acquisto una tantum, è necessario confermare l'acquisto chiamando la funzione acknowledge_purchase(), passando il valore purchase_token dal dizionario degli acquisti. Se non si conferma un acquisto entro tre giorni, l'utente riceverà automaticamente un rimborso e Google Play annullerà l'acquisto. Se si chiama comsume_purchase(), l'acquisto viene confermato automaticamente e non è necessario chiamare acknowledge_purchase().
Esempio d'uso di acknowledge_purchase():
func _process_purchase(purchase):
if "my_one_time_iap_item" in purchase.product_ids and \
purchase.purchase_state == BillingClient.PurchaseState.PURCHASED and \
not purchase.is_acknowledged:
# Add code to store payment so we can reconcile the purchase token
# in the completion callback against the original purchase
billing_client.acknowledge_purchase(purchase.purchase_token)
func _on_acknowledge_purchase_response(result: Dictionary):
if result.response_code == BillingClient.BillingResponseCode.OK:
print("Acknowledge purchase success")
_handle_purchase_token(result.token, true)
else:
print("Acknowledge purchase failed")
print("response_code: ", result.response_code, "debug_message: ", result.debug_message, "purchase_token: ", result.token)
# Find the product associated with the purchase token and award the
# product if successful
func _handle_purchase_token(purchase_token, purchase_successful):
# check/award logic, remove purchase from tracking list
Abbonamenti
Gli abbonamenti funzionano in modo simile ai normali acquisti in-app. Utilizzare BillingClient.ProductType.SUBS come secondo argomento di query_product_details() per ottenere i dettagli dell'abbonamento. Passare BillingClient.ProductType.SUBS a query_purchases() per ottenere i dettagli dell'acquisto dell'abbonamento.
È possibile controllare is_auto_renewing nell'acquisto di un abbonamento restituito da query_purchases() per verificare se un utente ha annullato un abbonamento con rinnovo automatico.
È necessario confermare i nuovi acquisti di abbonamento, ma non i rinnovi automatici.
Se si supporta passare tra diversi livelli di abbonamento, è necessario utilizzare update_subscription() per utilizzare il flusso di aggiornamento dell'abbonamento e modificare un abbonamento attivo. Come per purchase(), i risultati sono restituiti dal segnale on_purchases_updated. Questi sono i parametri di update_subscription():
old_purchase_token: il token di acquisto dell'abbonamento attualmente attivo
replacement_mode: la modalità di sostituzione da applicare all'abbonamento
product_id: ID prodotto del nuovo abbonamento a cui passare
base_plan_id: ID del piano base dell'abbonamento interessato
offer_id: ID dell'offerta nel piano base (facoltativo)
is_offer_personalized: se abilitare i prezzi personalizzati (facoltativo)
I valori delle modalità di sostituzione sono definiti come:
# Access in your script as: BillingClient.ReplacementMode.WITH_TIME_PRORATION
enum ReplacementMode {
# Unknown...
UNKNOWN_REPLACEMENT_MODE = 0,
# The new plan takes effect immediately, and the remaining time will be prorated and credited to the user.
# Note: This is the default behavior.
WITH_TIME_PRORATION = 1,
# The new plan takes effect immediately, and the billing cycle remains the same.
CHARGE_PRORATED_PRICE = 2,
# The new plan takes effect immediately, and the new price will be charged on next recurrence time.
WITHOUT_PRORATION = 3,
# Replacement takes effect immediately, and the user is charged full price of new plan and
# is given a full billing cycle of subscription, plus remaining prorated time from the old plan.
CHARGE_FULL_PRICE = 5,
# The new purchase takes effect immediately, the new plan will take effect when the old item expires.
DEFERRED = 6,
}
Comportamento predefinito con WITH_TIME_PRORATION.
Esempio d'uso di update_subscription:
billing_client.update_subscription(_active_subscription_purchase.purchase_token, \
BillingClient.ReplacementMode.WITH_TIME_PRORATION, "new_sub_product_id", "base_plan_id")