关于订阅

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

如果您尚未为您的应用程序配置订阅产品,请参阅 创建和配置您的产品.

订阅概述

订阅表示用户可以在指定时间段内访问的一组权益。例如,订阅可以使用户有权访问音乐流媒体服务。

您可以在同一应用程序中拥有多个订阅,无论是表示不同的权益集,还是表示单一权益集的不同层级(例如,“银牌”和“金牌”层级)。

通过基础计划优惠,您可以为同一订阅产品创建多个配置。例如,您可以为从未订阅过您应用程序的用户创建入门优惠。同样,您可以为已经订阅的用户创建升级优惠。

有关订阅产品、基础计划和优惠的详细概述,请参阅 Play 管理中心帮助中心中的文档。

预付费计划集成

预付费计划不会在过期后自动续订。要延长他们的订阅资格,而不会中断,用户必须为同一订阅的预付费计划充值

对于充值,请像最初购买一样启动计费流程。您无需指明购买是充值。

预付费计划充值始终使用 CHARGE_FULL_PRICE 替换模式,您无需显式设置此模式。用户将立即被收取一个完整的计费周期,他们的资格将延长充值中指定的时长。

充值后,Purchase 结果对象中的以下字段将更新以反映最新的充值购买

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

以下 Purchase 字段始终包含与原始购买中相同的數據

  • 包名
  • 购买状态
  • 产品
  • 自动续订

预付费购买确认

与自动续订订阅类似,您必须在购买后确认预付费计划。最初的购买和任何充值都需要确认。有关更多信息,请参阅 处理购买.

由于预付费计划期限可能较短,因此尽快确认购买非常重要。

期限为一周或更长的预付费计划必须在三天内确认。

期限少于一周的预付费计划必须在计划期限的一半内确认。例如,开发人员有 1.5 天的时间来确认三天期限的预付费计划。

分期付款订阅集成

分期付款订阅是一种订阅类型,用户可以分期付款来支付订阅费用,而不是一次性支付全部订阅费用。

分期付款订阅的其他注意事项

  • 国家/地区可用性:分期付款订阅功能仅在巴西、法国、意大利和西班牙可用(查看管理中心了解最新可用性)。
  • 设置价格:在 Console 上设置分期订阅的价格时,价格代表每月付款金额。此价格与设置的承诺期相结合,在购买界面生成订阅的总金额。
  • 承诺期:初始订阅承诺的总时长,在此期间需要每月付款。例如,如果基本计划的承诺期为 15 个月,用户将在该期间内支付 15 个月的款项。
  • 续订:在分期订阅的语境中,“续订”表示承诺期的结束,无论是初始承诺期还是后续承诺期。在首次注册后,第一次续订发生在整个初始承诺期结束后。后续续订发生在每个后续承诺期结束后。分期订阅的续订类型可以是“每月自动续订”或“自动续订相同时长”。对于“每月自动续订”,没有后续承诺,该计划的行为类似于每月订阅,其中每次每月订阅费用构成续订。
  • 账单周期:在分期订阅的语境中,这指的是基本计划中指定的,每次付款发生的重复间隔。
  • 计划变更与价格变更行为:对于价格变更和取消,承诺是固定的。这意味着如果用户想要取消或开发者想要更改价格,更改将在承诺期结束时生效。对于计划变更,承诺并非固定。这意味着计划变更不必等到承诺期结束,它会根据设置的替换模式立即生效或在下个付款日期生效。
  • 相同订阅计划变更:不允许从分期基本计划更改到同一订阅产品的非分期基本计划。
  • 实时开发者通知 (RTDN):当用户主动取消时,如果承诺期内仍有付款,将立即发送 SUBSCRIPTION_CANCELLATION_SCHEDULED RTDN。取消处于待定状态,将在承诺期结束时生效。然后,如果用户没有恢复,SUBSCRIPTION_CANCELEDSUBSCRIPTION_EXPIRED RTDN 将在承诺期结束时发送。

  • 支付/收入实现:开发者支付将在用户每月付款时发生,遵循与所有其他订阅相同的条款。用户注册分期订阅时,开发者不会预先支付。

  • 漏付收集:如果用户未能支付任何分期订阅款项,Google 或开发者都不会尝试从用户处收取任何此类漏付或未付款项,但 Google 可能会根据其正常的付款重试实践,在任何适用的宽限期或账户持有期内定期重试付款。Google 对任何剩余的未付分期款项不承担责任。

  • Play 结算库可用性installmentDetails 字段仅适用于 PBL 7 或更高版本。对于 PBL 5 及更高版本,分期订阅使用 queryProductDetails() 返回,但订阅不会包含详细的分期信息,例如计划的已付付款次数。

