本主题介绍如何脱离使用 Android 接口定义语言 (AIDL) 的结算服务集成。使用 AIDL 访问 Google Play 结算系统这种方式已被弃用,日后所有集成都必须使用 Google Play 结算库。
迁移步骤
导入 Google Play 结算库
首先,为 Google Play 结算库添加依赖项。如果您使用的是 Gradle,则可将以下内容添加到应用的 build.gradle
文件中:
Groovy
dependencies { def billing_version = "6.1.0" implementation "com.android.billingclient:billing:$billing_version" }
Kotlin
dependencies { val billing_version = "6.1.0" implementation("com.android.billingclient:billing:$billing_version") }
您可以删除任何“粘合”代码(例如 IabHelper
),这些代码可能是您从以前的参考代码中复制的。IabHelper
所提供的功能现在已包含在 Google Play 结算库中。
移除 com.android.vending.BILLING
权限
Google Play 结算库在其清单中嵌入了 com.android.vending.BILLING
权限。因此,应用的清单中无需再明确添加此权限。
连接到 Google Play 结算服务
Google Play 结算库方法 BillingClient
可为您管理连接。如需进行迁移,请对您的应用做出如下更改:
- 创建
BillingClient
的实例。 - 实现
BillingClientStateListener
以接收有关服务状态的回调。 - 在
BillingClient
实例上调用startConnection()
。 - 移除与应用内购买相关的
onActivityResult()
代码,并将其移至PurchasesUpdatedListener
。
以下示例是应用在进行这些更改前后的比较:
之前
mServiceConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
...
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
...
}
};
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
List<ResolveInfo> intentServices = mContext.getPackageManager()
.queryIntentServices(serviceIntent, 0);
if (intentServices != null && !intentServices.isEmpty()) {
mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
} else {
// Handle errors.
...
}
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IabResult result;
if (requestCode != mRequestCode || data == null) {
// Handle errors.
...
}
int responseCode = getResponseCodeFromIntent(data);
String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA);
String dataSignature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE);
if (resultCode != Activity.RESULT_OK || responseCode != BILLING_RESPONSE_RESULT_OK) {
// Handle errors.
...
}
// Process successful purchase.
...
return true;
}
之后
Kotlin
class MyBillingImpl(private var billingClient: BillingClient) : PurchasesUpdatedListener { init { billingClient = BillingClient.newBuilder(activity).setListener(this).build() billingClient.startConnection(object : BillingClientStateListener { override fun onBillingSetupFinished(billingResult: BillingResult?) { // Logic from ServiceConnection.onServiceConnected should be moved here. } override fun onBillingServiceDisconnected() { // Logic from ServiceConnection.onServiceDisconnected should be moved here. } }) } override fun onPurchasesUpdated( billingResult: BillingResult?, purchases: MutableList<Purchase>? ) { // Logic from onActivityResult should be moved here. } }
Java
public class MyBillingImpl implements PurchasesUpdatedListener { private BillingClient billingClient; ... public void initialize() { billingClient = BillingClient.newBuilder(activity).setListener(this).build(); billingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(BillingResult billingResult) { // Logic from ServiceConnection.onServiceConnected should be moved here. } @Override public void onBillingServiceDisconnected() { // Logic from ServiceConnection.onServiceDisconnected should be moved here. } }); } @Override public void onPurchasesUpdated( @BillingResponse int responseCode, @Nullable List<Purchase> purchases) { // Logic from onActivityResult should be moved here. } }
进行购买
如需启动购买对话框,请执行以下操作:
- 将 SKU 详细信息
Bundle
转换为SkuDetailsParams
。 - 将
mService.getSkuDetails()
调用改为BillingClient.querySkuDetailsAsync()
- 将购买 intent
Bundle
转换为BillingFlowParams
对象。 - 将
mService.getBuyIntent()
调用改为BillingClient.launchBillingFlow()
。 - 从
onActivityResult()
移除所有与应用内购买相关的代码,并将此代码移至PurchasesUpdatedListener
。
以下示例是应用在进行这些更改前后的比较:
之前
// Query Skus
String skuToSell = "premium_upgrade";
ArrayList<String> skus = new Arraylist<>();
skus.add(skuToSell);
Bundle querySkus = new Bundle();
querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skus);
Bundle skuDetails = mService.getSkuDetails(3,
mContext.getPackageName(),
itemType,
querySkus);
if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) {
// Handle errors.
...
}
// Launch Buy Flow
Bundle buyIntentBundle = mService.getBuyIntent(3,
mContext.getPackageName(),
skuToSell,
"Inapp",
"");
int response = getResponseCodeFromBundle(buyIntentBundle);
if (response != BILLING_RESPONSE_RESULT_OK) {
// Handle errors.
...
}
PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT);
act.startIntentSenderForResult(pendingIntent.getIntentSender(),
requestCode,
new Intent(),
Integer.valueOf(0),
Integer.valueOf(0),
Integer.valueOf(0));
// Purchase is handled in onActivityResult illustrated in the previous section.
之后
Kotlin
val skuToSell = "premium_upgrade" val skuList = mutableListOf<String>() skuList.add(skuToSell) val params = SkuDetailsParams.newBuilder() params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP) billingClient.querySkuDetailsAsync(params.build(), object : SkuDetailsResponseListener { override fun onSkuDetailsResponse( billingResult: BillingResult?, skuDetailsList: MutableList<SkuDetails>?) { // Process the result. } }) // SkuDetails object obtained above. val skuDetails = ... val purchaseParams = BillingFlowParams.newBuilder() .setSkuDetails(skuDetails) .build() billingClient.launchBillingFlow(activity, purchaseParams) // Purchase is handled in onPurchasesUpdated illustrated in the previous section
Java
String skuToSell = "premium_upgrade"; List<String> skuList = new ArrayList<> (); skuList.add(skuToSell); SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); params.setSkusList(skuList).setType(SkuType.INAPP); billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { @Override public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) { // Process the result. ... } }); // SkuDetails object obtained above. SkuDetails skuDetails = ...; BillingFlowParams purchaseParams = BillingFlowParams.newBuilder() .setSkuDetails(skuDetails) .build(); mBillingClient.launchBillingFlow(mActivity, purchaseParams); // Purchase is handled in onPurchasesUpdated illustrated in the previous section.
消耗所购商品
如需使用 Google Play 结算库消耗所购商品,请执行以下操作:
以下示例是应用在进行这些更改前后的比较:
之前
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
int responseCode = data.getIntExtra(RESPONSE_CODE);
JSONObject purchaseData =
new JSONObject(data.getStringExtra("INAPP_PURCHASE_DATA"));
String token = purchaseData.get("purchaseToken");
...
// Consume purchase
int response = mService.consumePurchase(3, mContext.getPackageName(), token);
if (response != BILLING_RESPONSE_RESULT_OK) {
// Handle errors.
...
}
// Handle successful consumption.
}
之后
Kotlin
class MyBillingImpl(private val billingClient: BillingClient) : ... , ConsumeResponseListener { fun consumePurchase(purchaseToken: String) { val consumeParams = ConsumeParams .newBuilder() .setPurchaseToken(purchaseToken) .build() } override fun onConsumeResponse( billingResult: BillingResult?, purchaseToken: String?) { // Handle consumption } }
Java
public class MyBillingImpl implements ..., ConsumeResponseListener { private BillingClient billingClient; ... public void consumePurchase(String purchaseToken) { ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchaseToken) .build(); } @Override void onConsumeResponse(BillingResult billingResult, String purchaseToken) { // Handle consumption. ... } }
确认购买交易
从 Google Play 结算库 2.0 版开始,您的应用必须消耗所有所购商品或确认所有购买交易。
如果您在三天内未消耗所购商品或确认购买交易,Google 会自动撤消购买交易并向用户退款。如需了解详情,请参阅确认购买交易。
识别应用外购买
如需将应用外购买交易的处理迁移到 Google Play 结算库,请执行以下操作:
- 确保您的应用在其
onResume()
回调中调用BillingClient.queryPurchasesAsync()
。 - 移除
com.android.vending.billing.PURCHASES_UPDATED
的广播接收器,并将相应回调代码移至PurchasesUpdatedListener
。
以前,将 Google Play 结算服务与 AIDL 集成时,您的应用需要注册监听器才能接收 com.android.vending.billing.PURCHASES_UPDATED
intent,用于处理应用外购买交易。
使用 Google Play 结算库时,您应始终先在应用的 onResume()
回调中调用 queryPurchasesAsync()
,以确保识别出在应用未运行期间完成的所有购买交易。在应用运行时,Google Play 结算库会自动监听应用外购买交易,并通过 PurchasesUpdatedListener
通知您。
处理待处理的交易
从 Google Play 结算库 2.0 版开始,应用必须处理某些待处理的交易,这些交易需要在购买后执行额外操作,然后才能授予使用权。例如,用户可能会选择使用现金在实体店购买您的应用内商品。也就是说,交易是在应用外部完成的。在这种情况下,只有在用户完成交易后,您才能授予使用权。
如需了解详情,请参阅支持待处理的交易。
开发者载荷
开发者载荷向来被用于各种不同用途,包括防欺诈以及将购买交易归因于正确的用户。由于 Google Play 结算库现已支持这些用例,因此从 Google Play 结算库 2.2 版开始,我们已弃用开发者载荷。如需了解详情,请参阅开发者载荷。
详细的错误消息
从 Google Play 结算库 2.0 版开始,所有错误都包含相应的调试相关消息。这些消息可以通过调用 BillingResult.getDebugMessage()
获得。