在 AIDL 中採用 Google Play 帳單系統

警告:AIDL 目前已淘汰,並將在日後推出的版本中移除。如要導入帳單相關功能,請使用 Google Play 帳款服務程式庫

您可以運用 Android 介面定義語言 (AIDL) 介面導入 Google Play 帳單系統的部分功能。

購買產品

圖 1. 購物要求的基本流程。

Google Play Billing AIDL API 的一般購買流程如下所示:

  1. 您的應用程式傳送 isBillingSupported 要求至 Google Play,確認 Google Play 是否支援您使用的 Google Play Billing AIDL API 目標版本。這項要求也會驗證 Google Play 是否支援使用者所在國家/地區的帳單系統服務。
  2. 當您的應用程式開始提供服務或使用者登入後,建議您前往 Google Play 確認使用者擁有哪些商品。如要查詢使用者的購買交易,請傳送 getPurchases 要求。如果要求成功,Google Play 會傳回 Bundle,當中包含已購買商品的產品 ID 清單、個別購物交易詳細資料清單,以及購物交易的簽名清單。
  3. 通常我們會建議您將可購買產品的相關資訊告知使用者。如要查詢您在 Google Play 中定義的應用程式內產品詳細資料,應用程式可以傳送 getSkuDetails 要求。您必須在查詢要求中指定產品 ID 清單。如果要求成功,Google Play 會傳回 Bundle,其中包含產品的價格、名稱、說明和購買類型等產品詳細資料。
  4. 如果使用者尚未擁有應用程式內產品,可以購買該產品。如要發起購買要求,您的應用程式會傳送 getBuyIntent 要求,並指定要購買的商品的產品 ID 以及其他參數。當您在 Google Play 管理中心建立新的應用程式內產品時,請務必記錄產品 ID。
    1. Google Play 傳回的 Bundle 包含 PendingIntent,您的應用程式會將其用於啟動購買交易的結帳 UI。
    2. 您的應用程式藉由呼叫 startIntentSenderForResult 方法建立待處理的 Intent。
    3. 完成結帳流程 (也就是使用者成功購買商品或取消購買) 後,Google Play 會傳送回應 Intent 至您的 onActivityResult 方法。onActivityResult 的結果碼中會有一個結果碼,用於指出使用者成功完成購買或是取消購買。回應 Intent 包含已購買商品的相關資訊,包括 Google Play 為了專門識別這個購買交易而產生的 purchaseToken 字串。另外,Intent 也包含使用您開發人員私密金鑰簽署的購物交易簽名。

如要進一步瞭解 Google Play Billing AIDL API 呼叫和伺服器回應,請參閱這篇文章的 Google Play Billing AIDL API 參考資料。

消耗應用程式內產品

您可以使用消耗機制追蹤使用者對納入管理產品的擁有權。

所有納入管理的產品都會透過 Google Play Billing AIDL API 管理。也就是說,購買納入管理的產品後,使用者對所有納入管理產品的擁有權都會由 Google Play 維護,而且您的應用程式可視需要查詢使用者的購物資訊。 當使用者成功購買納入管理的產品後,Google Play 就會記錄該筆購買交易。納入管理的產品一經購買,就會被視為「已有擁有者」。如果納入管理的產品處於「已有擁有者」狀態,則無法透過 Google Play 購買。您必須針對「已有擁有者」的納入管理的產品傳送消耗要求,Google Play 才會將該產品再次上架。消耗納入管理的產品後,產品的狀態會回復到「沒有擁有者」狀態,並刪除先前的購買資料。

圖 2. 消耗要求的基本流程。

如要擷取使用者擁有的產品清單,應用程式會傳送 getPurchases 呼叫至 Google Play。您的應用程式可透過傳送 consumePurchase 呼叫提出消耗要求。在要求引數中,您必須指定購買納入管理的產品時從 Google Play 取得的不重複 purchaseToken 字串。Google Play 會傳回狀態碼,指出消耗要求是否已成功記錄。

非消耗性與消耗性的納入管理產品