使用深度链接允许用户管理订阅

您的应用应在设置或偏好设置屏幕上包含一个链接,允许用户管理他们的订阅,您可以将其整合到您的应用的自然外观和感觉中。

您可以从您的应用中包含一个深度链接到 Google Play 订阅中心,用于未过期的订阅,您可以使用 subscriptionState 字段来确定 订阅资源。根据此,您可以通过多种方式深度链接到 Play 商店订阅中心。

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

https://play.google.com/store/account/subscriptions
The Play Store subscriptions screen shows status for all of a user's Google Play-billed subscriptions.
图 1. Play 商店订阅屏幕显示用户所有 Google Play 计费订阅的状态。


Tap on a subscription to see additional details.
图 2. 点击订阅以查看更多详细信息。

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

要直接链接到未过期订阅的管理页面,请指出与已购买订阅关联的包名和 productId。要以编程方式确定现有订阅的 productId,请查询您的应用的后端或调用 BillingClient.queryPurchasesAsync() 以获取与特定用户关联的订阅列表。每个订阅都包含作为订阅状态信息一部分的相应 productId。每个与订阅购买相关的 SubscriptionPurchaseLineItem 对象都包含与用户在该行项目中购买的订阅相关的 productId 值。

使用以下 URL 将用户定向到特定订阅管理屏幕,将“your-sub-product-id”和“your-app-package”分别替换为 productId 和应用包名

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

然后,用户能够管理他们的付款方式并访问包括取消、重新订阅和暂停在内的功能。

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

您可以为现有订阅者提供各种选项来更改他们的订阅计划,以更好地满足他们的需求

  • 如果您销售多个订阅层级,例如“基本”和“高级”订阅,您可以允许用户通过购买不同订阅的基本计划或优惠来切换层级。
  • 您可以允许用户更改他们当前的账单周期,例如从每月计划切换到年度计划。
  • 您还可以允许用户在自动续订计划和预付费计划之间切换。

您可以通过为符合条件的用户提供订阅优惠来鼓励任何这些更改,以提供折扣。例如,您可以创建一个优惠,在从每月计划切换到年度计划时,为第一年提供 50% 的折扣,并将此优惠限制为订阅了每月计划且尚未购买此优惠的用户。有关优惠资格标准的更多信息,请访问 帮助中心

图 3 显示了一个具有三种不同计划的示例应用

This app has three subscription tiers..
图 3. 此应用有三个订阅层级。

您的应用可以显示类似于图 3 的屏幕,为用户提供更改订阅的选项。在所有情况下,都应该清楚地向用户说明他们当前的订阅计划是什么,以及他们有哪些更改订阅的选项。

当用户决定升级、降级或更改他们的订阅时,您指定一个替换模式,该模式确定如何应用当前已付账单周期的按比例计费值以及何时发生任何权利变更。

替换模式

下表列出了可用的替换模式以及示例用法和被视为已支付的付款次数。

替换模式

描述

示例用法

记录为已支付的承诺付款(用于分期订阅替换)

WITH_TIME_PRORATION

订阅立即升级或降级。任何剩余时间将根据价格差进行调整,并通过将下一个账单日期推迟到新的订阅中进行抵消。这是默认行为。

升级到更昂贵的层级,无需立即额外付款。

0

CHARGE_PRORATED_PRICE

订阅立即升级,账单周期保持不变。然后,剩余期间的价格差将计入用户账单。

注意:此选项仅适用于订阅升级,即每次时间的价格上涨。

升级到更昂贵的层级,不更改账单日期。

1

CHARGE_FULL_PRICE

订阅立即升级或降级,用户立即支付新权利的全部价格。之前订阅的剩余价值将用于同一权利的延续,或在切换到不同权利时按时间进行按比例分配。

