欢迎参加我们将于 6 月 3 日举行的 #Android11:Beta 版发布会

从 AIDL 迁移到 Google Play 结算库的迁移指南

本主题介绍如何停止使用采用 Android 接口定义语言 (AIDL) 的 Google Play 结算服务集成。使用 AIDL 访问 Google Play 结算服务的功能已弃用,今后所有集成都必须使用 Google Play 结算库。

迁移步骤

导入 Google Play 结算库

首先,向 Google Play 结算库添加依赖项。如果您使用的是 Gradle,则可将以下内容添加到应用的 build.gradle 文件中:

dependencies {
        implementation 'com.android.billingclient:billing:2.2.0'
    }
    

您可以删除任何“粘合”代码(例如 IabHelper),这些代码可能是您从以前的参考代码中复制的。IabHelper 所提供的功能现在已包含在 Google Play 结算库中。

移除 com.android.vending.BILLING 权限

Google Play 结算库在其清单中嵌入了 com.android.vending.BILLING 权限。因此,应用的清单中无需再明确添加此权限。

连接到 Google Play 结算服务

Google Play 结算库的 BillingClient 负责为您处理连接管理。要进行迁移,请对您的应用做出如下更改:

应用在进行这些更改前后如以下示例所示:

之前

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.
        }
    }
    

进行购买

要启动购买对话框,请执行以下操作:

应用在进行这些更改前后如以下示例所示:

之前

// 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 结算库,请执行以下操作:

以前,将 Google Play 结算服务与 AIDL 集成时,您的应用需要注册监听器才能接收 com.android.vending.billing.PURCHASES_UPDATED intent,用于处理在应用外完成的购买交易。

使用 Google Play 结算库时,您的应用始终应首先在应用的 onResume() 回调中调用 queryPurchases(),以确保识别在应用未运行期间完成的所有购买交易。在应用运行时,结算库会自动监听应用外购买交易,并通过 PurchasesUpdatedListener 通知您。

处理待处理的交易

从 Google Play 结算库 2.0 版开始,应用必须处理待处理的交易,这些交易需要在购买后先执行其他操作,然后才能授予权利。例如,用户可能会选择使用现金在实体店购买您的应用内商品。也就是说,交易是在应用外部完成的。在这种情况下,只有在用户完成交易后,您才能授予权利。

如需了解详情,请参阅支持待处理的交易

开发者载荷

开发者载荷向来被用于各种不同用途,包括防欺诈以及将购买交易归因于正确的用户。由于 Google Play 结算库现已支持这些用例,因此从 Google Play 结算库 2.2 版开始,我们已弃用开发者载荷。如需了解详情,请参阅开发者载荷

详细的错误消息

从 Google Play 结算库 2.0 版开始,所有错误都包含相应的调试相关消息。这些消息可以通过调用 BillingResult.getDebugMessage() 来获得。