开发者控制台

实现Google Play Billing接口

实现Google Play Billing接口

本页详细介绍了您的应用如何使用亚马逊应用商店计费兼容性SDK实现应用内购买。如果已将应用与Google Play Billing结算库集成,则在大多数步骤中都无需更改代码或只需进行极少的更改。

有关详细的API参考,请参阅亚马逊应用商店计费兼容性SDK API参考

初始化BillingClient

此处无需更改代码。

按照亚马逊应用商店计费兼容性SDK中的步骤操作之后,初始化BillingClient实例。BillingClient对象支持亚马逊应用商店计费兼容性API和您的应用之间的通信。BillingClient为许多常用计费操作提供了异步便捷方法。

和Google Play Billing一样,强烈建议您一次仅实例化一个BillingClient 实例。但是,使用亚马逊应用商店计费兼容性SDK,一次实例化多个BillingClient实例的做法不会导致单个购买事件出现多个PurchasesUpdatedListener回调。相反,每个新的BillingClient实例化都会将PurchasesUpdatedListener更新为提供的新侦听器,即使对于其他BillingClient实例也是如此。

使用newBuilder()方法创建BillingClient。要接收购买更新,请通过调用setListener()添加侦听器。将PurchasesUpdatedListener对象传递给setListener()方法。

enablePendingPurchases()方法只能作为无操作方法使用。它不支持待处理的购买。

以下代码展示了如何初始化BillingClient

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        // 待实现
    }
};

private BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .build();

连接到亚马逊应用商店

此处无需更改代码。

和在Google Play中建立连接的要求不同,亚马逊应用商店没有任何保持连接的概念。由于亚马逊应用商店不需要保持连接,因此您无需监测连接是否中断。与连接相关的API以无操作方法的形式受到支持,该方法假定连接始终就绪。

调用startConnection()时,BillingClientStateListener总会收到包含BillingResponseCode.OK的回调。onBillingServiceDisconnected()方法以无操作方法的形式提供,亚马逊应用商店计费兼容性SDK从不引用该方法。

以下示例演示了如何连接到亚马逊应用商店。

billingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(BillingResult billingResult) {
        if (billingResult.getResponseCode() == BillingResponseCode.OK) {
            //在亚马逊应用商店计费兼容性SDK中,BillingClientStateListener总会收到
            //包含BillingResponseCode.OK的回调。

            // 在此处查询产品和购买。
        }
    }

    @Override
    public void onBillingServiceDisconnected() {
        // 这是一种无操作方法,亚马逊应用商店计费兼容性SDK从不引用该方法。
    }
});

显示可供购买的产品

此处无需更改代码。

在向用户展示产品之前,请务必查询产品详细信息以获取本地化产品信息。可以调用queryProductDetailsAsync()querySkuDetailsAsync()以查询应用内产品详细信息。

亚马逊应用商店计费兼容性SDK返回的错误响应代码只有BillingResponseCode.DEVELOPER_ERRORBillingResponseCode.ERROR。也可使用Google Play Billing支持的其他错误响应代码,但从不返回这些代码。

QueryProductDetailsAsync API

可以使用queryProductDetailsAsync()方法查询产品详细信息。此方法采用QueryProductDetailsParams的实例。QueryProductDetailsParams对象会指定一个列表,其中包含您在亚马逊开发者控制台中创建的产品ID字符串,同时会指定ProductType。对于消费品和权利,ProductTypeProductType.INAPP。对于订阅,ProductTypeProductType.SUBS

对于订阅产品,API返回订阅优惠详细信息列表,即List<ProductDetails.SubscriptionOfferDetails>,其中包含用户可使用的所有优惠。每项优惠都有一个唯一的优惠令牌,您可以使用getOfferToken()方法访问该令牌。启动购买流程时,您必须传递优惠令牌。您可以使用API响应的getOneTimePurchaseOfferDetails()方法访问一次性购买应用程序内商品的优惠详细信息。

要处理异步操作的结果,queryProductDetailsAsync()方法还需要侦听器。此侦听器是ProductDetailsResponseListener接口的实现,会覆盖onProductDetailsResponse()onProductDetailsResponse()方法会在产品详细信息查询完成后通知侦听器,如以下示例所示。