注意:如果新订阅有免费试用或入门优惠,用户在升级或降级时将支付 0 美元或入门优惠的价格,以实际情况为准。

从较短的账单周期升级到较长的账单周期。

1(注意:如果新订阅有免费试用,则为 0。)

WITHOUT_PRORATION

订阅立即升级或降级,新价格在订阅续订时收取。账单周期保持不变。

升级到更高的订阅层级,同时保留任何剩余的免费时间。

0

DEFERRED

订阅仅在订阅续订时升级或降级,但新购买会立即发出,新权利的开始日期在未来,因此开发者可以允许用户在需要时进行其他更改。例如,他们可以恢复到原始计划或启动新的延迟计划更改。注意:对于分期订阅,计划更改发生在下个付款日期开始时。

降级到更便宜的层级。

1

要详细了解升级或降级优惠的不同加价和赢回应用,请阅读优惠和促销指南。

设置购买的替换模式

您可以根据您的偏好和业务逻辑,为不同类型的订阅转换使用不同的替换模式。本节说明如何为订阅的更改设置替换模式以及适用的限制。

在同一订阅内重新订阅或切换计划

您可以在 Google Play Console 中指定默认的替换模式。此设置可让您选择何时向当前订阅者收费,如果他们为同一订阅购买了不同的基本计划或优惠,或在取消后重新订阅。可用的选项是立即收费,相当于 CHARGE_FULL_PRICE,以及在下个账单日期收费,相当于 WITHOUT_PRORATION。当在同一订阅内切换基本计划时,这些是唯一相关的替换模式。

例如,如果您在用户取消后但订阅结束之前为同一计划实施赢回优惠,您可以将新购买处理为常规购买,而无需在 SubscriptionUpdateParams 中指示任何值。系统将使用您在订阅中配置的默认替换模式,并自动处理从旧购买到新购买的计划转换。

跨订阅计划切换,或覆盖默认替换模式

如果用户正在更改订阅产品——购买不同的订阅——或者出于任何原因要覆盖默认的替换模式,您需要在购买流程参数中运行时指定比例分配率。

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

  • 升级、降级或发起同一订阅切换预付费计划预付费计划、自动续订计划或分期付款计划,唯一允许的替换模式是CHARGE_FULL_PRICE。如果您指定了任何其他替换模式,则购买将失败,并且会向用户显示错误。
  • 在同一订阅内切换计划自动续订计划预付费计划或自动续订计划,有效的比例分配模式是CHARGE_FULL_PRICEWITHOUT_PRORATION。如果您指定了任何其他比例分配模式,则购买将失败,并且会向用户显示错误。
  • 不允许在同一订阅产品内从分期付款基本计划切换到非分期付款基本计划。

替换示例和行为

要了解每种比例分配模式的工作原理,请考虑以下场景

山姆威斯订阅了 Country Gardener 应用程序的在线内容。他每月订阅了内容的第一层版本,该版本仅包含文本。此订阅每月花费他2 美元,并在每月第一天续订。

4 月 15 日,山姆威斯选择升级到第二层订阅的年度版本,该版本包括视频更新,每年花费36 美元

升级订阅时,开发者选择比例分配模式。以下列表描述了每种比例分配模式如何影响山姆威斯的订阅

WITH_TIME_PRORATION

山姆威斯的第一层订阅立即结束。因为他为整个四月 (4 月 1 日至 30 日) 付款,但中途升级,所以半个月的订阅费用 (1 美元) 将计入他的新订阅。但是,由于新订阅每年花费 36 美元,因此 1 美元的信用余额仅支付了 10 天 (4 月 16 日至 25 日);因此,在 4 月 26 日,他将被收取 36 美元用于新订阅,并在接下来的每年的 4 月 26 日再收取 36 美元。

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

CHARGE_PRORATED_PRICE

可以使用这种模式,因为第二层订阅的每时间单位价格 (36 美元/年 = 3 美元/月) 大于第一层订阅的每时间单位价格 (2 美元/月)。山姆威斯的第一层订阅立即结束。因为他支付了整个月的费用,但只使用了半个月,所以半个月的订阅费用 (1 美元) 将计入他的新订阅。但是,由于新订阅每年花费 36 美元,所以剩余的 15 天花费了 1.50 美元;因此,他将被收取 0.50 美元的差价用于他的新订阅。在 5 月 1 日,山姆威斯将被收取 36 美元用于他的新订阅层,并在接下来的每年的 5 月 1 日再收取 36 美元。

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

