订阅简介

本主题介绍了如何处理订阅生命周期事件,如续订和到期。此外,还介绍了其他订阅功能,如提供促销活动以及允许用户管理他们自己的订阅。

如果您还没有为您的应用配置订阅商品,请参阅创建和配置您的商品

订阅概览

订阅代表用户在指定时间段内可以享受的一系列权益。例如,订阅可授予用户使用某项音乐在线播放服务的权利。

您可以在同一个应用中提供多项订阅;这些订阅可以分别代表一组不同的权益,也可以代表同一组权益的不同层级(例如,“白银”层级和“黄金”层级)。

您可以通过基础方案和优惠,为同一订阅商品创建多个配置。例如,您可以针对从未订阅过您的应用的用户创建初次体验优惠。同样,您也可以针对已经订阅的用户创建升级优惠。

如需详细了解订阅商品、基础方案和优惠,请参阅 Play 管理中心帮助中心内的相关文档。

预付费方案集成

预付费方案到期后不会自动续订。如需延长订阅内容使用权而不出现中断,用户必须给同一项订阅内容的预付费方案充值。

对于充值,请按照与原始购买交易相同的方式启动结算流程。您无需指明购买交易是充值。

预付费方案充值始终使用 CHARGE_FULL_PRICE 替换模式,您无需明确设置此模式。系统会立即向用户收取整个结算周期的费用,并按充值时指定的时长延长其使用权。

充值后,Purchase 结果对象中的以下字段会更新,以反映最新的充值交易:

  • 订单 ID
  • 购买时间
  • 签名
  • 购买令牌
  • 已确认

以下 Purchase 字段中包含的数据始终与原始购买交易中的数据相同:

  • 软件包名称
  • 购买状态
  • 商品
  • 自动续订

预付费购买交易确认

与自动续订订阅内容类似,您必须在购买交易完成后确认预付费方案。初始购买交易和所有充值都需要进行确认。如需了解详情,请参阅处理购买交易

由于预付费方案的时长有可能比较短,因此请务必尽快确认购买交易。

时长为一周或更长时间的预付费方案必须在三天内确认。

对于时长不到一周的预付费方案,其确认时间不得晚于方案时长过半之时。例如,开发者必须在 1.5 天内确认时长为三天的预付费方案。

使用深层链接让用户能够管理订阅

您的应用应在设置或偏好设置界面上添加一个链接,让用户能够管理订阅,您可将链接与应用的自然外观和风格融为一体。

对于未过期的订阅,您可以添加从您的应用到 Google Play 订阅中心的深层链接,您可以使用订阅资源subscriptionState 字段来确定订阅是否未过期。基于此,您可以通过多种方式深层链接到 Play 商店订阅中心。

使用以下网址将用户定向到显示其所有订阅的页面,如图 1 和图 2 所示:

https://play.google.com/store/account/subscriptions
Play 商店“订阅”界面显示了用户通过 Google Play 结算的所有订阅的状态。
图 1.Play 商店“订阅”界面显示了用户通过 Google Play 结算的所有订阅的状态。


点按某个订阅可查看更多详情。
图 2. 点按某个订阅可查看更多详情。

此深层链接可能有助于用户从 Play 商店订阅中心恢复已取消的订阅。

若要直接链接到一项未过期订阅的管理页面,请指明与购买的订阅关联的软件包名称和 productId。若要以程序化方式确定一项现有订阅的 productId,请在应用的后端查询,或针对与特定用户关联的订阅列表调用 BillingClient.queryPurchasesAsync()。每项订阅都包含相应的 productId,作为订阅状态信息的一部分。与订阅购买交易关联的每个 SubscriptionPurchaseLineItem 对象都包含与用户在该订单项中购买的订阅关联的 productId 值。

使用以下网址将用户定向到特定订阅的管理界面,并将“your-sub-product-id”和“your-app-package”分别替换为 productId 和应用软件包名称:

https://play.google.com/store/account/subscriptions?sku=your-sub-product-id&package=your-app-package

然后,用户就能管理其付款方式并使用取消、重新订阅和暂停等功能。

允许用户升级、降级或更改订阅

