Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Android 應用內購買

Godot offers a first-party GodotGooglePlayBilling Android plugin compatible with Godot 4 which uses the Google Play Billing library.

使用量

入門

Make sure you have enabled and successfully set up Android Gradle Builds. Follow the compiling instructions on the GodotGooglePlayBilling github page.

然後將檔案`./godot-google-play-billing/build/outputs/aar/GodotGooglePlayBilling.***.release.aar` 和`./GodotGooglePlayBilling.gdap` 放入您的專案中的`res:// android /plugins` 資料夾。

該外掛程式現在應該顯示在 Android 匯出設定中,您可以在其中啟用它。

初始化外掛

要使用“GodotGooglePlayBilling” API:

  1. 取得``GodotGooglePlayBilling``單例的引用

  2. 連接插件訊號的處理程式

  3. Call startConnection

在下方範例中:

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.billing_resume.connect(_on_billing_resume) # No params
        payment.connected.connect(_on_connected) # No params
        payment.disconnected.connect(_on_disconnected) # No params
        payment.connect_error.connect(_on_connect_error) # Response ID (int), Debug message (string)
        payment.price_change_acknowledged.connect(_on_price_acknowledged) # Response ID (int)
        payment.purchases_updated.connect(_on_purchases_updated) # Purchases (Dictionary[])
        payment.purchase_error.connect(_on_purchase_error) # Response ID (int), Debug message (string)
        payment.product_details_query_completed.connect(_on_product_details_query_completed) # Products (Dictionary[])
        payment.product_details_query_error.connect(_on_product_details_query_error) # Response ID (int), Debug message (string), Queried SKUs (string[])
        payment.purchase_acknowledged.connect(_on_purchase_acknowledged) # Purchase token (string)
        payment.purchase_acknowledgement_error.connect(_on_purchase_acknowledgement_error) # Response ID (int), Debug message (string), Purchase token (string)
        payment.purchase_consumed.connect(_on_purchase_consumed) # Purchase token (string)
        payment.purchase_consumption_error.connect(_on_purchase_consumption_error) # Response ID (int), Debug message (string), Purchase token (string)
        payment.query_purchases_response.connect(_on_query_purchases_response) # Purchases (Dictionary[])

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

API 在使用前必須處於連線狀態。當連線過程成功時,將發送“connected”訊號。您也可以使用“isReady()”來確定插件是否可以使用。 getConnectionState() 函式傳回外掛程式的目前連線狀態。

getConnectionState() 的回傳值:

# Matches BillingClient.ConnectionState in the Play Billing Library
enum ConnectionState {
    DISCONNECTED, # not yet connected to billing service or was already closed
    CONNECTING, # currently in process of connecting to billing service
    CONNECTED, # currently connected to billing service
    CLOSED, # already closed and shouldn't be used again
}

有六種搜尋模式:

API 連線後,使用「querySkuDetails()」查詢 SKU。在呼叫 purchase()queryPurchases() 函式之前,您必須成功完成 SKU 查詢,否則它們將傳回錯誤。 querySkuDetails() 有兩個參數:一個 SKU 名稱字串陣列,以及一個指定要查詢的 SKU 型別的字串。對於正常的應用程式內購買,SKU 型別字串應為 "inapp" ,對於訂閱,應為 "subs" 。陣列中的名稱字串應與您的應用程式的 Google Play Console 條目中定義的 SKU 產品 ID 相符。

querySkuDetails() 的範例用法:

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

func _on_product_details_query_completed(product_details):
  for available_product in product_details:
    print(available_product)

func _on_product_details_query_error(response_id, error_message, products_queried):
    print("on_product_details_query_error id:", response_id, " message: ",
            error_message, " products: ", products_queried)

查詢使用者購買記錄

要獲得所有的購買,請呼叫 queryPurchases。與大多數其他函式不同的是,queryPurchases 是一個同步操作,會返回一個 Dictionary,其中包含狀態碼和一個購買陣列或一個錯誤資訊。只會返回處於活躍狀態的訂閱和尚未消耗的一次性購買。