WITHOUT_PRORATION

山姆威斯的第一层订阅会立即升级到第二层,无需额外付费,并在 5 月 1 日被收取 36 美元用于他的新订阅层,并在接下来的每年的 5 月 1 日再收取 36 美元。

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

DEFERRED

山姆威斯的第一层订阅将持续到 4 月 30 日到期。在 5 月 1 日,第二层订阅生效,山姆威斯将被收取 36 美元用于他的新订阅层。

您应该在购买成功后立即调用应用程序的PurchasesUpdatedListener,并且能够在queryPurchasesAsync() 调用中检索新购买。您的后端会立即收到SUBSCRIPTION_PURCHASED实时开发者通知。您应该处理购买,就像您在此时处理任何其他新购买一样。特别地,确保您确认了新购买。请注意,新订阅的startTime是在替换生效时填充的,即旧订阅到期时。在那一点上,您将收到SUBSCRIPTION_RENEWEDRTDN 用于新订阅计划。有关ReplacementMode.DEFERRED行为的更多信息,请阅读处理延迟替换

CHARGE_FULL_PRICE

山姆威斯的第一层订阅立即结束。他的第二层订阅从今天开始,他将被收取 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 开发者 API 在订阅资源 中返回linkedPurchaseToken,当购买替换现有购买时。请务必使linkedPurchaseToken 中提供的令牌失效,以确保旧令牌不会用于访问您的服务。有关处理升级和降级购买的信息,请参阅升级、降级和重新注册

收到新的购买令牌后,请按照与验证新的购买令牌相同的验证过程进行操作。请务必使用 Google Play 结算库中的BillingClient.acknowledgePurchase() 或 Google Play 开发者 API 中的Purchases.subscriptions:acknowledge 来确认这些购买。

处理延迟替换

延迟替换模式允许您让用户在开始使用新计划之前使用完旧计划中的剩余权利。

当您对新的购买使用ReplacementMode.DEFERRED 时,queryPurchasesAsync() 会在购买流程之后返回一个新的购买令牌,该令牌与旧产品相关联,直到在下一个续订日期发生延迟替换,之后将返回新产品。

在过去,您可以使用已弃用的ProrationMode.DEFERRED来实现这种用户体验,但是ProrationMode.DEFERRED在 Play 结算库 6 中被弃用。请参阅下表以了解行为差异

时间

ProrationMode.DEFERRED (已弃用)

ReplacementMode.DEFERRED

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

PurchasesUpdatedListener 在购买后调用,并提供升级或降级是否成功的状态。

对旧计划的权利将持续到下一个续订日期。为了确保应用程序提供正确的权利,queryPurchasesAsync() 会返回一个 Purchase 对象,其中包含原始购买令牌和原始权利,直到替换发生。

新的购买令牌不会显示,因此此时无法处理。

PurchasesUpdatedListener 在购买后调用,并提供升级或降级是否成功的状态。

queryPurchasesAsync() 会立即返回包含购买令牌的购买,以及与其关联的原始权利

新的购买令牌会显示,因此应该在此时处理,同时考虑到替换何时发生。

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

SUBSCRIPTION_PURCHASED RTDN 不会在购买流程之后发送。后端尚未收到新的购买信息。

SUBSCRIPTION_PURCHASED RTDN (包含旧产品 ID) 会在购买流程之后立即发送,用于新的购买令牌。

使用新的购买令牌调用purchases.subscriptionsv2.get 方法会返回一个购买,该购买的 'startTime' 指示购买时间,包含两行项目

  • 一个代表权益,并在未来具有“过期时间”。旧权益不会续订,并且具有一个 DeferredItemReplacement,其中包含权益产品的。这表示旧权益在过期时将进行待处理的替换。
  • 一个代表新购买的权益。它没有为“过期时间”设置任何值。

对于购买令牌发送的SUBSCRIPTION_EXPIRED。当使用购买令牌调用purchases.subscriptionsv2.get方法时,它显示为已过期(旧计划的权益将转移到新的购买中,以获取剩余时间)。

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

