本主题将介绍如何从 Google Play 结算库版本 4 或 5 迁移到 Google Play 结算库版本 6,以及如何使用新的订阅功能。
如需查看版本 6.0.0 的完整变更列表,请参阅版本说明。
概览
Google Play 结算库版本 6 以版本 5 为基础,引入了新订阅功能,并做出了多项改进。借助这些功能,您能以更多方式销售订阅内容,还能降低运营费用,因为无需创建和管理越来越多的 SKU。
如需详细了解 Play 结算库 5 中引入的新功能,请参阅 Play 管理中心内订阅方面的近期变更。
向后兼容的 Play 结算库升级
作为 2022 年 5 月发布的 Play 结算库版本 5 和新订阅平台的一部分,所有现有的订阅产品都会自动转换为这种新范例。这意味着,您无需更改订阅产品配置,即可获得与新版 Play 结算库兼容的目录。如需详细了解如何将订阅 SKU 转换为向后兼容的订阅,请参阅 Play 管理中心帮助文章中的“使用旧版订阅”部分。
旧版应用仍可正常运行
如果您有向后兼容的订阅目录,那么您所有现有版本的应用仍应按预期适用于这些产品。一次性商品购买交易应该仍然可以继续在旧版中正常进行。
使用已废弃方法(例如 querySkuDetailsAsync()
)的应用版本将无法销售任何不向后兼容的基础方案或优惠。如需了解向后兼容的优惠,请参阅相关的 Play 管理中心帮助中心文章。
升级到 Play 结算库 5 或 6
Play 结算库 5 和 6 包含已废弃的 querySkuDetailsAsync
和 BillingFlowParams.Builder.setSkuDetails
方法,其中这些方法的结算流程参数为 SkuDetails
。这意味着,您可以通过规划不同的迁移阶段,逐步迁移至 Play 结算库 6。
如要迁移,首先更新库版本,保持目录和后端不变,然后在其仍使用已废弃方法时测试应用。如果未使用 queryPurchases
、launchPriceChangeFlow
或 setVrPurchaseFlow
,则它应仍可按预期运行。之后,您可以通过迭代来全面采用 2022 年 5 月发布的新订阅功能。
如果您之前已通过 Google Play 结算库版本 5 迁移采用了这些功能,则可以直接跳至标记为更新 Google Play 结算库和更改用户的订阅购买交易的部分。如果您是从早期版本开始迁移,或尚未全面采用新功能,请参阅完整的迁移步骤,了解如何采用这些功能。
完整的迁移步骤
在后端商品清单中创建新订阅
现在,使用 Play 管理中心或 Play Developer API,您可以配置包含多个基础方案的单个订阅,每个基础方案可提供多项优惠。您可以为订阅优惠设置灵活的定价模式和资格条件。您可以使用各种各样的自动续订服务和预付费方案,在整个订阅生命周期中创建优惠。
我们建议在迁移应用之前,按照新订阅平台中的实体结构为 Play 结算库版本 6 集成创建新产品。您可以在单个订阅下合并旧清单中提供相同使用权福利的重复产品,并使用基础方案和优惠配置来表示您希望提供的所有选项。如需详细了解此建议,请参阅 Play 管理中心帮助文章的“使用旧版订阅”部分。
建议您不要修改在 2022 年 5 月版本之后转换的订阅产品,应该保持不变,即使用已废弃的方法(例如,querySkuDetailsAsync()
)随应用版本一起销售,避免引入可能影响这些旧 build 的变更。
转换流程会使 2022 年 5 月之前的清单中的订阅产品变为只读状态,以避免可能导致现有集成出现问题的意外更改。可以更改这些订阅,但可能对您的前端和后端集成产生影响:
在前端,使用
querySkuDetailsAsync()
获取订阅产品详情的应用版本只能销售向后兼容的基础方案和优惠,并且只能有一个向后兼容的基础方案和优惠组合,因此如果您向转换后的订阅添加新的方案或优惠,新的额外基础方案或优惠将无法在这些旧版应用中销售。在后端,如果您在 Play 管理中心界面中修改转换后的订阅,则无法使用
inappproducts
端点管理这些订阅(如果您为此目的调用了该端点)。您还应迁移到新的订阅购买状态端点 (purchases.subscriptionsv2.get
) 来管理这些订阅的购买交易,因为旧购买状态端点 (purchases.subscriptions.get
) 仅返回处理向后兼容的基础方案和优惠购买交易所需的数据。如需了解详情,请参阅管理订阅购买状态部分。
使用新 API 管理后端订阅清单
如果您使用 Google Play Developer API 自动管理订阅产品清单,则需要使用新的订阅产品定义端点来创建和管理订阅、基础方案和优惠。请参阅 2022 年 5 月的订阅功能指南,详细了解此版本的产品清单 API 变更。
如需迁移 Google Play 结算服务订阅的自动产品清单管理模块,请将 inappproducts
API 替换为新的 Subscription Publishing API 来管理和发布订阅清单。有三个新端点:
Monetization.subscriptions
,用于管理订阅产品。Monetization.basePlans
,用于管理订阅的基础方案。Monetization.offers
,用于管理基础方案的优惠。
这些新端点具有利用清单中的所有新功能所需的所有功能:基础方案和优惠标签、区域定位、预付费方案等。
您应该依然使用 inappproducts
API 来管理一次性购买产品的应用内产品清单。
使用已废弃方法(例如 querySkuDetailsAsync()
)的应用版本将无法销售任何不向后兼容的基础方案或优惠。您可以在此处了解向后兼容的优惠。
更新 Google Play 结算库
创建新的订阅产品清单后,您可以将应用迁移到 Google Play 结算库版本 5。使用应用 build.gradle
文件更新后的版本替换现有的 Play 结算库依赖项。
dependencies {
def billingVersion = "6.0.0"
implementation "com.android.billingclient:billing:$billingVersion"
}
即使您没有修改任何方法调用,您的项目应该也会立即构建,因为我们已在 Play 结算库版本 6 中实现了向后兼容性。SKU 的概念被视为已废弃,但仍会存在,目的是使应用移植流程更简单且更循序渐进。
初始化结算客户端并与 Google Play 建立连接
从 Android 应用启动购买交易的前几步保持不变:
展示可供购买的商品
为了获取用户符合购买条件的所有优惠,请按以下步骤操作:
- 将
SkuDetailsParams
替换为QueryProductDetailsParams
- 将
BillingClient.querySkuDetailsAsync()
调用改为BillingClient.queryProductDetailsAsync()
请注意,查询结果现在是 ProductDetails
,而不是 SkuDetails
。每个 ProductDetails
项目都包含商品的相关信息(ID、商品名、类型等)。对于订阅商品,ProductDetails
包含一个 List<ProductDetails.SubscriptionOfferDetails>
,即订阅优惠详情列表。对于一次性购买商品,ProductDetails
包含一个 ProductDetails.OneTimePurchaseOfferDetails
。它们可用于确定要向用户显示哪些优惠。
以下示例是应用在进行这些更改前后的比较:
之前
Kotlin
val skuList = ArrayList<String>() skuList.add("up_basic_sub") val params = SkuDetailsParams.newBuilder() params.setSkusList(skuList).setType(BillingClient.SkuType.SUBS).build() billingClient.querySkuDetailsAsync(params) { billingResult, skuDetailsList -> // Process the result }
Java
List<String> skuList = new ArrayList<>(); skuList.add("up_basic_sub"); SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); params.setSkusList(skuList).setType(SkuType.SUBS).build(); billingClient.querySkuDetailsAsync(params, new SkuDetailsResponseListener() { @Override public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) { // Process the result. } } );
之后
Kotlin
val productList = listOf( QueryProductDetailsParams.Product.newBuilder() .setProductId("up_basic_sub") .setProductType(BillingClient.ProductType.SUBS) .build() ) val params = QueryProductDetailsParams.newBuilder().setProductList(productList).build() billingClient.queryProductDetailsAsync(params) { billingResult, productDetailsList -> // Process the result }
Java
ImmutableList<Product> productList = ImmutableList.of(Product.newBuilder() .setProductId("up_basic_sub") .setProductType(ProductType.SUBS) .build()); QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder() .setProductList(productList) .build(); billingClient.queryProductDetailsAsync( params, new ProductDetailsResponseListener() { public void onProductDetailsResponse(BillingResult billingResult, List<ProductDetails> productDetailsList) { // Process the result } } );
queryProductDetailsAsync
的回调会返回一个 List<ProductDetails>
。每个 ProductDetails
项目都包含商品的相关信息(ID、商品名、类型等)。主要区别在于,订阅商品现在还包含一个 List<ProductDetails.SubscriptionOfferDetails>
,其中包含用户可以享受的所有优惠。
由于以前的 Play 结算库版本不支持新对象(订阅、基础方案、优惠等),因此新系统将每个订阅 SKU 转换为单个向后兼容的基础方案和优惠。可用的一次性购买商品也改为使用 ProductDetails
对象。您可以使用 getOneTimePurchaseOfferDetails()
方法访问一次性购买商品的优惠详情。
在极少数情况下,某些设备无法支持 ProductDetails
和 queryProductDetailsAsync()
,这通常是因为 Google Play 服务版本已过时。为了确保对此场景提供适当的支持,请先针对 PRODUCT_DETAILS
功能调用 isFeatureSupported()
,然后再调用 queryProductDetailsAsync
。如果响应为 OK
,表示设备支持该功能,您可以继续调用 queryProductDetailsAsync()
。如果响应为 FEATURE_NOT_SUPPORTED
,您可以改用 querySkuDetailsAsync()
请求可用的向后兼容产品列表。如需详细了解如何使用向后兼容功能,请参阅 2022 年 5 月的订阅功能指南。
启动优惠购买流程
启动优惠的购买流程与启动 SKU 的流程非常相似。如需使用版本 6 发起购买请求,请执行以下操作:
- 不要将
SkuDetails
用于BillingFlowParams
,请改为使用ProductDetailsParams
。 - 可以使用
SubscriptionOfferDetails
对象获取优惠详情,例如优惠 ID、基础方案 ID 等。
为了销售提供用户所选优惠的商品,请获取所选优惠的 offerToken
,并将其传入 ProductDetailsParams
对象。
创建 BillingFlowParams
对象后,使用 BillingClient
启动结算流程的操作保持不变。
以下示例是应用在进行这些更改前后的比较:
之前
Kotlin
// An activity reference from which the billing flow will be launched. val activity : Activity = ... // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync(). val billingFlowParams = BillingFlowParams.newBuilder() .setSkuDetails(skuDetails) .build() val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Java
// An activity reference from which the billing flow will be launched. Activity activity = ...; // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync(). BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setSkuDetails(skuDetails) .build(); BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
之后
Kotlin
// An activity reference from which the billing flow will be launched. val activity : Activity = ...; val productDetailsParamsList = listOf( BillingFlowParams.ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For One-time product, "setOfferToken" method shouldn't be called. // For subscriptions, to get the offer token corresponding to the selected // offer call productDetails.subscriptionOfferDetails?.get(selectedOfferIndex)?.offerToken .setOfferToken(selectedOfferToken) .build() ) val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build() // Launch the billing flow val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)
Java
// An activity reference from which the billing flow will be launched. Activity activity = ...; ImmutableList<ProductDetailsParams> productDetailsParamsList = ImmutableList.of( ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // For one-time products, "setOfferToken" method shouldn't be called. // For subscriptions, to get the offer token corresponding to the selected // offer call productDetails.getSubscriptionOfferDetails().get(selectedOfferIndex).getOfferToken() .setOfferToken(selectedOfferToken) .build() ); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); // Launch the billing flow BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
处理购买交易
使用 Google Play 结算库版本 6 处理购买交易的操作与以前的版本类似。
如需拉取用户拥有的所有有效购买交易并查询新购买交易,请执行以下操作:
- 请传递一个包含
BillingClient.ProductType
值的QueryPurchasesParams
对象,而不要向queryPurchasesAsync()
传递BillingClient.SkuType
值。
以下示例是应用在进行这些更改前后的比较:
之前
Kotlin
billingClient.queryPurchasesAsync(BillingClient.SkuType.SUBS) { billingResult, purchaseList -> { // Process the result } }
Java
billingClient.queryPurchasesAsync( BillingClient.SkuType.SUBS, new PurchasesResponseListener() { public void onQueryPurchasesResponse( BillingResult billingResult, ListP<urchase >purchases) { // process the result } } );
之后
Kotlin
billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder() .setProductType(BillingClient.ProductType.SUBS) .build() ) { billingResult, purchaseList -> // Process the result }
Java
billingClient.queryPurchasesAsync( QueryPurchasesParams.newBuilder().setProductType(ProductType.SUBS).build(), new PurchasesResponseListener() { public void onQueryPurchasesResponse( BillingResult billingResult, List<Purchase> purchases) { // Process the result } } );
在后端使用新 API 管理订阅购买状态
您应该迁移后端中的订阅购买状态管理组件,以便处理在前面步骤中创建的新产品的购买交易。对于您在 2022 年 5 月发布之前定义的转换后订阅产品,您当前的订阅购买状态管理组件应该可以正常工作,它应该足以管理向后兼容优惠的购买交易,但不支持任何新功能。
您需要为订阅购买状态管理模块实现新的 Subscription Purchases API,该模块会在后端检查购买状态并管理 Play 结算服务订阅使用权。该 API 的旧版本不会返回在新平台中管理购买交易所需的所有详细信息。如需详细了解与先前版本相比的变化,请参阅 2022 年 5 月新订阅功能指南。
通常在每次收到 SubscriptionNotification
实时开发者通知时调用 Subscription Purchases API,即可拉取有关订阅状态的最新信息。您需要将对 purchases.subscriptions.get
的调用替换为新版本的 Subscription Purchases API purchases.subscriptionsv2.get
。在新模型中,有一个名为 SubscriptionPurchaseV2
的新资源,可提供足够的信息来管理订阅的购买使用权。
此新端点会返回所有订阅产品和所有购买交易的状态,无论销售该产品的应用版本是什么,也不管该产品是何时定义的(2022 年 5 月版本之前或之后),因此在迁移后,您只需使用此版本的订阅购买状态管理模块。
更改用户的订阅购买交易
在 Play 结算库 5 及更低版本中,ProrationMode
用于将更改应用于用户的订阅购买交易,例如升级或降级。在版本 6 中,它已被废弃,取而代之的是 ReplacementMode
。
处理订阅价格变动
先前已废弃的 launchPriceConfirmationFlow
API 已从 Play 结算库 6 中移除。如需了解替代方案,请参阅价格变动指南。
处理 Play 结算库错误
Play 结算库 6 中新增了 NETWORK_ERROR
代码,用于指明用户设备和 Google Play 系统之间的网络连接问题。代码 SERVICE_TIMEOUT
和 SERVICE_UNAVAILABLE
也发生了变化。如需了解详情,请参阅处理 BillingResult 响应代码。
处理待处理的交易
从 6.0.0 版开始,Play 结算库不再为待处理的购买交易创建订单 ID。只有在购买交易变为 PURCHASED
状态后,系统才会为这类购买交易填充订单 ID。确保您的集成仅预期在交易全部完成后获得订单 ID。您仍可将购买令牌用作记录。如需详细了解如何处理待处理的购买交易,请参阅 Play 结算库集成指南和购买生命周期管理指南。