Register now for Android Dev Summit 2019!

Google Play 结算库版本说明

本主题包含 Google Play 结算库的版本说明。

Google Play 结算库 2.0.1 版 (2019-06-06)

Google Play 结算库 2.0.1 版现已推出。此版本包含以下变更。

错误修复

  • 修复了在某些情况下系统将调试消息作为 null 返回的错误。
  • 修复了潜在的内存泄漏问题。

Google Play 结算库 2.0 版 (2019-05-07)

Google Play 结算库 2.0 版现已推出。此版本包含以下变更。

必须在三天内确认购买交易

Google Play 支持从您的应用内部(应用内)或您的应用外部(应用外)购买商品。为了确保无论用户在哪里购买您的商品,Google Play 都能提供一致的购买体验,您必须在授予用户权利后尽快确认通过 Google Play 结算库收到的所有购买交易。如果您在三天内未确认购买交易,则用户会自动收到退款,并且 Google Play 会撤消该购买交易。对于待处理的交易(2.0 版中的新功能),三天的期限从购买交易改为 SUCCESS 状态时起算,而在购买交易处于 PENDING 状态时不适用。

对于订阅,您必须确认包含新购买令牌的任何购买交易。这意味着,需要确认所有初始购买、计划变更和重新注册,但无需确认后续续订。要确定购买交易是否需要确认,您可以检查购买交易中的确认字段。

Purchase 对象现在包含 isAcknowledged() 方法,该方法可指示购买交易是否已得到确认。此外,服务器端 API 现在包含 Product.purchases.get()Product.subscriptions.get() 的确认布尔值。在确认购买交易之前,请使用这些方法来确定购买交易是否已得到确认。

您可以使用以下某种方法来确认购买交易:

  • 对于消耗型商品,请使用客户端 API 中的 consumeAsync()
  • 对于非消耗型商品,请使用客户端 API 中的 acknowledgePurchase()
  • 还可以使用服务器 API 中新增的 acknowledge() 方法。

已移除 BillingFlowParams.setSku()

在此版本中已移除先前弃用的 BillingFlowParams#setSku() 方法。在购买流程中呈现商品之前,您现在必须调用 BillingClient.querySkuDetailsAsync(),将生成的 SkuDetails 对象传递给 BillingFlowParams.Builder.setSkuDetails()

如需查看代码示例,请参阅使用 Google Play 结算库

支持开发者有效负载

Google Play 结算库 2.0 版添加了对开发者有效负载(即,可附加到购买交易的任意字符串)的支持。您可以将开发者有效负载参数附加到购买交易,但只有在已确认购买交易或已消耗所购商品时才能附加。这与 AIDL 中的开发者有效负载不同,在 AIDL 中,可以在启动购买流程时指定有效负载。因为现在可以从您的应用外部发起购买交易,所以此变更可确保您始终有机会将有效负载添加到购买交易。

Purchase 对象现在包含 getDeveloperPayload() 方法,用于访问新库中的有效负载。

一致的报价

当您提供折扣 SKU 时,Google Play 现在会返回 SKU 的原价,以便您向用户显示他们正在享受折扣。

SkuDetails 包含两种用来检索 SKU 原价的新方法:

待处理的交易

在 Google Play 结算库 2.0 版中,您必须支持在授予权利之前需要执行其他操作的购买交易。例如,用户可能会选择使用现金在实体店购买您的应用内商品。这意味着,交易在您的应用外部完成。在这种情况下,只有在用户完成交易后,您才能授予权利。

要启用待处理的购买交易,请在初始化您的应用期间调用 enablePendingPurchases()

使用 Purchase.getState() 确定购买状态是 PURCHASED 还是 PENDING。请注意,只有在状态为 PURCHASED 时,您才能授予权利。您应执行以下操作来检查 Purchase 状态更新:

  1. 在启动您的应用时,调用 BillingClient.queryPurchases() 以检索与用户关联的非消耗型商品的列表。
  2. 在返回的每个 Purchase 对象上调用 Purchase.getState()
  3. 实现 onPurchasesUpdated() 方法以响应对 Purchase 对象的更改。

除了这些变更之外,服务器端 API 现在还包含 Product.purchases.get()Product.subscriptions.get()PENDING 状态。