queryPurchases() 的範例用法:

func _query_purchases():
    payment.queryPurchases("inapp") # Or "subs" for subscriptions

func _on_query_purchases_response(query_result):
    if query_result.status == OK:
        for purchase in query_result.purchases:
            _process_purchase(purchase)
    else:
        print("queryPurchases failed, response code: ",
                query_result.response_code,
                " debug message: ", query_result.debug_message)

成功檢索 SKU 詳細資訊後,您應該在啟動期間查詢購買情況。由於使用者可能會從您的應用程式外部進行購買或解決待處理的交易,因此您應該在從後台恢復時重新檢查購買情況。為了實作這一點,您可以使用「billing_resume」訊號。

billing_resume 的範例用法:

func _on_billing_resume():
    if payment.getConnectionState() == ConnectionState.CONNECTED:
        _query_purchases()

有關處理“queryPurchases()”返回的購買商品的更多信息,請參閱“處理購買商品”_

購買專案

要啟動一個專案的購買流程,請呼叫 purchase。在啟動購買流程之前,你**必須**查詢該專案的 SKU 詳情。

purchase() 的範例用法:

payment.purchase("my_iap_item")

支付流程將在成功時發送“purchases_updated”訊號,在失敗時發送“purchase_error”訊號。

func _on_purchases_updated(purchases):
    for purchase in purchases:
        _process_purchase(purchase)

func _on_purchase_error(response_id, error_message):
    print("purchase_error id:", response_id, " message: ", error_message)

建立內容

“query_purchases_response” 和 “purchases_updated” 訊號以 Dictionary <class_Dictionary> 格式提供一系列購買。購買字典包含對應到 Google Play Billing Purchase 類別的值的鍵。

購買專案:

dictionary.put("order_id", purchase.getOrderId());
dictionary.put("package_name", purchase.getPackageName());
dictionary.put("purchase_state", purchase.getPurchaseState());
dictionary.put("purchase_time", purchase.getPurchaseTime());
dictionary.put("purchase_token", purchase.getPurchaseToken());
dictionary.put("quantity", purchase.getQuantity());
dictionary.put("signature", purchase.getSignature());
// PBL V4 replaced getSku with getSkus to support multi-sku purchases,
// use the first entry for "sku" and generate an array for "skus"
ArrayList<String> skus = purchase.getSkus();
dictionary.put("sku", skus.get(0)); # Not available in plugin
String[] skusArray = skus.toArray(new String[0]);
dictionary.put("products", productsArray);
dictionary.put("is_acknowledged", purchase.isAcknowledged());
dictionary.put("is_auto_renewing", purchase.isAutoRenewing());

檢查購買狀態

檢查購買的“purchase_state”值以確定購買是否已完成或仍待處理。

PurchaseState 取值:

# Matches Purchase.PurchaseState in the Play Billing Library
enum PurchaseState {
    UNSPECIFIED,
    PURCHASED,
    PENDING,
}

如果購買處於「待處理」狀態,則在達到「已購買」狀態之前,您不應授予購買的內容或對購買進行任何進一步處理。如果您有商店介面,您可能想要顯示有關需要在 Google Play 商店中完成的待處理購買的資訊。有關待處理購買的更多詳細信息,請參閱 Google Play 結算庫文件中的“處理待處理交易 <https://developer.android.com/google/play/billing/integrate#pending>”。

常數

如果你的應用內物品不是一次性購買,而是可以多次購買的消耗品(如硬幣),你可以用購買權杖呼叫 consumePurchase 來消耗物品。呼叫 queryPurchases 來獲取購買權杖。呼叫 consumePurchase 會自動確認購買。消耗產品後,使用者就可以再一次進行購買,同時也會將其從後續 queryPurchases 的返回中移除。

consumePurchase() 的範例用法:

func _process_purchase(purchase):
    if "my_consumable_iap_item" in purchase.products and purchase.purchase_state == PurchaseState.PURCHASED:
        # Add code to store payment so we can reconcile the purchase token
        # in the completion callback against the original purchase
        payment.consumePurchase(purchase.purchase_token)

