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...
Android 應用程式內購
Godot 提供官方的 GodotGooglePlayBilling Android 外掛,相容於 Godot 4.2+,並使用 Google Play Billing 函式庫。
用法
入門
請確保你已啟用並成功設定 Android Gradle Builds。接著依照 GodotGooglePlayBilling 的 GitHub 頁面 上的安裝說明操作。
初始化外掛程式
要使用 GodotGooglePlayBilling API:
Access the
BillingClient.連接其訊號以接收交易結果。
呼叫
start_connection。
初始化範例:
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()
API 必須在連線狀態下才能使用。當連線成功時會送出 connected 訊號。你也可以使用 is_ready() 判斷外掛是否已就緒。get_connection_state() 函式會回傳外掛目前的連線狀態。
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.
}
查詢可購買項目
API 連線後, 請使用 query_product_details() 查詢產品 ID。在呼叫 purchase() 、 purchase_subscription() 或 update_subscription() 前, 必須先成功查詢產品詳細資料, 否則會回傳錯誤。 query_product_details() 需要兩個參數: 產品 ID 字串陣列, 以及要查詢的產品類型。一般應用內購買請用 BillingClient.ProductType.INAPP , 訂閱則用 BillingClient.ProductType.SUBS. 陣列中的 ID 字串必須與你在 Google Play Console 為 app 設定的產品 ID 一致。
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)
查詢用戶購買紀錄
要取得使用者的購買紀錄,請呼叫 query_purchases() 並傳入要查詢的產品類型。一般應用內購買請用 BillingClient.ProductType.INAPP,訂閱則用 BillingClient.ProductType.SUBS。查詢結果會透過 query_purchases_response 訊號傳回。該訊號有一個參數:一個 Dictionary,包含回應代碼以及購買項目陣列或除錯訊息。購買陣列只包含有效訂閱與尚未消耗的一次性購買。
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)
購買項目
To launch the billing flow for an item: Use purchase() for in-app products, passing the product ID string.
Use purchase_subscription() for subscriptions, passing the product ID and base plan ID. You may also optionally provide an offer ID.
對於 purchase() 與 purchase_subscription() , 你可以選擇性地傳入布林值, 以指示是否使用 個人化優惠
提醒: 在把某項目傳給 purchase() 前, 你 必須 先查詢該項目的產品詳細資料。此方法會回傳一個字典, 表示結帳流程是否成功啟動。其中包含回應代碼以及購買陣列或除錯訊息。
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)
購買結果會透過 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)
處理購買項目
query_purchases_response 與 on_purchases_updated 訊號會提供一個 Dictionary 格式的購買紀錄陣列。每筆購買的字典鍵值會對應到 Google Play Billing 的 Purchase 類別欄位。
購買欄位:
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
檢查購買狀態
請檢查購買紀錄中的 purchase_state 欄位,以判斷該筆購買是否已完成或仍在處理中。
PurchaseState 可能值:
# Matches Purchase.PurchaseState in the Play Billing Library
# Access in your script as: BillingClient.PurchaseState.PURCHASED
enum PurchaseState {
UNSPECIFIED,
PURCHASED,
PENDING,
}
若購買處於 PENDING 狀態,請勿給予道具或進行任何後續處理,直到其進入 PURCHASED 狀態。如果你有商店介面,建議顯示提示告知用戶需至 Google Play 商店完成待處理訂單。詳情請參考 Google Play Billing 文件中的 處理待處理交易。
消耗品
若你的應用內項目不是一次性購買,而是可重複購買的消耗品(例如金幣),可呼叫 consume_purchase() 並傳入購買字典中的 purchase_token 來消耗該項目。呼叫 consume_purchase() 會自動確認該筆購買。消耗後,使用者即可再次購買;除非再次購買,否則它不會出現在後續的 query_purchases() 查詢結果中。
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
確認購買
若你的應用內項目為一次性購買,必須呼叫 acknowledge_purchase() 並傳入購買字典內的 purchase_token 來確認該筆交易。若三天內未確認,使用者會自動獲得退款,且 Google Play 會撤銷該筆購買。若你已呼叫 consume_purchase(),則會自動完成確認,不需再呼叫 acknowledge_purchase()。
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
訂閱
訂閱大致與一般應用內項目相同。要取得訂閱詳細資料,請在 query_product_details() 的第二個參數傳入 BillingClient.ProductType.SUBS。要取得訂閱購買紀錄,請在 query_purchases() 傳入 BillingClient.ProductType.SUBS。
你可以檢查 query_purchases() 回傳之訂閱購買紀錄中的 is_auto_renewing,以判斷使用者是否已取消自動續訂。
新訂閱購買需進行確認,但自動續訂不需再次確認。
如果你的 App 支援在不同訂閱等級間升級或降級,應使用 update_subscription() 來進行訂閱更新流程以變更現有的有效訂閱。與 purchase() 相同,結果會透過 on_purchases_updated 訊號回傳。以下是 update_subscription() 的參數:
old_purchase_token:目前有效訂閱的購買憑證(purchase token)
replacement_mode:要套用於該訂閱的替換模式
product_id:要切換到的新訂閱之產品 ID
base_plan_id:目標訂閱的基礎方案 ID
offer_id:基礎方案下的優惠 ID(選用)
is_offer_personalized:是否啟用個人化定價(選用)
替換模式的值定義如下:
# 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,
}
預設行為為 WITH_TIME_PRORATION。
update_subscription() 的使用範例:
billing_client.update_subscription(_active_subscription_purchase.purchase_token, \
BillingClient.ReplacementMode.WITH_TIME_PRORATION, "new_sub_product_id", "base_plan_id")