此版本还引入了一个新的实时开发者通知类型,即 OneTimeProductNotification。此通知类型包含一条消息,其值为 INAPP_PURCHASEDINAPP_CANCELED。系统仅针对与延迟付款方式(如现金)关联的购买交易发送此类型的通知。

在确认待处理的购买交易时,请确保只有在购买状态是 SUCCESS(而不是 PENDING)时才确认。

API 变更

Google Play 结算库 2.0 版包含多项 API 变更,以支持新特性并澄清现有功能。

consumeAsync

consumeAsync() 现在接受 ConsumeParams 对象而不是 purchaseTokenConsumeParams 包含 purchaseToken 以及可选的开发者有效负载。

在此版本中已移除之前版本的 consumeAsync()

queryPurchaseHistoryAsync

为了最大限度地减少混淆,queryPurchaseHistoryAsync() 现在返回 PurchaseHistory 对象而不是 Purchase 对象。PurchaseHistory 对象与 Purchase 对象相同,只不过它仅反映由 queryPurchaseHistoryAsync() 返回的值,并且不包含 autoRenewingorderIdpackageName 字段。请注意,返回的数据没有任何变化 - queryPurchaseHistoryAsync() 返回的数据与以前相同。

BillingResult 返回值

先前返回 BillingResponse 整数值的 API 现在返回 BillingResult 对象。BillingResult 包含 BillingResponse 整数以及可用于诊断错误的调试字符串。该调试字符串使用 en-US 语言环境,不会向最终用户显示。

错误修复

Google Play 结算库 1.2.2 版 (2019-03-07)

Google Play 结算库 1.2.2 版现已推出。此版本包含以下变更。

问题修复

  • 修复了 v1.2.1 中引入的线程问题。后台调用不再阻止主线程。

其他变更

  • 虽然仍建议使用主线程,但您现在可以从后台线程实例化 Google Play 结算库。
  • 实例化已完全迁移到后台线程,以降低导致 ANR 的几率。

Play 结算库 1.2.1 版 (2019-03-04)

Google Play 结算库 1.2.1 版现已推出。此版本包含以下变更。

主要变更

其他变更

  • PurchasesResultSkuDetailsResult 添加了公共构造函数,以使测试变得更容易。
  • SkuDetails 对象可以使用新方法 getOriginalJson()
  • 所有 AIDL 服务调用现在都由后台线程处理。

问题修复

  • 空回调监听器不再传递到公共 API 中。

Google Play 结算库 1.2 版 (2018-10-18)

Google Play 结算库 1.2 版现已推出。此版本包含以下变更。

变更摘要

  • Google Play 结算库现在依据 Android 软件开发工具包许可协议授权。
  • 添加了 launchPriceChangeConfirmationFlow API,用于提示用户检查对订阅价格的待定更改。
  • 在升级或降级用户的订阅时,添加了对新的按比例计费模式 DEFERRED 的支持。
  • BillingFlowParams 类中,将 setSku() 替换成了 setSkuDetails()
  • 修复了一些小问题并优化了代码。

价格变动确认

您现在可以在 Google Play 管理中心内更改订阅的价格,并在用户进入您的应用时提示他们查看并接受新价格。

要使用此 API,请使用订阅产品的 skuDetails 创建 PriceChangeFlowParams 对象,然后调用 launchPriceChangeConfirmationFlow()。当价格变动确认流程完成时,实现 PriceChangeConfirmationListener 来处理结果,如以下代码段所示:

Kotlin

val priceChangeFlowParams = PriceChangeFlowParams.newBuilder()
    .setSkuDetails(skuDetailsOfThePriceChangedSubscription)
    .build()

billingClient.launchPriceChangeConfirmationFlow(activity,
        priceChangeFlowParams,
        object : PriceChangeConfirmationListener() {
            override fun onPriceChangeConfirmationResult(responseCode: Int) {
                // Handle the result.
            }
        })

Java

PriceChangeFlowParams priceChangeFlowParams =
        PriceChangeFlowParams.newBuilder()
    .setSkuDetails(skuDetailsOfThePriceChangedSubscription)
    .build();

billingClient.launchPriceChangeConfirmationFlow(activity,
        priceChangeFlowParams,
        new PriceChangeConfirmationListener() {
            @Override
            public void onPriceChangeConfirmationResult(int responseCode) {
                // Handle the result.
            }
        });

价格变动确认流程会显示一个包含新定价信息的对话框,要求用户接受新价格。此流程会返回 BillingClient.BillingResponse 类型的响应代码。