func _on_purchase_consumed(purchase_token):
    _handle_purchase_token(purchase_token, true)

func _on_purchase_consumption_error(response_id, error_message, purchase_token):
    print("_on_purchase_consumption_error id:", response_id,
            " message: ", error_message)
    _handle_purchase_token(purchase_token, false)

# Find the sku 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

確認購買

如果您的應用程式內商品是一次性購買,則必須透過呼叫「acknowledgePurchase()」函式並傳遞購買字典中的「purchase_token」值來確認購買。如果您在三天內未確認購買,使用者將自動收到退款,並且 Google Play 會撤銷購買。如果您呼叫“comsumePurchase()”,它會自動確認購買,您無需呼叫“acknowledgePurchase()”。

acknowledgePurchase() 的範例用法:

func _process_purchase(purchase):
    if "my_one_time_iap_item" in purchase.products and \
            purchase.purchase_state == 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
        payment.acknowledgePurchase(purchase.purchase_token)

func _on_purchase_acknowledged(purchase_token):
    _handle_purchase_token(purchase_token, true)

func _on_purchase_acknowledgement_error(response_id, error_message, purchase_token):
    print("_on_purchase_acknowledgement_error id: ", response_id,
            " message: ", error_message)
    _handle_purchase_token(purchase_token, false)

# Find the sku 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

說明

訂閱的工作原理和普通的應用內專案沒有太大區別. 只要使用 "subs" 作為 querySkuDetails() 的第二個參數, 就可以得到訂閱的詳細資訊. 在 queryPurchases() 的結果中檢查 is_auto_renewing 來查看使用者是否取消了自動更新的訂閱。

您可以在從“queryPurchases()”返回的訂閱購買中檢查“is_auto_renewing”,以查看使用者是否取消了自動續訂訂閱。

您需要確認新的訂閱購買,但不需要確認自動訂閱續訂。

如果您支援在不同訂閱等級之間升級或降級,則應使用 updateSubscription() 來使用訂閱更新流程來變更活動訂閱。與“purchase()”一樣,結果由“purchases_updated”和“purchase_error”訊號傳回。 updateSubscription() 有三個參數:

  1. 目前有效訂閱的購買令牌

  2. 要變更為的訂閱 SKU 的產品 ID 字串

  3. 適用於訂閱的按比例分配模式。

比例值定義為:

enum SubscriptionProrationMode {
    # Replacement takes effect immediately, and the remaining time
    # will be prorated and credited to the user.
    IMMEDIATE_WITH_TIME_PRORATION = 1,
    # Replacement takes effect immediately, and the billing cycle remains the same.
    # The price for the remaining period will be charged.
    # This option is only available for subscription upgrade.
    IMMEDIATE_AND_CHARGE_PRORATED_PRICE,
    # Replacement takes effect immediately, and the new price will be charged on
    # next recurrence time. The billing cycle stays the same.
    IMMEDIATE_WITHOUT_PRORATION,
    # Replacement takes effect when the old plan expires, and the new price
    # will be charged at the same time.
    DEFERRED,
    # 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.
    IMMEDIATE_AND_CHARGE_FULL_PRICE,
}

預設行為是“IMMEDIATE_WITH_TIME_PRORATION”。

StaticBody2D 的範例用法:

payment.updateSubscription(_active_subscription_purchase.purchase_token, \
                                            "new_sub_sku", SubscriptionProrationMode.IMMEDIATE_WITH_TIME_PRORATION)

confirmPriceChange() 函式可用於啟動訂閱的價格變更確認流程。傳遞價格變動的訂閱 SKU 的產品 ID。結果將透過「price_change_acknowledged」訊號發送。

“confirmPriceChange()”的使用範例:

enum BillingResponse {SUCCESS = 0, CANCELLED = 1}

func confirm_price_change(product_id):
    payment.confirmPriceChange(product_id)

func _on_price_acknowledged(response_id):
    if response_id == BillingResponse.SUCCESS:
        print("price_change_accepted")
    elif response_id == BillingResponse.CANCELED:
        print("price_change_canceled")