使用 Digital Goods API 和 Payment Request API 通过 Google Play 结算服务接收付款

安德烈·奇普里亚尼·班达拉
André Cipriani Bandarra

如果您的应用通过 Google Play 分发,并且您希望销售数字商品或优惠订阅,则必须使用 Google Play 结算服务。Google Play 结算服务提供了用于管理目录、价格和订阅的工具、实用的报告,以及由用户熟悉的 Play 商店提供支持的结账流程。

对于使用 Trusted Web Activity 构建并通过 Google Play 商店分发的应用,您现在可以使用 Payment Request APIDigital Goods API 与 Google Play 结算服务集成。适用于 Android 和 ChromeOS 的 Chrome 101 及更高版本。

在本指南中,您将学习如何向 PWA 添加 Google Play 结算服务支持,并将其打包,以便在 Google Play 商店中针对 ChromeOS 和 Play 商店分发。

您将使用两个 Web 平台 API 为 PWA 添加 Play 结算服务支持。Digital Goods API 用于收集 SKU 信息,并检查 Play 商店中的购买交易和使用权。Payment Request API 用于将 Google Play 商店配置为付款方式,并完成购买流程。

如何通过 Play 商店中的应用创收

您的应用可以通过两种方式在 Play 商店中借助 Google Play 结算服务进行创收:

  • 借助应用内购功能,您可以销售虚拟耐用品和消耗品,例如增加额外功能或移除广告。
  • 订阅:让您的用户定期付费,持续访问内容或服务,例如新闻订阅或会员。

要求

如需设置 Google Play 结算服务,您需要:

更新 Bubblewrap 项目

如果您未安装 Bubblewrap,则需要安装。如需详细了解如何开始使用,请参阅快速入门指南。如果您已安装 Bubblewrap,请务必更新到 1.8.2 或更高版本。

Bubblewrap 还有标记背后的功能。如需启用此功能,您需要在项目根目录下的 twa-manifest.json 中修改项目配置,并启用 alphaDependenciesplayBilling 功能:

  ...,
  "enableNotifications": true,
  "features": {
    "playBilling": {
      "enabled": true
    }
  },
  "alphaDependencies": {
    "enabled": true
  },
  ...

更新配置文件后,运行 bubblewrap update 以将配置应用于项目,然后运行 bubblewrap build 以生成新的 Android 软件包,并将该软件包上传到 Play 商店。

用于检测 Digital Goods API 和 Google Play 结算服务可用性的功能

目前,只有当 PWA 在 Trusted Web Activity 中执行时,Chrome 才支持 Digital Goods API,并且可以通过检查 window 对象上是否有 getDigitalGoodsService 来检测该 API 是否可用:

if ('getDigitalGoodsService' in window) {
 // Digital Goods API is supported!
}

Digital Goods API 可在任何浏览器中使用,并且支持不同的商店。为了检查是否支持特定的商店后端,您需要调用 getDigitalGoodsService() 并以参数形式传递商店 ID。Google Play 商店由字符串 https://play.google.com/billing 标识:

if ('getDigitalGoodsService' in window) {
  // Digital Goods API is supported!
  try {
    const service =
        await window.getDigitalGoodsService('https://play.google.com/billing');
    // Google Play Billing is supported!

  } catch (error) {
    // Google Play Billing is not available. Use another payment flow.
    return;
  }
}

检索 SKU 的详细信息

Digital Goods API 提供了 getDetails(),支持从付款后端检索商品名、说明(最重要的是价格)等信息。

然后,您可以在使用界面中使用此信息,并向用户提供更多详细信息:

const skuDetails = await service.getDetails(['shiny_sword', 'gem']);
for (item of skuDetails) {
  // Format the price according to the user locale.
  const localizedPrice = new Intl.NumberFormat(
      navigator.language,
      {style: 'currency', currency: item.price.currency}
    ).format(item.price.value);

  // Render the price to the UI.
  renderProductDetails(
        item.itemId, item.title, localizedPrice, item.description);
}

构建购买流程

PaymentRequest 的构造函数采用两个参数:付款方式列表和付款明细列表。

在 Trusted Web Activity 中,您必须使用 Google Play 结算服务付款方式,方法是将 https://play.google.com/billing 设置为标识符,并将产品 SKU 添加为数据成员:

async function makePurchase(service, sku) {
   // Define the preferred payment method and item ID
   const paymentMethods = [{
       supportedMethods: "https://play.google.com/billing",
       data: {
           sku: sku,
       }
   }];

   ...
}

虽然必须提供付款信息,但 Play 结算服务会忽略这些值,并使用在 Play 管理中心内创建 SKU 时设置的值,因此可能会填入虚假值:

const paymentDetails = {
    total: {
        label: `Total`,
        amount: {currency: `USD`, value: `0`}
    }
};

const request = new PaymentRequest(paymentMethods, paymentDetails);