您可以为现有订阅者提供各种选项,方便他们更改订阅方案以更好地满足个人需求:

  • 如果您销售多个订阅层级(例如“基础”和“付费”订阅),可以允许用户通过购买不同订阅的基础方案或优惠来切换层级。
  • 您可以允许用户更改其当前结算周期,例如从包月方案改为包年方案。
  • 您还可以允许用户在自动续订和预付费方案之间切换。

您可以通过订阅优惠向符合条件的用户提供折扣,鼓励用户进行上述任何更改。例如,您可以创建一个从包月方案改为包年方案第一年可享 5 折价格的优惠,并将此优惠限制为仅面向订阅了包月方案但尚未购买此优惠的用户。如需详细了解优惠资格条件,请访问帮助中心

图 3 显示了一款提供 3 种不同方案的示例应用:

此应用有 3 个订阅层级。
图 3. 此应用有 3 个订阅层级。

应用可以显示类似于图 3 的界面,为用户提供更改其订阅的选项。在任何情况下,应用都必须向用户清楚展示当前采用的订阅方案是什么,以及可采用的方案更改选项。

当用户决定升级、降级或更改其订阅时,您可以指定替换模式,确定如何采用目前付费结算周期的按比例计费值,以及任何使用权变更的生效时间。

替换模式

下表列出了可用的替换模式和用法示例。

替换模式

说明

用法示例

WITH_TIME_PRORATION

订阅会立即升级或降级。系统会根据差价调整任何剩余时长,并将下一个结算日期往后推延,将剩余时长计入新的订阅。这是默认行为。

升级到费用更高的层级,无需立即支付额外费用。

CHARGE_PRORATED_PRICE

订阅会立即升级,结算周期保持不变。用户随后需要补足剩余订阅期的差价。

注意:此选项仅适用于每时间单位的价格会提高的订阅升级。

升级到费用更高的层级,无需更改结算日期。

CHARGE_FULL_PRICE

订阅会立即升级或降级,并且系统会即刻按全价向用户收取新使用权的费用。如果使用权不变,系统会将之前订阅的剩余价值结转;如果使用权有变化,系统会将剩余价值按比例折算成时间。

注意:如果新订阅提供免费试订或初次体验优惠,则在升级或降级时,用户需支付 0 美元或初次体验价费用(以适用者为准)。

从更短的结算周期升级到更长的结算周期。

WITHOUT_PRORATION

订阅会立即升级或降级,在订阅续订时将按新价格收取费用。结算周期保持不变。

升级到更高的订阅层级,同时保留所有剩余的免费试用期。

DEFERRED

只有在续订时,订阅才会升级或降级,但新购买的内容会立即发放,新订阅的开始日期在未来某个日期,因此开发者可允许用户按需要进行其他更改。例如,用户可以还原到原始方案,或发起新的延迟方案更改。

降级到费用更低的层级。

如需详细了解如何将升级或降级优惠应用在各种追加销售和客户赢回活动中,请参阅优惠与促销活动指南。

为购买交易设置替换模式

您可以根据自己的偏好设置和业务逻辑,为不同类型的订阅转换采用不同的替换模式。本部分介绍如何针对订阅更改设置替换模式以及适用的限制。

重新订阅或在同一订阅中切换方案

您可以在 Google Play 管理中心内指定默认替换模式。如果当前订阅者购买同一订阅的不同基础方案或优惠,或者在取消订阅后重新订阅,您可以通过此设置选择何时向其收费。可用选项包括“立即收费”(等同于 CHARGE_FULL_PRICE)和“在下一个结算日收费”(等同于 WITHOUT_PRORATION)。在同一订阅中切换基础方案时,这些是仅有的相关替换模式。

例如,如果您要在用户取消订阅后、订阅结束前针对同一方案实现赢回优惠,则可以将新购买交易作为常规购买交易处理,无需在 SubscriptionUpdateParams 中指定任何值。系统会使用您在订阅中配置的默认替换模式,并自动处理从旧购买交易到新购买交易的方案转换。

跨订阅切换方案,或替换默认替换模式

如果用户更改订阅产品(即购买其他订阅),或者如果您出于任何原因想要替换默认替换模式,您可在购买流程参数中指定运行时按比例计费费率。