QueryProductDetailsParams queryProductDetailsParams =
    QueryProductDetailsParams.newBuilder()
        .setProductList(
            ImmutableList.of(
                Product.newBuilder()
                    .setProductId("product_id_example")
                    .setProductType(ProductType.INAPP)
                    .build()))
        .build();

billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
        public void onProductDetailsResponse(BillingResult billingResult,
                List<ProductDetails> productDetailsList) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // 处理返回的skuDetailsList。
            } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
                // 处理错误响应。
            } else if (billingResult.getResponseCode() == BillingResponseCode.DEVELOPER_ERROR) {
                // 处理开发者错误响应。
            } else {
                //也可使用其他错误代码,但亚马逊应用商店计费兼容性SDK
                //从不返回这些代码。
            }
        }
    }
);

和Google Play Billing不同,ProductDetails.getTitle()不包含应用名称。

QuerySkuDetailsAsync API

可以使用querySkuDetailsAsync()方法查询SKU详细信息。此方法采用SkuDetailsParams实例,该实例会指定一个列表,其中包含在亚马逊开发者控制台中创建的SKU字符串,同时会指定SkuType。对于消费品和权利,SkuTypeSkuType.INAPP。对于订阅,SkuTypeSkuType.SUBS

要处理异步操作的结果,querySkuDetailsAsync()还需要侦听器。此侦听器是SkuDetailsResponseListener接口的实现,会覆盖onSkuDetailsResponse()onSkuDetailsResponse()方法会在SKU详细信息查询完成后通知侦听器,如以下示例所示。

SkuDetailsParams skuDetailsParams =
    SkuDetailsParams.newBuilder()
            .setType(BillingClient.SkuType.INAPP)
            .setSkusList(skusList)
            .build();

billingClient.querySkuDetailsAsync(
    skuDetailsParams,
    new SkuDetailsResponseListener() {
        public void onSkuDetailsResponse(BillingResult billingResult,
               List<SkuDetails> skuDetailsList) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // 处理返回的skuDetailsList。
            } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
                // 处理错误响应。
            } else if (billingResult.getResponseCode() == BillingResponseCode.DEVELOPER_ERROR) {
                // 处理开发者错误响应。
            } else {
                //也可使用其他错误代码,但亚马逊应用商店计费兼容性SDK
                //从不返回这些代码。
            }
        }
    }
);

启动购买流程

此处可能需要对代码进行极少的更改。

和Google Play Billing不同,亚马逊应用商店计费兼容性SDK允许在单次购买中使用最多一种产品。如果列表中有多个商品,则会返回错误BillingResponseCode.FEATURE_NOT_SUPPORTED

要让应用启动购买流程,请从应用的主线程调用launchBillingFlow()launchBillingFlow()方法采用BillingFlowParams对象,其中包含ProductDetails对象。可以通过调用queryProductDetailsAsync()来获取ProductDetails。使用BillingFlowParams.Builder类创建BillingFlowParams对象。以下示例展示了如何启动结算流程。

// 启动结算流程的活动参考
Activity activity = ...;

ImmutableList productDetailsParamsList =
    ImmutableList.of(
        ProductDetailsParams.newBuilder()
             // 调用queryProductDetailsAsync获取productDetails
            .setProductDetails(productDetails)
            .build()
    );

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build();

// 启动结算流程
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

以下代码显示了为购买设置优惠令牌的示例。有关优惠令牌的更多详细信息,请参阅QueryProductDetailsAsync API

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setOfferToken(offerDetails.getOfferToken())
.build();

或者,可以使用通过调用querySkuDetailsAsync()获得的SkuDetails来初始化BillingFlowParams对象,如下所示。

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
     .setSkuDetails(skuDetails)
     .build();

当初始化BillingClient时,使用了setLister()PurchasesUpdatedListener的实现添加为侦听器。此侦听器会覆盖onPurchasesUpdated()方法,该方法可提供购买结果。onPurchasesUpdated()的实现必须处理可能出现的响应代码,如以下示例所示。