新的按比例计费模式

当升级或降级用户的订阅时,您可以使用新的按比例计费模式 DEFERRED。此模式会在下次续订时更新用户的订阅。要详细了解如何设置此按比例计费模式,请参阅设置按比例计费模式

用于设置 SKU 详情的新方法

BillingFlowParams 类中,已弃用 setSku() 方法。此变更有助于优化 Google Play 结算服务流程。

在您的应用内购买结算客户端中构造新的 BillingFlowParams 实例时,我们建议您直接使用 setSkuDetails() 来处理 JSON 对象,如以下代码段所示。

BillingFlowParams Builder 类中,已弃用 setSku() 方法。请改用 setSkuDetails() 方法,如以下代码段所示。传递到 setSkuDetails() 对象中的对象来自 querySkuDetailsAsync() 方法。

Kotlin

private lateinit var mBillingClient: BillingClient
private val mSkuDetailsMap = HashMap<String, SkuDetails>()

private fun querySkuDetails() {
    val skuDetailsParamsBuilder = SkuDetailsParams.newBuilder()
    mBillingClient.querySkuDetailsAsync(skuDetailsParamsBuilder.build()
    ) { responseCode, skuDetailsList ->
        if (responseCode == 0) {
            for (skuDetails in skuDetailsList) {
                mSkuDetailsMap[skuDetails.sku] = skuDetails
            }
        }
    }
}

private fun startPurchase(skuId: String) {
    val billingFlowParams = BillingFlowParams.newBuilder()
    .setSkuDetails(mSkuDetailsMap[skuId])
    .build()
}

Java

private BillingClient mBillingClient;
private Map<String, SkuDetails> mSkuDetailsMap = new HashMap<>();

private void querySkuDetails() {
    SkuDetailsParams.Builder skuDetailsParamsBuilder
            = SkuDetailsParams.newBuilder();
    mBillingClient.querySkuDetailsAsync(skuDetailsParamsBuilder.build(),
            new SkuDetailsResponseListener() {
                @Override
                public void onSkuDetailsResponse(int responseCode,
                        List<SkuDetails> skuDetailsList) {
                    if (responseCode == 0) {
                        for (SkuDetails skuDetails : skuDetailsList) {
                            mSkuDetailsMap.put(skuDetails.getSku(), skuDetails);
                        }
                    }
                }
            });
}

private void startPurchase(String skuId) {
    BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
            .setSkuDetails(mSkuDetailsMap.get(skuId))
            .build();
}

Play 结算库 1.1 版 (2018-05-07)

Google Play 结算库 1.1 版现已推出。此版本包含以下变更。

变更摘要

  • 扩大了支持范围,现在可以在升级或降级现有订阅时在 BillingFlowParams 中指定按比例计费模式。
  • 不再支持 BillingFlowParams 中的 replaceSkusProration 布尔标记。请改用 replaceSkusProrationMode
  • launchBillingFlow() 现在触发失败响应的回调。

行为变更

Google Play 结算库 1.1 版包含以下行为变更。

开发者可以在 BillingFlowParams 类中设置 replaceSkusProrationMode

在升级或降级用户的订阅时,ProrationMode 会提供有关按比例计费类型的更多详情。

Kotlin

BillingFlowParams.newBuilder()
    .setSku(skuId)
    .setType(billingType)
    .setOldSku(oldSku)
    .setReplaceSkusProrationMode(replaceSkusProrationMode)
    .build()

Java

BillingFlowParams.newBuilder()
    .setSku(skuId)
    .setType(billingType)
    .setOldSku(oldSku)
    .setReplaceSkusProrationMode(replaceSkusProrationMode)
    .build();

目前,Google Play 支持以下按比例计费模式:

IMMEDIATE_WITH_TIME_PRORATION 替换会立即生效,并且系统会按比例计算新的有效期,同时向用户返还余额或收取相关费用。这是当前的默认行为。
IMMEDIATE_AND_CHARGE_PRORATED_PRICE 替换会立即生效,结算周期保持不变。用户需要补足剩余订阅期的差价。

注意:此选项仅适用于订阅升级。

IMMEDIATE_WITHOUT_PRORATION 替换会立即生效,并且会在下个续订时间点按新价格收费。结算周期保持不变。

BillingFlowParams 类不再支持 replaceSkusProration