若要在运行时购买流程配置中正确提供 SubscriptionUpdateParams,请注意以下限制:

  • 预付费方案或自动续订型方案升级、降级或在同一订阅中切换预付费方案时,唯一允许使用的按比例计费模式为 CHARGE_FULL_PRICE。如果您指定任何其他按比例计费模式,将导致购买失败,并向用户显示错误消息。
  • 在同一订阅中将方案预付费方案或自动续订型方案切换自动续订型方案时,有效的按比例计费模式为 CHARGE_FULL_PRICEWITHOUT_PRORATION。如果您指定任何其他按比例计费模式,将导致购买失败,并向用户显示错误消息。

替换示例和行为

为了理解各种按比例计费模式的运作原理,我们来考虑下面的场景:

李明订阅了 Country Gardener 应用的在线内容。他按月订阅第 1 层级版的内容,该内容只包含文字。此订阅的费用为每月 2 美元,并且在每月的第一天续订。

在 4 月 15 日,李明选择升级到第 2 层级按年订阅,该内容包含视频更新,费用为每年 36 美元

升级订阅时,开发者会选择一种按比例计费模式。以下列表说明了各种按比例计费模式对李明的订阅有何影响:

WITH_TIME_PRORATION

李明的第 1 层级订阅会立即终止。由于他支付了一整个月(4 月 1 日至 30 日)的费用,但在订阅期刚过一半时升级了订阅,因此剩余半个月的订阅费用(1 美元)会应用到新订阅。不过,由于新订阅的费用为每年 36 美元,1 美元的余额只够 10 天(4 月 16 日至 25 日)的费用,因此在 4 月 26 日,他需要为新订阅支付 36 美元的费用,并且此后每年的 4 月 26 日需要再支付 36 美元。

您应在购买交易成功时调用应用的 PurchasesUpdatedListener,并且您能通过 queryPurchasesAsync() 调用检索新购买交易。您的后端会立即收到 SUBSCRIPTION_PURCHASED 实时开发者通知。

CHARGE_PRORATED_PRICE

可以使用此模式,因为第 2 层级的每时间单位的订阅价格(36 美元/年 = 3 美元/月)高于第 1 层级的每时间单位的订阅价格(2 美元/月)。李明的第 1 层级订阅会立即终止。由于他支付了一整个月的费用,但只用了一半,因此剩余半个月的订阅费用(1 美元)会应用到新订阅。不过,由于新订阅的费用为每年 36 美元,剩余 15 天的费用为 1.50 美元,因此他需要为新订阅支付 0.50 美元的差价。在 5 月 1 日,李明需要为新订阅层级支付 36 美元,并且此后每年的 5 月 1 日都需要再支付 36 美元。

您应在购买交易成功时调用应用的 PurchasesUpdatedListener,并且您能通过 queryPurchasesAsync() 调用检索新购买交易。您的后端会立即收到 SUBSCRIPTION_PURCHASED 实时开发者通知。

WITHOUT_PRORATION

李明的第 1 层级订阅会立即升级到第 2 层级,无需支付额外的费用,而在 5 月 1 日,他需要为新订阅层级支付 36 美元,并且此后每年的 5 月 1 日都需要再支付 36 美元。

您应在购买交易成功时调用应用的 PurchasesUpdatedListener,并且您能通过 queryPurchasesAsync() 调用检索新购买交易。您的后端会立即收到 SUBSCRIPTION_PURCHASED 实时开发者通知。

DEFERRED

李明的第 1 层级订阅会一直持续到 4 月 30 日到期。在 5 月 1 日,第 2 层级订阅开始生效,李明需要为新订阅层级支付 36 美元。

您应在购买交易成功时调用应用的 PurchasesUpdatedListener,并且您能通过 queryPurchasesAsync() 调用检索新购买交易。您的后端会立即收到 SUBSCRIPTION_PURCHASED 实时开发者通知。您应该处理购买交易,采用与此时处理任何其他新购买交易相同的方式。尤其需要注意的是,请务必确认新的购买交易。请注意,在替换生效时(即旧订阅到期时),系统会填充新订阅的 startTime。届时,您会收到新订阅方案的 SUBSCRIPTION_RENEWED RTDN。如需详细了解 ReplacementMode.DEFERRED 行为,请参阅处理延迟替换