queryPurchasesAsync()返回一个具有购买令牌和权益的新购买对象。

现在出现了新的购买令牌,因此应对其进行处理

queryPurchasesAsync()立即返回具有购买令牌的购买以及与之关联的新权益

当购买流程成功时,新的购买应该已经得到处理,因此应用程序除了确保授予正确的权益外,不应该采取任何特殊的操作。

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

当发送第一个SUBSCRIPTION_RENEWED RTDN时,现在可以处理并确认新的购买。

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

当为新的购买令牌发送SUBSCRIPTION_PURCHASED RTDN时,新的购买已得到处理并确认,并被记录为“开始时间”。

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

当使用新的购买令牌调用purchases.subscriptionsv2.get方法时,将返回具有两行项目的购买。

  • 一个代表权益,过期时间在过去,并且没有为 DeferredItemReplacement设置任何值。
  • 一个代表权益,过期时间在未来,并且自动续订标志已打开。

从现在开始,应该使用ReplacementMode.DEFERRED而不是已弃用的ProrationMode.DEFERRED,因为它在权益更改方面表现出相同的行为,但提供了一种更符合其他新购买行为的方式来管理购买。

客户管理

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

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

订阅过期前 订阅过期后
应用内 Play 商店 应用内 Play 商店
赢回功能 应用内订阅 恢复 应用内订阅 重新订阅
用户经历结账流程
用户订阅与同一个 SKU 相关联 用户可以注册相同或不同的 SKU 用户可以注册相同或不同的 SKU
创建新的购买令牌
默认情况下启用 是,所有开发者都需要支持

没有 Billing Library 2.0+ 的应用程序:否

具有 Billing Library 2.0+ 的应用程序:是。开发者可以在控制台中选择退出。

当用户被收取费用时

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

如果使用不同的 SKU:取决于比例分配模式。

当前结算周期的结束 立即 立即
需要实现 在您的应用程序中提供重新注册 UI

检测订阅状态的变化

深层链接到 Play 商店

在您的应用程序中提供重新注册 UI 处理应用程序外购买

订阅过期前 - 应用内

对于已取消但尚未过期的订阅,您可以允许订阅者在应用程序内恢复其订阅,方法是应用与新订阅者相同的应用内产品购买流程。确保您的 UI 反映用户拥有现有订阅。例如,您可能希望显示用户的当前过期日期和重复价格,并带有重新激活按钮。

大多数情况下,您将希望为用户提供他们已订阅的相同价格和 SKU,如下所示

  • 使用相同的 SKU 启动新的订阅购买。
  • 新的订阅将替换旧的订阅,并在相同的过期日期续订。旧的订阅立即被标记为已过期。
  • 例如,Achilles 订阅了 Example Music App,订阅将于 8 月 1 日过期。7 月 10 日,他重新订阅了每月相同价格的月度订阅。新的订阅按比例分配剩余的信用额度,立即生效,并且仍然在 8 月 1 日续订。

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

  • 使用替换模式WITHOUT_PRORATION 启动升级或降级,使用不同的 SKU。
  • 新的订阅将替换旧的订阅,并在相同的过期日期续订。用户将在原始过期日期支付新 SKU 的价格,包括任何介绍性价格。如果旧订阅是使用模糊的帐户 ID 创建的,则应将相同的 ID 传递到BillingFlowParams 以进行升级和降级。
  • 例如,Achilles 订阅了 Example Music App,订阅将于 8 月 1 日过期。7 月 10 日,他重新订阅了一个带有介绍性价格的年度订阅。新的订阅立即生效,用户将在 8 月 1 日支付介绍性价格。
  • 如果您决定在赢回 SKU 中包含免费试用或介绍性价格,请确保用户有资格,方法是在 Google Play 管理中心取消选中每个应用程序允许一次免费试用框,该框会限制用户每个应用程序只能获得一次免费试用。

收到购买令牌后,处理购买,就像处理新的订阅一样。此外,Google Play 开发者 API 在订阅资源中返回linkedPurchaseToken。请务必使linkedPurchaseToken中提供的令牌失效,以确保旧令牌不被用来访问您的服务。

订阅过期前 - Play 商店