您可以自行決定要將納入管理的產品做為非消耗性產品還是消耗性產品處理。

非消耗性產品
一般來說,如果納入管理的產品只能在應用程式中購買一次,而且購買後即享有永久福利,我們就不會將這類產品當做消耗性產品,這是因為這些產品在售出後會永久與使用者的 Google 帳戶建立關聯。例如,付費升級或等級包都屬於非消耗性納入管理的產品。
消耗性產品
另一方面,對於可多次購買的產品,您可以將其設定為消耗性產品。一般來說,這些產品可提供特定暫時性效果。例如,使用者的遊戲內角色可從道具欄中取得生命點數或額外的金幣。在應用程式中提供已購買產品的福利或效果,就是在「佈建」納入管理的產品。您負責控管及追蹤如何向使用者佈建納入管理的產品。

重要事項:您必須先傳送消耗要求給 Google Play,並在收到指出此次消耗已記錄的成功回覆後,才能在應用程式中佈建消耗性納入管理的產品。

管理應用程式內消耗性產品的購買

以下是購買消耗性納入管理的產品的基本流程:

  1. 呼叫 getBuyIntent 方法可啟動購買流程。
  2. 檢查 Google Play 傳回的 Bundle,確定購買交易是否順利完成。
  3. 如果購買成功,請透過呼叫 consumePurchase 方法來消耗購買的產品。
  4. 檢查來自 Google Play 的回應代碼,確定消耗是否已順利完成。
  5. 如果消耗成功,請在應用程式中佈建產品。

隨後,當使用者開啟或登入您的應用程式時,建議您檢查使用者是否擁有任何尚未消耗的消耗性應用程式內產品;如果有的話,請務必消耗和佈建這些商品。如果您的應用程式中有消耗性應用程式內產品,建議您採用以下的應用程式啟動流程:

  1. 傳送 getPurchases 要求,查詢使用者擁有的應用程式內產品。
  2. 如有任何消耗性應用程式內產品,請呼叫 consumePurchase 來消耗這些商品。這個步驟絕不可省略,因為應用程式可能已完成消耗性產品的購買訂單,但在傳送消耗要求前暫停處理或中斷連線。
  3. 檢查來自 Google Play 的回應代碼,確定消耗是否已順利完成。
  4. 如果消耗成功,請在應用程式中佈建產品。

設定購買獎勵

警告:我們已不再支援獎勵商品。詳情請參閱建立獎勵商品

使用 AIDL 處理獎勵商品時,您應在使用者要收取獎勵之前快取購買「Intent」。您可以在背景執行緒呼叫購買 Intent 並儲存成功的回應「Intent」,直到使用者採取行動收取獎勵。

列出並載入 SKU

在為使用者提供獎勵商品前,請先透過呼叫 getSkuDetails() 取得產品詳細資料。系統會為 SKU 清單中的每個獎勵商品填入新的 JSON 欄位「rewardToken」。

為提供最佳的使用者體驗,請務必在提供獎勵商品給使用者之前,確定廣告已載入且可使用。為此,請在背景執行緒呼叫 getBuyIntentExtraParams()。收到 BILLING_RESPONSE_RESULT_OK 的回應後,請為使用者啟用獎勵商品,然後儲存傳回的 PendingIntent 物件以供日後使用。 下列程式碼片段演示載入與獎勵商品相關聯廣告的流程:

Kotlin

val rewardToken = skuDetailsJson.optString("rewardToken")
val extraParams = Bundle().putString("rewardToken", rewardToken)

// This call blocks the current thread, so do this in the background.
val buyIntentBundle : Bundle = mService.getBuyIntentExtraParams(9, packageName,
        sku, "inapp", "", extraParams)

val response = buyIntentBundle.getInt("RESPONSE_CODE")
if (response == BILLING_RESPONSE_RESULT_OK) {
    // Enable rewarded product.

    // Save this object for use later.
    val pendingIntentToSave = bundle.getParcelable(RESPONSE_BUY_INTENT)
} else {
    // Don't offer rewarded product.
}