CHARGE_FULL_PRICE

李明的第 1 层级订阅会立即终止。他的第 2 层级订阅当天开始生效,他需要支付 36 美元。由于他支付了一整个月的费用,但只用了一半,因此剩余半个月的订阅费用(1 美元)会应用到新订阅。由于新订阅的费用为每年 36 美元,因此他的订阅期限会延长一年的 1/36(约 10 天)。这样一来,李明的下一次扣款时间距离现在还有 1 年零 10 天,下次扣款金额为 36 美元。此后,他每年需要支付 36 美元。

选择按比例计费模式时,请务必查看我们的替换建议

在应用内触发订阅更改

您的应用可以使用与启动购买流程相同的步骤来为用户提供升级或降级。不过,在升级或降级时,您需要提供当前订阅、将来(升级或降级的)订阅以及要使用的替换模式的详细信息,如以下示例所示:

Kotlin

val offerToken = productDetails
        .getSubscriptionOfferDetails(selectedOfferIndex)
        .getOfferToken()

val billingParams = BillingFlowParams.newBuilder().setProductDetailsParamsList(
       listOf(
           BillingFlowParams.ProductDetailsParams.newBuilder()
               .setProductDetails(productDetails)
               .setOfferToken(offerToken)
               .build()
       )
       ).setSubscriptionUpdateParams(
           BillingFlowParams.SubscriptionUpdateParams.newBuilder()
               .setOldPurchaseToken("old_purchase_token")
               .setSubscriptionReplacementMode(
                 BillingFlowParams.ReplacementMode.CHARGE_FULL_PRICE
               )
               .build()
       ).build()

billingClient.launchBillingFlow(
    activity,
    billingParams
   )
// ...

Java

String offerToken = productDetails
    .getSubscriptionOfferDetails(selectedOfferIndex)
    .getOfferToken();

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(
        ImmuableList.of(
            ProductDetailsParams.newBuilder()
                // fetched via queryProductDetailsAsync
                .setProductDetails(productDetails)
                // offerToken can be found in
                // ProductDetails=>SubscriptionOfferDetails
                .setOfferToken(offerToken)
                .build()))
    .setSubscriptionUpdateParams(
        SubscriptionUpdateParams.newBuilder()
            // purchaseToken can be found in Purchase#getPurchaseToken
            .setOldPurchaseToken("old_purchase_token")
            .setSubscriptionReplacementMode(ReplacementMode.CHARGE_FULL_PRICE)
            .build())
    .build();

BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);
// ...

替换建议

下表显示了不同的按比例计费场景以及我们针对各种场景给出的建议:

场景 建议的替换模式 结果
升级到费用更高的层级 CHARGE_PRORATED_PRICE 用户会立即获得访问权限,而结算周期保持不变。
降级到费用更低的层级 DEFERRED 用户已经付费购买了费用更高的层级,因此将保有访问权限,直到下一个结算日期。
在免费试订期间升级 - 保留免费试订 WITHOUT_PRORATION 用户会保有对免费试订的访问权限,但试订期的剩余时间会升级到更高的层级。
在免费试订期间升级 - 终止对免费试订的访问权限 CHARGE_PRORATED_PRICE 用户会立即获得对新层级的访问权限,但不能再享受免费试订。

处理订阅更改购买交易

就所有条款和用途而言,方案的更改是指新的购买交易,且在结算流程成功完成后应该以此形式处理及确认。除了适当处理新购买交易之外,您还必须停用将被替换的购买交易。

应用内行为与任何新购买交易的行为一样。您的应用会在 PurchasesUpdatedListener 中收到新购买交易的结果,而新购买交易会在 queryPurchasesAsync 中可用。

当购买交易替换现有购买交易时,Google Play Developer API 会在订阅资源中返回一个 linkedPurchaseToken。请务必使在 linkedPurchaseToken 中提供的令牌无效,确保旧令牌不会被用于获取对您服务的访问权限。如需了解如何处理升级购买交易和降级购买交易,请参阅升级、降级和重新注册

当您收到购买令牌时,请遵循与验证新购买令牌相同的验证流程。请务必使用 Google Play 结算库中的 BillingClient.acknowledgePurchase() 或 Google Play Developer API 中的 Purchases.subscriptions:acknowledge 确认这些购买交易。