当订阅被取消,但仍处于活动状态时,用户可以通过点击 Google Play 订阅中心中的重新订阅(以前称为恢复)来恢复订阅。这将保留相同的订阅和购买令牌。

subscriptions section in the google play store app showing a
            cancelled subscription with a resubscribe button
图 8. Google Play 商店应用程序中的帐户 > 订阅部分,显示了一个带有重新订阅按钮的已取消订阅。

有关恢复订阅的更多信息,请参阅恢复

订阅过期后 - 应用内

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

  • 为了为用户提供折扣,您可能希望为您的订阅提供一个具有特殊定价的产品 ID,也称为赢回 SKU。您可以在应用程序中提供优惠,或者您可以在应用程序之外(例如,在电子邮件中)通知用户优惠。
  • 要启动赢回订阅,请使用 Google Play 结算库在您的 Android 应用程序中启动购买流程。这与新的订阅相同,但您可以确定用户可以使用哪个 SKU。
  • 如果您决定在赢回 SKU 中包含免费试用或介绍性价格,请确保用户有资格,方法是在 Google Play 管理中心取消选中每个应用程序允许一次免费试用框,该框会限制用户每个应用程序只能获得一次免费试用。
  • 如果用户重新订阅了同一个 SKU,他们将不再有资格享受免费试用或介绍性价格。确保您的 UI 反映这一点。

收到购买令牌后,处理购买,就像处理新的订阅一样。您不会在订阅资源中收到linkedPurchaseToken

订阅过期后 - Play 商店

如果已启用,用户可以在过期后的一年内通过点击 Google Play 订阅中心中的重新订阅来重新订阅同一个 SKU。这将生成新的订阅和购买令牌。

subscriptions section in the google play store app showing a
            cancelled and expired subscription with resubscribe and remove
            buttons
图 9. Google Play 商店应用程序中的帐户 > 订阅部分,显示了一个已取消和已过期的订阅,带有重新订阅删除按钮。

重新订阅被视为应用程序外购买,因此请务必遵循处理从应用程序外部进行的购买的最佳实践。

推广您的订阅

您可以创建推广代码,为选定的用户提供对现有订阅的延长免费试用期。要了解更多信息,请参阅推广代码

对于免费试用,Google Play 会在开始免费试用之前验证用户是否拥有有效的付款方式。一些用户可能会将此验证视为对他们的付款方式的保留或收费。此保留或收费是暂时的,稍后将被撤销或退款。

试用期结束后,用户将通过其付款方式支付完整的订阅费用。

如果用户在免费试用期间的任何时间取消订阅,则该订阅将在试用期结束之前保持活动状态,并且在免费试用期结束时不会收取费用。

取消、退款或撤销

您可以使用Google Play 开发者 API取消退款撤销订阅。此功能也可以在Google Play 管理中心中使用。

  • 取消:用户可以在 Google Play 上取消订阅。您也可以为用户提供在应用程序或网站上取消的选项。您的应用程序应该按照取消中所述处理这些取消。
  • 退款:当您退款时,用户可以继续使用订阅。如果例如存在阻止用户访问您的产品的技术错误,但该错误已得到解决,则可以使用退款。请注意,要退款超过最近的付款,或者如果您要进行部分退款,则必须使用 Google Play 管理中心。
  • 撤销:当您撤销时,用户将立即失去对订阅的访问权限。如果例如存在阻止用户访问您的产品的技术错误,并且用户不想继续使用该产品,则可以使用此功能。您的应用程序应该按照撤销中所述处理这些取消。

下表说明了取消、退款和撤销之间的差异。

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

为订阅者延迟结算

您可以使用 Google Play 开发者 API 中的 Purchases.subscriptions:defer 来提前自动续订订阅者的下一个计费日期。在延期期间,用户订阅您的内容并拥有完全访问权限,但不会被收费。订阅续订日期会更新以反映新日期。

对于预付费计划,您可以使用延期计费 API 延期到期时间。

延期计费允许您执行以下操作:

  • 向用户提供免费访问权限作为特殊优惠,例如购买电影时赠送一周免费试用。
  • 出于善意,向客户提供免费访问权限。

每次 API 调用可以将计费延期最短一天,最长一年。若要进一步延期计费,您可以在新计费日期到达之前再次调用 API。