Java

String rewardToken = skuDetailsJson.optString("rewardToken");
Bundle extraParams = new Bundle();
extraParams.putString("rewardToken", rewardToken);

// This call blocks the current thread, so do this in the background.
Bundle buyIntentBundle = mService.getBuyIntentExtraParams(9, getPackageName(),
        sku, "inapp", "", extraParams);

int response = buyIntentBundle.getInt("RESPONSE_CODE");
if (response == BILLING_RESPONSE_RESULT_OK) {
    // Enable rewarded product.

    // Save this object for use later.
    PendingIntent pendingIntentToSave = bundle.getParcelable(RESPONSE_BUY_INTENT);
} else {
    // Don't offer rewarded product.
}

聲明適齡的廣告

為協助遵守《兒童網路隱私保護法》(COPPA) 和《一般資料保護規則》(GDPR) 等兒童和未成年使用者相關的法律義務,您的應用程式必須聲明哪些廣告在美國應視為兒童導向廣告,還有哪些廣告以未滿所在國家/地區適用規定年齡的使用者為導向。AdMob 說明中心的文章說明在哪些情況下應將廣告請求標記為兒童導向內容適合未滿規定年齡使用者的內容,並詳述標記後的影響。

如要表示獎勵要求是針對兒童或未滿規定年齡的使用者,請加入 childDirectedunderAgeOfConsent 額外參數,如以下程式碼片段所示:

Kotlin

val rewardToken = skuDetailsJson.optString("rewardToken")
val extraParams = Bundle().putString("rewardToken", rewardToken)
        .putInt("childDirected", ChildDirected.CHILD_DIRECTED)
        .putInt("underAgeOfConsent", UnderAgeOfConsent.UNDER_AGE_OF_CONSENT)

// This call blocks the current thread, so do this in the background.
val buyIntentBundle : Bundle = mService.getBuyIntentExtraParams(9, packageName,
        sku, "inapp", "", extraParams)

Java

Bundle extraParams = new Bundle();
extraParams.putString("rewardToken", rewardToken);
extraParams.putInt("childDirected", ChildDirected.CHILD_DIRECTED);
extraParams.putInt("underAgeOfConsent", UnderAgeOfConsent.UNDER_AGE_OF_CONSENT);

// This call blocks the current thread, so do this in the background.
Bundle buyIntentBundle =
  mService.getBuyIntentExtraParams(
    9, getPackageName(), sku, "inapp", "", extraParams);

在獎勵使用者之前播放廣告

在使用者點選按鈕開始觀看廣告後,您的應用程式可使用儲存的 PendingIntent 物件開始播放廣告。為此,請呼叫 startIntentSenderForResult()

Kotlin

startIntentSenderForResult(
    pendingIntentToSave,
    RC_BUY, Intent(),
    0,
    0,
    0
)

Java

startIntentSenderForResult(pendingIntentToSave, RC_BUY, new Intent(),
        0, 0, 0);

接著,請按照下列程式碼片段所示,處理 onActivityResult() 中的帳單工作流程結果。處理廣告播放流程時,Google Play 會比照處理其他帳單流程的狀況,使用同一組伺服器回應代碼

Kotlin

fun onActivityResult(requestCode : Int, resultCode : Int, data : Intent) {
    if (requestCode == RC_BUY) {
        int responseCode = data.getIntExtra(RESPONSE_CODE)
        String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA)
        String signature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE)

        // Handle reward purchase.
    }
}

Java

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == RC_BUY) {
        int responseCode = data.getIntExtra(RESPONSE_CODE);
        String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA);
        String signature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE);

        // Handle reward purchase.
    }
}

本機快取

Google Play 用戶端現在可直接在裝置上快取帳單資訊,因此您可以透過 Google Play Billing AIDL API 更頻繁地查詢這項資訊。下列 Google Play Billing AIDL API 呼叫執行時採用快取查詢,不必使用網路連線,進而大幅加快 API 的回應時間:

  • getBuyIntent
  • getPurchases
  • isBillingSupported