针对外部优惠计划的应用内集成指南

本指南介绍了如何与相关 API 集成,以便在符合条件的应用和地区中支持外部优惠。如需详细了解外部优惠计划(包括资格要求和地理范围),请参阅计划要求

Play 结算库设置

如需使用外部优惠 API,请向您的 Android 应用添加 Play 结算库依赖项(版本 8.2 或更高版本)。如果您需要从较早版本迁移,请先按照迁移指南中的说明操作,然后再尝试实现外部优惠。

连接到 Google Play

集成流程的最初步骤与结算服务集成指南中所述的一些步骤相同,但您必须在初始化 BillingClient 时调用 enableBillingProgram 来指明您要使用外部优惠:

以下示例演示了如何通过这些调整来初始化 BillingClient

Kotlin

val billingClient = BillingClient.newBuilder(context)
  .enableBillingProgram(BillingProgram.EXTERNAL_OFFER)
  .build()

Java

private BillingClient billingClient = BillingClient.newBuilder(context)
    .enableBillingProgram(BillingProgram.EXTERNAL_OFFER)
    .build();

初始化 BillingClient 后,您需要按照集成指南中的说明与 Google Play 建立连接

查看适用范围

如需确认当前用户是否可享受外部优惠,请调用 isBillingProgramAvailableAsync

如果有外部优惠,此 API 会返回 BillingResponseCode.OK。 如需详细了解您的应用应如何响应其他响应代码,请参阅响应处理部分。

Kotlin


billingClient.isBillingProgramAvailableAsync(
  BillingProgram.EXTERNAL_OFFER,
  object : BillingProgramAvailabilityListener {
    override fun onBillingProgramAvailabilityResponse(
      billingResult: BillingResult,
      billingProgramAvailabilityDetails: BillingProgramAvailabilityDetails) {
        if (billingResult.responseCode !=  BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors,
            // handling external offers unavailable, etc.
            return
        }

        // External offers are available. Continue with steps in the
        // guide.
      }
  })

Java


billingClient.isBillingProgramAvailableAsync(
  BillingProgram.EXTERNAL_OFFER,
  new BillingProgramAvailabilityListener() {
    @Override
    public void onBillingProgramAvailabilityResponse(
      BillingResult billingResult,
      BillingProgramAvailabilityDetails billingProgramAvailabilityDetails) {
        if (billingResult.getResponseCode() != BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors,
            // handling external offers being unavailable, etc.
            return;
        }
        // External offers are available. Continue with steps in the
        // guide.
      }
  });

准备外部交易令牌

如需向 Google Play 报告外部交易,您必须拥有通过 Play 结算库生成的外部交易令牌。您可以通过调用 createBillingProgramReportingDetailsAsync API 来获取此令牌。在将用户引导到应用外部之前,必须立即为每个外部优惠生成新令牌。不得跨交易缓存令牌。

Kotlin

val params =
  BillingProgramReportingDetailsParams.newBuilder()
    .setBillingProgram(BillingProgram.EXTERNAL_OFFER)
    .build();

billingClient.createBillingProgramReportingDetailsAsync(
  params,
  object : BillingProgramReportingDetailsListener {
    override fun onCreateBillingProgramReportingDetailsResponse(
      billingResult: BillingResult,
      billingProgramReportingDetails: BillingProgramReportingDetails?) {
        if (billingResult.responseCode !=  BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors.
            return
        }
        val externalTransactionToken =
            billingProgramReportingDetails?.externalTransactionToken
        // Persist the transaction token in your backend. You may pass it
        // to the external website when calling the launchExternalLink API.
    }
})

Java

BillingProgramReportingDetailsParams params =
  BillingProgramReportingDetailsParams.newBuilder()
    .setBillingProgram(BillingProgram.EXTERNAL_OFFER)
    .build();

billingClient.createBillingProgramReportingDetailsAsync(
  params,
  new BillingProgramReportingDetailsListener() {
    @Override
    public void onCreateBillingProgramReportingDetailsResponse(
      BillingResult billingResult,
      @Nullable BillingProgramReportingDetails
        billingProgramReportingDetails) {
        if (billingResult.getResponseCode() != BillingResponseCode.OK) {
            // Handle failures such as retrying due to network errors.
            return;
        }

        String transactionToken =
          billingProgramReportingDetails.getExternalTransactionToken();
        // Persist the transaction token in your backend. You may pass it
        // to the external website when calling the launchExternalLink API.
      }
});

或者,您可以使用 Kotlin 扩展查询挂起函数 createBillingProgramReportingDetailsAsync,这样您就无需定义监听器:

  val createBillingProgramReportingDetailsResult =
    withContext(context) {
      billingClient
        .createBillingProgramReportingDetails(params)
    }
  // Process the result

启动外部优惠流程

如需启动外部优惠流程,符合条件的应用必须从应用的主线程调用 launchExternalLink() API。此 API 接受 LaunchExternalLinkParams 对象作为输入。如需创建 LaunchExternalLinkParams 对象,请使用 LaunchExternalLinkParams.Builder 类。此类包含以下参数:

  • linkUri - 提供数字内容或应用下载的外部网站的链接。对于应用下载,此链接必须在 Play 管理中心内注册并获得批准。
  • linkType - 向用户提供的内容类型。
  • launchMode - 指定链接的启动方式。对于应用下载,您必须将此属性设置为 LAUNCH_IN_EXTERNAL_BROWSER_OR_APP
  • billingProgram - 将此项设置为 BillingProgram.EXTERNAL_OFFER