开发者过去可以设置一个布尔标志来针对订阅升级请求收取按比例计算的金额。鉴于我们现已支持 ProrationMode,它包含更详细的按比例计费说明,因此不再支持此布尔标志。

launchBillingFlow() 现在触发对失败响应的回调

结算库将始终触发 PurhcasesUpdatedListener 回调并异步返回 BillingResponse,也会保留 BillingResponse 的同步返回值。

错误修复

  • 当服务断开时,采用异步方法尽早正确退出。
  • Builder 参数对象不再使编译的对象突变。
  • 问题 68087141launchBillingFlow() 现在触发对失败响应的回调。

Google Play 结算库 1.0 版(2017-09-19,公告

Google Play 结算库 1.0 版现已推出。此版本包含以下变更。

重要变更

  • 在库的清单内嵌入了结算权限,因此不再需要在 Android 清单内添加 com.android.vending.BILLING 权限。
  • BillingClient.Builder 类中添加了新的编译程序。
  • SkuDetailsParams 类中引入了在查询 SKU 的方法中使用的编译程序模式。
  • 为了保持一致(相同的返回参数名称和顺序),更新了几个 API 方法。

行为变更

Google Play 结算库 1.0 版包含以下行为变更。

BillingClient.Builder 类

BillingClient.Builder 现在通过 newBuilder 模式初始化:

Kotlin

billingClient = BillingClient.newBuilder(context).setListener(this).build()

Java

billingClient = BillingClient.newBuilder(context).setListener(this).build();

现在使用 BillingFlowParams 类调用 launchBillingFlow 方法

为了启动购买交易或订阅的结算流程,launchBillingFlow() 方法会接收一个使用请求专用参数初始化的 BillingFlowParams 实例:

Kotlin

BillingFlowParams.newBuilder().setSku(skuId)
        .setType(billingType)
        .setOldSku(oldSku)
        .build()

// Then, use the BillingFlowParams to start the purchase flow
val responseCode = billingClient.launchBillingFlow(builder.build())

Java

BillingFlowParams.newBuilder().setSku(skuId)
                              .setType(billingType)
                              .setOldSku(oldSku)
                              .build();

// Then, use the BillingFlowParams to start the purchase flow
int responseCode = billingClient.launchBillingFlow(builder.build());

查询上架商品的新方式

过去将 queryPurchaseHistoryAsync()querySkuDetailsAsync() 方法的参数封装到了 Builder 模式中:

Kotlin

val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList)
        .setType(itemType)
billingClient.querySkuDetailsAsync(params.build(), object : SkuDetailsResponseListener() {
    ...
})

Java

SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList)
        .setType(itemType);
billingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {...})

为了方便您使用并在我们的 API 之间保持一致,现在通过结果代码和 SkuDetails 对象列表(而不是先前的封装容器类)返回结果:

Kotlin

fun onSkuDetailsResponse(@BillingResponse responseCode: Int, skuDetailsList: List<SkuDetails>)

Java

public void onSkuDetailsResponse(@BillingResponse int responseCode, List<SkuDetails> skuDetailsList)

已更改 onConsumeResponse() 方法的参数顺序

为了在我们的 API 之间保持一致,已更改 ConsumeResponseListener 接口中的 onConsumeResponse 的参数顺序:

Kotlin

fun onConsumeResponse(@BillingResponse responseCode: Int, outToken: String)

Java

public void onConsumeResponse(@BillingResponse int responseCode, String outToken)

PurchaseResult 对象已解除封装

为了在我们的 API 之间保持一致,PurchaseResult 已解除封装:

Kotlin

fun onPurchaseHistoryResponse(@BillingResponse responseCode: Int, purchasesList: List<Purchase>)

Java

void onPurchaseHistoryResponse(@BillingResponse int responseCode, List<Purchase> purchasesList)

问题修复

开发者预览版 1(2017-06-12,公告

发布了开发者预览版,旨在简化结算方面的开发过程,让开发者能够集中精力实现 Android 应用专用逻辑,如应用架构和导航结构。

该库包含一些方便使用的类和功能,供您在将 Android 应用与 Google Play Billing API 集成时使用。此外,该库还在 Android 接口定义语言 (AIDL) 服务之上提供了一个抽象层,让开发者可以更轻松地定义应用与 Google Play Billing API 之间的接口。