处理延迟替换

通过延迟替换模式,您可允许用户先用完旧方案中的剩余使用权,再开始使用新方案。

当您针对新购买交易使用 ReplaceMode.DEFERRED 时,queryPurchasesAsync() 会在购买流程结束后返回一个新购买令牌,该令牌仍与旧购买交易相关联,直到在下一个续订日期延迟替换模式生效后,系统才会返回新产品。

过去,您可以使用已废弃的 ProrationMode.DEFERRED 实现这种用户体验,但 Play 结算库 6 中废弃了 ProrationMode.DEFERRED。请参阅下表,了解此行为在哪些方面有所不同:

时间

ProrationMode.DEFERRED(已废弃)

ReplaceMode.DEFERRED

购买流程成功后立即启动(应用)

购买交易完成后,系统会调用 PurchasesUpdatedListener,并附带升级或降级是否成功的状态。

您可以保有对旧方案的使用权,直到下一个续订日期为止。为确保应用提供适当的使用权,queryPurchasesAsync() 会返回一个包含原始购买令牌和原始使用权的 Purchase 对象,直至替换发生。

新购买令牌尚未显示,因此目前无法处理。

购买交易完成后,系统会调用 PurchasesUpdatedListener,并附带升级或降级是否成功的状态。

queryPurchasesAsync() 会立即返回带有购买令牌的购买交易以及与其关联的原始使用权

新购买令牌已显示,考虑到替换的生效时间,应在此时进行处理

购买流程成功后立即启动(后端)

购买流程结束后,发送 SUBSCRIPTION_PURCHASED RTDN。后端尚未获知新购买交易。

购买流程结束后,立即针对新购买令牌发送 SUBSCRIPTION_PURCHASED RTDN。

使用新购买令牌调用 purchases.subscriptionsv2.get 方法会返回包含两个订单项的购买交易:

  • 一项代表当前使用权,“expiryTime”设置为将来的时间,并且没有自动续订标志。
  • 另一项代表使用权,自动续订已开启,且尚无“startTime”(尚未开始)。

针对购买令牌发送 SUBSCRIPTION_EXPIRED。使用购买令牌调用 purchases.subscriptionsv2.get 方法时,显示为已过期(旧方案剩余时长的使用权会转移到新购买交易)。

替换时 - 购买流程后的首次续订(应用)

queryPurchasesAsync() 会返回一个包含购买令牌和使用权的新 Purchase 对象。

新购买令牌现已显示,因此应该进行处理

queryPurchasesAsync() 会立即返回带有购买令牌的购买交易以及与其关联的新使用权

新购买交易应在购买流程成功后已处理完毕,因此除了确保正确授予使用权之外,应用不应执行任何特殊操作。

替换时 - 购买流程后的首次续订(后端)

现在,新购买交易可在系统发送第一个 SUBSCRIPTION_RENEWED RTDN 时处理和确认。

订阅资源中的 linkedPurchaseToken 可用于确定订阅后端的哪个用户(如果适用)应更新为拥有新的使用权。

针对新购买令牌发送 SUBSCRIPTION_PURCHASED RTDN 时处理并确认新购买交易。

使用 ReplaceMode.DEFERRED 时,首次续订将遵循任何其他续订的标准行为,并且当此事件发生时,您无需针对替换处理特殊逻辑。

使用新购买令牌调用 purchases.subscriptionsv2.get 方法会返回包含两个订单项的购买交易:

  • 一项代表使用权,“expiryTime”设置为过去的时间;
  • 一项代表使用权,“startTime”对应于替换发生的时间,“expiryTime”设置为未来的时间

从现在开始,应使用 ReplaceMode.DEFERRED,而非已废弃的 ProrationMode.DEFERRED,因为前者虽然执行与使用权更改相同的行为,但提供的购买交易管理方式与其他新购买交易的行为更加一致。

客户管理

使用实时开发者通知,当用户决定取消订阅时,您可以实时检测到。当用户取消了订阅但在订阅到期之前,您可以向他们发送推送通知或应用内消息,让他们重新订阅。