当您调用 launchExternalLink() 时,系统可能会根据用户的设置向用户显示其他信息对话框。Play 会根据 launchMode 参数在外部浏览器中启动链接 URI,或者将流程返回到您的应用以启动该 URI。在大多数情况下,您可以使用 LAUNCH_IN_EXTERNAL_BROWSER_OR_APP 模式,让 Play 为您启动 URI。如果您想实现更自定义的行为,例如在 WebView 中启动 URI 或在特定浏览器中打开 URI,可以使用 CALLER_WILL_LAUNCH_LINK 模式。为保护用户隐私,请确保 URI 中未传递任何个人身份信息 (PII)。

Kotlin


// An activity reference from which the external offers flow will be launched.
val activity = ...;

val params =
  LaunchExternalLinkParams.newBuilder()
    .setBillingProgram(BillingProgram.EXTERNAL_OFFER)
    // You can pass along the external transaction token from
    // BillingProgramReportingDetails as a URL parameter in the URI
    .setLinkUri(yourLinkUri)
    .setLinkType(LaunchExternalLinkParams.LinkType.LINK_TO_APP_DOWNLOAD)
    .setLaunchMode(
      LaunchExternalLinkParams.LaunchMode.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP)
    .build()

val listener : LaunchExternalLinkResponseListener =
  LaunchExternalLinkResponseListener {
      override fun onLaunchExternalLinkResponse(billingResult: BillingResult) {
    if (billingResult.responseCode == BillingResponseCode.OK) {
      // Proceed with the rest of the external offer flow. If the user
      // purchases an item, be sure to report the transaction to Google Play.
    } else {
      // Handle failures such as retrying due to network errors.
    }
  }
}

billingClient.launchExternalLink(activity, params, listener)

Java


// An activity reference from which the external offers flow will be launched.
Activity activity = ...;

LaunchExternalLinkParams params = LaunchExternalLinkParams.newBuilder()
  .setBillingProgram(BillingProgram.EXTERNAL_OFFER)
  // You can pass along the external transaction token from  
  // BillingProgramReportingDetails as a URL parameter in the URI
  .setLinkUri(yourLinkUri)
  .setLinkType(LaunchExternalLinkParams.LinkType.LINK_TO_APP_DOWNLOAD)
  .setLaunchMode(
    LaunchExternalLinkParams.LaunchMode.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP)
  .build();

LaunchExternalLinkResponseListener listener =
  new LaunchExternalLinkResponseListener() {
    @Override
    public void onLaunchExternalLinkResponse(BillingResult billingResult) {
      if (billingResult.responseCode == BillingResponseCode.OK) {
        // Proceed with the rest of the external offer flow. If the user
        // purchases an item, be sure to report the transaction to Google
        // Play.
      } else {
        // Handle failures such as retrying due to network errors.
      }
    }
  }

billingClient.launchExternalLink(activity, params, listener);

如果您将 LaunchMode 设置为 CALLER_WILL_LAUNCH_LINK,则仅当 onLaunchExternalLinkResponse 提供 BillingResponseCode.OK 时,才应将用户引导至应用外部。

向 Google Play 报告交易

您必须从后端调用 Google Play Developer API,向 Google Play 报告所有外部交易。报告交易时,您必须提供从 createBillingProgramReportingDetailsAsync API 获取的 externalTransactionToken。如果用户进行多次购买,您可以使用同一 externalTransactionToken 来报告每次购买。如需了解如何报告交易,请参阅后端集成指南

响应处理

如果发生错误,方法 isBillingProgramAvailableAsync()createBillingProgramReportingDetailsAsync()launchExternalLink() 可能会返回除 BillingResponseCode.OK 之外的响应。建议按如下方式处理这些响应代码:

  • ERROR:这是内部错误。请勿继续进行交易或打开外部网站。通过调用 launchExternalLink() 进行重试,以便在下次尝试将用户引导至应用外部时,向用户显示信息对话框。
  • FEATURE_NOT_SUPPORTED:当前设备上的 Play 商店不支持外部优惠 API。请勿继续进行交易或打开外部网站。
  • USER_CANCELED:不继续打开外部网站。再次调用 launchExternalLink() 以在下次尝试将用户引导至应用外部时向用户显示信息对话框。
  • BILLING_UNAVAILABLE:交易无法使用外部优惠,因此不应按照此计划继续进行。这是因为用户不在符合此计划条件的国家/地区,或者您的账号未成功注册此计划。如果是后一种情况,请在 Play 管理中心内检查您的注册状态。
  • DEVELOPER_ERROR:请求中存在错误。使用调试消息找出并更正错误,然后再继续交易。
  • NETWORK_ERROR, SERVICE_DISCONNECTED, SERVICE_UNAVAILABLE:这些是暂时性错误,应通过适当的重试政策进行处理。如果发生 SERVICE_DISCONNECTED 错误,请重新与 Google Play 建立连接,然后再重试。

测试外部优惠

许可测试人员应用于测试外部优惠集成。您不会收到许可测试人员账号发起的交易的账单。如需详细了解如何配置许可测试人员,请参阅使用应用许可来测试应用内购结算功能

后续步骤

完成应用内集成后,您就可以集成后端了。