@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
    if (billingResult.getResponseCode() == BillingResponseCode.OK) {
        for (Purchase purchase : purchases) {
            handlePurchase(purchase);
        }
    } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
        // 处理购买流程中的错误。
    } else if (billingResult.getResponseCode() == BillingResponseCode.DEVELOPER_ERROR) {
        // 处理购买流程中的开发者错误。
    } else {
        //也可使用其他错误代码,但亚马逊应用商店计费兼容性SDK
        //从不返回这些代码。
    }
}

亚马逊应用商店计费兼容性SDK返回的错误响应代码只有BillingResponseCode.DEVELOPER_ERRORBillingResponseCode.ERROR。也可使用Google Play Billing支持的其他错误响应代码,但从不返回这些代码。

成功购买后,会生成购买令牌。购买令牌是某次购买的唯一标识,代表了与该次购买相关的用户和产品ID。

不支持的字段

亚马逊应用商店计费兼容性SDK不支持Google Play Billing提供的以下字段。请从代码中删除对这些字段的引用。

请求字段:

  • Account identifiers(Obfuscated Account ID和Obfuscated Profile ID)
  • VR Purchase Flow

响应字段:

  • Account identifiers(Obfuscated Account ID和Obfuscated Profile ID)
  • Order ID
  • Signature
  • Package name
  • Acknowledged

注意:​ 亚马逊应用商店计费兼容性SDK仅支持IAB-4.0规范中出现的字段,不包括上面列出的字段。

处理购买

此处可能需要对代码进行极少的更改。

用户完成购买后,您的应用需要处理该购买。应用通常会通过PurchasesUpdatedListener收到购买通知。但是,在某些情况下,应用会使用queryPurchasesAsync()来提取购买,如提取购买中所述。

完成购买后,应用应该向客户提供相应的内容。对于权利,请使用acknowledgePurchase()确认内容的交付。对于消费品,请调用consumeAsync()以确认交付并将相应商品标记为已消费。

查看亚马逊应用商店的Google Play Billing API接口和Google Play结算库之间的以下区别:

  • 对消费品调用acknowledgePurchase()不仅会确认该商品,还会消费该商品。对权利或订阅调用consumeAsync()只能确认该商品,而不会消费该商品。之所以发生这种情况,是因为和Google Play Billing不同,亚马逊应用商店计费兼容性SDK在内部将消费品和权利视为独立的实体。
  • 亚马逊应用商店计费兼容性SDK允许再次购买消费品,即使已经购买过该消费品但尚未消费(如果上次购买时未调用consumeAsync(),则可能发生这种情况)。
  • 如果未确认购买,则用户不会自动收到退款。这不同于Google Play Billing,后者会撤销未在三天内收到确认的购,如Android开发者文档所详述。

以下示例展示了如何使用关联的购买代币消费产品:

void handlePurchase(Purchase purchase) {
    // 从queryPurchasesAsync或PurchasesUpdatedListener检索的购买。
    if (purchase.getPurchaseState() != PurchaseState.PURCHASED) {
        return;
    }

    // 向用户交付商品。

    // 消费商品。
    ConsumeParams consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.getPurchaseToken())
            .build();

    ConsumeResponseListener listener = new ConsumeResponseListener() {
        @Override
        public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // 处理消费操作成功的情况。
            } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
                // 处理错误响应。
            } else {
                //也可使用其他错误代码,但亚马逊应用商店计费兼容性SDK
                //从不返回这些代码。
            }
        }
    };

    billingClient.consumeAsync(consumeParams, listener);
}

类似地,以下示例展示了如何使用关联的购买令牌确认购买:

void handlePurchase(Purchase purchase) {
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
        AcknowledgePurchaseParams acknowledgePurchaseParams =
            AcknowledgePurchaseParams.newBuilder()
                .setPurchaseToken(purchase.getPurchaseToken())
                .build();

        AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...

        billingClient.acknowledgePurchase(
            acknowledgePurchaseParams,
            acknowledgePurchaseResponseListener);
    }
}

亚马逊应用商店计费兼容性SDK在消费商品时返回的错误响应代码只有BillingResponseCode.ERROR。也可使用Google Play Billing支持的其他错误响应代码,但从不返回这些代码。