在用户取消订阅后,您可以尝试在应用内或通过 Play 商店赢回他们。下表介绍了各种订阅场景以及相关的赢回操作和应用要求。

订阅到期之前 订阅到期之后
应用内 Play 商店内 应用内 Play 商店内
赢回功能 应用内订阅 恢复 应用内订阅 重新订阅
用户完成结账流程
用户订阅仍与同一 SKU 关联 用户可以注册相同或不同的 SKU 用户可以注册相同或不同的 SKU
创建新的购买令牌
默认处于启用状态 是,所有开发者都需要支持

未采用结算库 2.0 及以上版本的应用:否

采用结算库 2.0 及以上版本的应用:是。开发者可以在管理中心中选择停用该功能。

何时向用户收取费用

如果使用相同的 SKU:当前结算周期结束时。

如果使用不同的 SKU:取决于按比例计费模式。

当前结算周期结束时 立即 立即
所需实现 在应用中提供重新注册界面

检测订阅状态的变化

指向 Play 商店的深层链接

在应用中提供重新注册界面 处理应用外购买

订阅到期之前 - 应用内

对于已被取消但尚未过期的订阅,您可以通过应用与新订阅者相同的应用内商品购买流程,允许订阅者在您的应用中恢复他们的订阅。请确保界面中会显示用户的现有订阅。例如,您不妨显示用户当前的到期日期、定期支付的费用以及重新激活按钮。

大多数情况下,建议您向用户提供与已订阅内容相同的价格和 SKU,如下所示:

  • 使用同一个 SKU 发起新的订阅购买。
  • 新订阅将替换旧订阅,并在同一到期日期续订。旧订阅会立即标记为“已过期”。
  • 例如,小张订阅了一款示例音乐应用的内容且订阅的到期日期为 8 月 1 日。在 7 月 10 日,他以相同的每月价格重新订阅了一个月的订阅内容。系统会根据余额按比例计算新订阅的费用,新订阅会立即生效,并且仍在 8 月 1 日续订。

如果您想提供不同的价格(例如,新的免费试订或赢回折扣),则可以改为为用户提供不同的 SKU:

  • 使用采用了替换模式 WITHOUT_PRORATION 的不同 SKU 发起升级或降级
  • 新订阅将替换旧订阅,并在同一到期日期续订。在原始到期日期那天,用户会按新 SKU 的价格付费(包括所有初次体验价)。如果旧订阅是使用经过混淆处理的账号 ID 创建的,则应将同一 ID 传递给 BillingFlowParams,以进行升级和降级。
  • 例如,小张订阅了一款示例音乐应用的内容且订阅的到期日期为 8 月 1 日。在 7 月 10 日,他以初次体验价重新订阅了按年订阅的内容。新订阅会立即生效,并且用户将在 8 月 1 日按初次体验价付费。
  • 如果您决定在赢回 SKU 中添加免费试订或初次体验价,请确保用户有资格享受这些优惠,方法是在 Google Play 管理中心取消选中允许在每个应用中免费试订一次复选框,选中该复选框会限制用户在每个应用中只能免费试订一次。

当您收到购买令牌时,应该就像处理新订阅一样来处理购买交易。此外,Google Play Developer API 还会在订阅资源中返回一个 linkedPurchaseToken。请务必让 linkedPurchaseToken 中提供的令牌失效,以确保旧令牌不会被用于获取对您服务的访问权限。

订阅到期之前 - Play 商店内

在订阅被取消但仍然处于有效状态时,用户可以通过点击重新订阅(以前称为恢复)在 Google Play 订阅中心恢复订阅。这样会让订阅和购买令牌保持不变。

Google Play 商店应用中的“订阅”部分,其中显示了已取消的订阅以及“重新订阅”按钮
图 8. Google Play 商店应用中的“账号”>“订阅”部分,其中显示了已取消的订阅以及重新订阅按钮。

如需详细了解如何恢复订阅,请参阅恢复

订阅到期之后 - 应用内