对付款请求对象调用 show() 以启动付款流程。如果 promise 成功,则表示付款成功。如果付款失败,则用户很可能取消了付款。

如果 promise 成功,您需要验证并确认购买交易。为防范欺诈,此步骤必须使用后端实现。请参阅 Play 结算服务文档,了解如何在后端实现验证。如果您不确认购买交易,三天后,用户会收到退款,并且 Google Play 会撤消该购买交易

...
const request = new PaymentRequest(paymentMethods, paymentDetails);
try {
    const paymentResponse = await request.show();
    const {purchaseToken} = paymentResponse.details;

    // Call backend to validate and acknowledge the purchase.
    if (await acknowledgePurchaseOnBackend(purchaseToken, sku)) {
        // Optional: tell the PaymentRequest API the validation was
        // successful. The user-agent may show a "payment successful"
        // message to the user.
        const paymentComplete = await paymentResponse.complete('success');
    } else {
        // Optional: tell the PaymentRequest API the validation failed. The
        // user agent may show a message to the user.
        const paymentComplete = await paymentResponse.complete('fail');
    }
} catch(e) {
    // The purchase failed, and we can handle the failure here. AbortError
    // usually means a user cancellation
}
...

(可选)可以对 purchaseToken 调用 consume(),以将购买交易标记为已用完,并允许其再次购买。

综上所述,购买方法应如下所示:

async function makePurchase(service, sku) {
    // Define the preferred payment method and item ID
    const paymentMethods = [{
        supportedMethods: "https://play.google.com/billing",
        data: {
            sku: sku,
        }
    }];

    // The "total" member of the paymentDetails is required by the Payment
    // Request API, but is not used when using Google Play Billing. We can
    // set it up with bogus details.
    const paymentDetails = {
        total: {
            label: `Total`,
            amount: {currency: `USD`, value: `0`}
        }
    };

    const request = new PaymentRequest(paymentMethods, paymentDetails);
    try {
        const paymentResponse = await request.show();
        const {purchaseToken} = paymentResponse.details;

        // Call backend to validate and acknowledge the purchase.
        if (await acknowledgePurchaseOnBackend(purchaseToken, sku)) {
            // Optional: consume the purchase, allowing the user to purchase
            // the same item again.
            service.consume(purchaseToken);

            // Optional: tell the PaymentRequest API the validation was
            // successful. The user-agent may show a "payment successful"
            // message to the user.
            const paymentComplete =
                    await paymentResponse.complete('success');
        } else {
            // Optional: tell the PaymentRequest API the validation failed.
            // The user agent may show a message to the user.
            const paymentComplete = await paymentResponse.complete('fail');
        }
    } catch(e) {
        // The purchase failed, and we can handle the failure here.
        // AbortError usually means a user cancellation
    }
}

查看现有购买交易的状态

借助 Digital Goods API,您可以检查用户之前已经进行的购买交易(无论是在其他设备上、之前安装时、通过促销代码兑换过,还是上次打开应用时)已拥有任何现有使用权(尚未消耗的应用内购买或正在进行的订阅)。


const service =
     await window.getDigitalGoodsService('https://play.google.com/billing');
...
const existingPurchases = await service.listPurchases();
for (const p of existingPurchases) {
    // Update the UI with items the user is already entitled to.
    console.log(`Users has entitlement for ${p.itemId}`);
}

这也是检查之前进行但未确认的购买交易的好时机。 建议您尽快确认购买交易,以确保用户的权限正确体现在您的应用中。

const service =
     await window.getDigitalGoodsService("https://play.google.com/billing");
...
const existingPurchases = await service.listPurchases();
for (const p of existingPurchases) {
    await verifyOrAcknowledgePurchaseOnBackend(p.purchaseToken, p.itemId);

    // Update the UI with items the user is already entitled to.
    console.log(`Users has entitlement for ${p.itemId}`);
}

测试集成

在开发 Android 设备上

您可以在 Android 开发设备上启用 Digital Goods API 以进行测试:

  • 确保您使用的是 Android 9 或更高版本,并启用开发者模式
  • 安装 Chrome 101 或更高版本。
  • 在 Chrome 中启用以下标志,方法是转到 chrome://flags 并按名称搜索这些标志:
    • #enable-debug-for-store-billing
  • 请确保该网站使用 https 协议托管。使用 http 将导致 API 状态变为 undefined

在 ChromeOS 设备上

从版本 89 开始,ChromeOS 稳定版将提供 Digital Goods API。在此期间,可以测试 Digital Goods API:

  • 从设备上的 Play 商店安装您的应用。
  • 请确保该网站使用 https 协议托管。使用 http 将导致 API 状态变为 undefined

测试用户和质量检查团队

Play 商店提供各种测试功能,包括用户测试帐号和测试 SKU。 如需了解详情,请参阅 Google Play 结算服务测试文档

下一步做什么?

如本文档中所述,Play Billing API 具有由 Digital Goods API 管理的客户端组件和服务器端组件。