提取购买

此处可能需要对代码进行极少的更改。

尽管应用会在通过PurchasesUpdatedListener进行侦听时收到购买通知,但某些场景可能会导致应用不知道用户进行了购买。应用可能会不知道用户进行了购买的场景包括:

  • 网络问题: 用户成功购买,但在通过PurchasesUpdatedListener收到购买通知之前,他们的设备发生了网络连接故障。
  • 多台设备: 用户在一台设备上购买了一件商品,切换到另一台设备,希望看到购买的商品。
  • 订阅生命周期事件: 订阅生命周期事件(如续订)定期发生,无需来自计费客户端的API调用。

可以通过在onResume()方法中调用queryPurchasesAsync()来处理这些场景。这样可确保成功处理所有购买,如处理购买中所述。与Google Play Billing不同,queryPurchasesAsync()在本地缓存过期时进行网络调用,这会影响侦听器回调所用的时间。要减少亚马逊应用商店计费兼容性SDK中的调用时间,请将queryPurchasesAsync()调用中的SKU数量限制为100。

queryPurchasesAsync() 方法仅返回权利、未消费的消费品和有效订阅的未消费应用内购买。以下示例展示了如何提取用户的应用内购买:

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder()
      .setProductType(ProductType.INAPP)
      .build(),
    new PurchasesResponseListener() {
      public void onQueryPurchasesResponse(BillingResult billingResult, List purchases) {
        if (billingResult.getResponseCode() == BillingResponseCode.OK) {
            // 处理返回的购买列表(显示用户拥有的应用程序内商品)。
        } else if (billingResult.getResponseCode() == BillingResponseCode.ERROR) {
            // 处理错误响应。
        } else if (billingResult.getResponseCode() == BillingResponseCode.DEVELOPER_ERROR) {
            // 处理开发者错误响应。
        } else {
            //也可使用其他错误代码,但亚马逊应用商店计费兼容性SDK
            //从不返回这些代码。
        }
      }
    }
);

对于订阅,在创建QueryPurchasesParams时传递ProductType.SUBS,如下所示。

QueryPurchasesParams.newBuilder()
.setProductType(ProductType.SUBS)
.build()

或者,可以使用指定SkuType的字符串来调用queryPurchasesAsync(),而不是使用QueryPurchasesParams对象,如下所示。

billingClient.queryPurchasesAsync(
     SkuType.INAPP,
     purchasesResponseListener
 );

亚马逊应用商店计费兼容性SDK返回的错误响应代码只有BillingResponseCode.DEVELOPER_ERRORBillingResponseCode.ERROR。也可使用Google Play Billing支持的其他错误响应代码,但从不返回这些代码。

和Google Play Billing不同,只有在进行购买时使用的设备上才会返回未消费(如果未调用consumeAsync())的消费品,而在其他设备上不会返回。如果同一台设备上的应用版本有所变化(例如在应用升级后),则可能不会立即返回尚未消费的消费品,但最终会返回。

不支持的字段

亚马逊应用商店计费兼容性SDK在响应中不支持Google Play Billing提供的以下字段。请从代码中删除对这些字段的引用。

  • Account identifiers(Obfuscated Account ID和Obfuscated Profile ID)
  • Order ID
  • Signature
  • Package name
  • Acknowledged

注意:​ 亚马逊应用商店计费兼容性SDK仅支持IAB-4.0规范中出现的字段,不包括上面列出的字段。

不支持的功能

亚马逊应用商店计费兼容性SDK不支持以下特性和API:

测试您的应用

要测试您的应用并验证与亚马逊应用商店计费兼容性SDK的集成,请遵循以下指南。

  • 使用动态应用测试服务通过一组选定用户在实际生产环境中对应用进行测试。
  • 在开始动态应用测试之前,为集成了亚马逊应用商店计费兼容性SDK的应用创建并提交应用内购买商品。
  • 让应用在亚马逊开发者控制台中的应用程序内商品SKU与在Google Play控制台中的产品ID保持相同。否则,还必须更新应用中的产品ID。

Last updated: 2023年10月27日