您可以允许订阅已过期的订阅者在您的应用中重新订阅,方法是应用与新订阅者相同的应用内商品购买流程。不过,请注意以下几点:

  • 为了给用户提供折扣,您可能需要为您的订阅提供一个具有特殊定价的商品 ID,也称为“赢回 SKU”。您可以在应用中提供优惠,也可以在应用外(如通过电子邮件)通知用户优惠活动。
  • 为了开始赢回订阅,请使用 Google Play 结算库在您的 Android 应用中启动购买流程。这与新订阅的流程相同,但您可以确定提供给用户的 SKU。
  • 如果您决定在赢回 SKU 中添加免费试订或初次体验价,请确保用户有资格享受这些优惠,方法是在 Google Play 管理中心取消选中允许在每个应用中免费试订一次复选框,选中该复选框会限制用户在每个应用中只能免费试订一次。
  • 如果用户重新订阅同一 SKU,便没有资格再享受免费试订或初次体验价。请务必在界面中说明这一点。

当您收到购买令牌时,应该就像处理新订阅一样来处理购买交易。您将不会在订阅资源中收到 linkedPurchaseToken

订阅到期之后 - Play 商店内

如果您启用了重新订阅功能,用户便可在订阅到期后最长一年时间内,通过在 Google Play 订阅中心点击重新订阅来重新订阅同一 SKU。这样会生成新的订阅和购买令牌。

Google Play 商店应用中的“订阅”部分,其中显示了已取消且已过期的订阅,以及相应的“重新订阅”和“移除”按钮
图 9. Google Play 商店应用中的“账号”>“订阅”部分,其中显示了已取消且已过期的订阅,以及相应的重新订阅移除按钮。

重新订阅属于应用外购买,因此请务必遵循处理在您的应用外进行的购买交易中介绍的最佳实践。

宣传您的订阅

您可以创建促销代码,让部分用户能够免费试订现有订阅更长时间。如需了解详情,请参阅促销代码

对于免费试订,Google Play 会在免费试订开始之前验证用户是否具有有效的付款方式。某些用户可能会看到此验证的结果显示为付款方式被暂停或产生扣款。这种暂停或扣款是暂时的,稍后会撤消或退还。

试订期结束后,系统会通过用户的付款方式,按照全价收取订阅费用。

如果用户在免费试订期间的任一时刻取消了订阅,订阅将保持活动状态,直到试订期结束,当免费试订期结束时,用户不会被扣款。

取消、退款或撤消

您可以使用 Google Play Developer API 取消订阅、为订阅退款撤消订阅。Google Play 管理中心也提供了此功能。

  • 取消:用户可以在 Google Play 上取消订阅。您也可为用户提供一个在您的应用中或您的网站上取消订阅的选项。您的应用应按照取消中的说明处理这些取消操作。
  • 退款:当您退款时,用户可以继续使用订阅内容。例如,如果因技术错误而导致用户无法访问您的商品,但该错误已得到解决,则可以使用退款。请注意,如果要退还的不只是最近一次的付款,或者如果您要办理部分退款,必须使用 Google Play 管理中心。
  • 撤消:当您撤消时,用户会立即失去对订阅的访问权限。例如,如果因技术错误而导致用户无法访问您的商品,因而用户不想继续使用该商品,则可以使用此选项。您的应用应按照撤消中的说明来处理这些取消事件。

下表说明了取消、退款和撤消之间的区别。

停止续订 退还款项 撤消访问权限
取消
退款
撤消

为订阅者推迟结算

您可以使用 Google Play Developer API 中的 Purchases.subscriptions:defer 将自动续订订阅者的下一个结算日期向前推。在推迟期内,用户会订阅您的内容并且拥有完全访问权限,但不会被扣款。订阅续订日期会更新以反映新的日期。

对于预付费方案,您可以使用推迟结算 API 来推迟到期时间。

推迟结算可让您做到以下几点:

  • 将免费访问权限作为一种特别优惠提供给用户,如购买电影时免费一周。
  • 向客户提供免费访问权限以表达善意。

每次调用该 API,结算最短可推迟一天,最长为一年。如需进一步推迟结算,您可以在新的结算日期到来之前再次调用该 API。

例如,Darcy 按月订阅了 Fishing Quarterly 应用的在线内容。正常情况下,她在每个月第一天都需要支付 1.25 英镑的费用。在 3 月,她参与了应用发布商的在线问卷调查。该发布商为她提供了免费六周的奖励,将下一笔付款推迟到 5 月 15 日,也就是在她先前预定结算日期(即 4 月 1 日)的六周后。Darcy 不需要支付 4 月或 5 月初的费用,并且仍能访问相关内容。在 5 月 15 日,她支付了当月 1.25 英镑的正常订阅费用。她的下一个续订日期现在为 6 月 15 日。