例如,Darcy 订阅了 Fishing Quarterly 应用程序的在线内容,每月订阅费为 1.25 英镑,通常在每月 1 日收费。3 月,她参与了该应用程序发布者的在线调查。发布者通过将下次付款延期至 5 月 15 日(比她之前计划的 4 月 1 日计费日期晚 6 周)来奖励她 6 周的免费使用权。Darcy 在 4 月和 5 月初无需付费,但仍然可以访问内容。5 月 15 日,她将被收取当月 1.25 英镑的正常订阅费。她的下一个续订日期现在是 6 月 15 日。

延期时,您可能需要通过电子邮件或在应用程序内通知用户,告知他们计费日期已更改。

处理付款失败

如果订阅续订出现付款问题,Google 将定期尝试在取消之前续订订阅一段时间。此恢复期可能包括宽限期,然后是账户冻结期。在此期间,Google 会向用户发送电子邮件和通知,提示他们更新付款方式。

如果付款失败,订阅将进入 宽限期(如果已配置)。在宽限期内,您应确保用户仍然可以访问订阅权限。

任何宽限期结束后,订阅将进入 账户冻结期。在账户冻结期内,您应确保用户无法访问订阅权限。

您可以在 Google Play 管理中心指定每个自动续订基础计划的宽限期和账户冻结期。指定小于默认值的长度可能会减少从付款失败中恢复的订阅数量。

为了最大程度地提高订阅在付款失败期间恢复的可能性,您可以告知用户付款问题并要求他们解决问题。

您可以自己完成此操作(如 宽限期账户冻结期 部分所述),也可以实现应用内消息 API,让 Google 在您的应用中向用户显示消息。

应用内消息

如果您已使用 InAppMessageCategoryId.TRANSACTIONAL 启用应用内消息,Google Play 将在宽限期和账户冻结期内每天向用户显示消息,并为他们提供修复付款而不离开应用的机会。

Snackbar notifying the user to fix their payment
图 20. 通知用户修复付款的 Snackbar。

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

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

集成应用内消息

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

以下是如何触发应用内消息流程的示例:

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

处理订阅挂起交易

挂起交易 可能会发生在首次购买、充值、升级或降级时。订阅购买从 SUBSCRIPTION_STATE_PENDING 状态开始,然后过渡到 SUBSCRIPTION_STATE_ACTIVE 状态。如果交易过期或被用户取消,它将转到 SUBSCRIPTION_STATE_PENDING_PURCHASE_EXPIRED 状态。您必须并且应该在交易完成后才更新用户的权限。

首次购买时,带有挂起交易的订阅状态更改非常简单。当用户启动挂起交易时,您的应用程序会收到一个状态为 PENDINGPurchase。当交易完成时,您的应用程序会再次收到 Purchase,状态更新为 PURCHASED。带有类型 SUBSCRIPTION_PURCHASEDSubscriptionNotification 消息将发送到您的 RTDN 客户端。按照正常流程验证购买,授予用户访问内容的权限并确认购买。如果交易过期或被取消,则会向您的 RTDN 客户端发送类型为 SUBSCRIPTION_PENDING_PURCHASE_CANCELEDSubscriptionNotification 消息。在这种情况下,用户永远不应该获得访问内容的权限。

带有挂起交易的充值、升级或降级涉及旧订阅和新订阅的状态更改。当用户启动挂起充值、升级或降级交易时,您的应用程序会收到一个带有 PendingPurchaseUpdate 对象的旧订阅的 Purchase。此时,用户仍然拥有旧订阅,尚未获得新订阅。在 PendingPurchaseUpdate 对象上调用 getProducts()getPurchaseToken() 将返回新订阅的产品 ID 和购买令牌。当交易完成时,您的应用程序会收到一个顶层购买令牌设置为新订阅且状态设置为 PURCHASEDPurchase。带有类型 SUBSCRIPTION_PURCHASEDSubscriptionNotification 消息将发送到您的 RTDN 客户端。只有此时,您才应该用新购买令牌替换旧购买令牌,并更新用户的访问内容权限。如果交易过期或被取消,则会向您的 RTDN 客户端发送类型为 SUBSCRIPTION_PENDING_PURCHASE_CANCELEDSubscriptionNotification 消息。在这种情况下,用户仍然应该可以访问旧订阅的内容。