推迟结算时,您可能需要通过电子邮件或在应用中通知用户,告知用户他们的结算日期发生了变化。

处理付款遭拒问题

如果续订存在付款问题,Google 会在取消订阅前的一段时间内定期尝试续订。此恢复期可以由一个宽限期和一个帐号保留期组成。在此期间,Google 会向用户发送电子邮件和通知,提示他们更新付款方式。

付款遭拒后,如果配置了宽限期,订阅会进入宽限期。在宽限期内,您应确保用户仍有权访问订阅内容使用权。

任何宽限期结束后,订阅会进入帐号保留期。在帐号保留期间,您应确保用户无权访问订阅内容使用权。

您可以在 Google Play 管理中心内指定每个自动续订型基础方案的宽限期时长和帐号保留时长。指定小于默认值的长度可能会减少从付款遭拒时恢复的订阅数量。

为了在付款遭拒期间最大限度提高恢复订阅的可能性,您可以将付款问题告知用户,并请他们解决此问题。

您可以自行执行此操作(如宽限期账号冻结部分中所述);也可以实现 In-App Messaging API,通过此方法让 Google 在应用中向用户显示消息。

In-App Messaging

如果您使用 InAppMessageCategoryId.TRANSACTIONAL 启用了 In-App Messaging 功能,Google Play 会在宽限期和账号冻结期内每天向用户显示一次消息,并使用户能够无需离开应用即可解决付款问题。

通知用户解决付款问题的信息提示控件
图 20. 通知用户解决付款问题的信息提示控件。

我们建议您在用户每次打开应用时都调用此 API,以确定是否应该显示此消息。

如果用户成功恢复了订阅,您会收到响应代码 SUBSCRIPTION_STATUS_UPDATED 以及购买令牌。然后,您应使用此购买令牌调用 Google Play Developer API 并刷新应用中的订阅状态。

集成 In-App Messaging 功能

如需向用户显示应用内消息,请使用 BillingClient.showInAppMessages()

以下是触发 In-App Messaging 流程的示例:

Kotlin

val inAppMessageParams = InAppMessageParams.newBuilder()
        .addInAppMessageCategoryToShow(InAppMessageCategoryId.TRANSACTIONAL)
        .build()

billingClient.showInAppMessages(activity,
        inAppMessageParams,
        object : InAppMessageResponseListener() {
            override fun onInAppMessageResponse(inAppMessageResult: InAppMessageResult) {
                if (inAppMessageResult.responseCode == InAppMessageResponseCode.NO_ACTION_NEEDED) {
                    // The flow has finished and there is no action needed from developers.
                } else if (inAppMessageResult.responseCode
                        == InAppMessageResponseCode.SUBSCRIPTION_STATUS_UPDATED) {
                    // The subscription status changed. For example, a subscription
                    // has been recovered from a suspend state. Developers should
                    // expect the purchase token to be returned with this response
                    // code and use the purchase token with the Google Play
                    // Developer API.
                }
            }
        })

Java

InAppMessageParams inAppMessageParams = InAppMessageParams.newBuilder()
        .addInAppMessageCategoryToShow(InAppMessageCategoryId.TRANSACTIONAL)
        .build();

billingClient.showInAppMessages(activity,
        inAppMessageParams,
        new InAppMessageResponseListener() {
            @Override
            public void onInAppMessageResponse(InAppMessageResult inAppMessageResult) {
                if (inAppMessageResult.responseCode
                        == InAppMessageResponseCode.NO_ACTION_NEEDED) {
                    // The flow has finished and there is no action needed from developers.
                } else if (inAppMessageResult.responseCode
                        == InAppMessageResponseCode.SUBSCRIPTION_STATUS_UPDATED) {
                    // The subscription status changed. For example, a subscription
                    // has been recovered from a suspend state. Developers should
                    // expect the purchase token to be returned with this response
                    // code and use the purchase token with the Google Play
                    // Developer API.
                }
            }
        });