如果您的应用通过 Google Play 分发,并且您希望销售数字商品或优惠订阅,则必须使用 Google Play 结算服务。Google Play 结算服务提供了用于管理目录、价格和订阅的工具、实用的报告,以及由用户熟悉的 Play 商店提供支持的结账流程。
对于使用 Trusted Web Activity 构建并通过 Google Play 商店分发的应用,您现在可以使用 Payment Request API 和 Digital 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 结算服务,您需要:
- 相互关联的 Google Play 开发者帐号和 Google Payments 商家帐号。
- Play 商品详情以及发布到公开轨道、封闭式测试轨道或内部测试轨道的版本。
- 在 Play 商店中创建和配置应用的产品和订阅。
- 由 Bubblewrap 生成的项目(具有有效的 Digital Asset Links 配置)。
更新 Bubblewrap 项目
如果您未安装 Bubblewrap,则需要安装。如需详细了解如何开始使用,请参阅快速入门指南。如果您已安装 Bubblewrap,请务必更新到 1.8.2 或更高版本。
Bubblewrap 还有标记背后的功能。如需启用此功能,您需要在项目根目录下的 twa-manifest.json
中修改项目配置,并启用 alphaDependencies
和 playBilling
功能:
...,
"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 管理的客户端组件和服务器端组件。
- 如需查看 Peter Conn 的示例,请访问 https://github.com/PEConn/beer
- 请参阅有关购买交易验证的 Play 文档。
- 请考虑使用一个提供多种语言版本的 Google Play Developer API 客户端库。
- 如果您要在应用中实现订阅模式,请参阅 Play 结算服务订阅文档。
- 实现实时开发者通知 (RTDN) 并订阅通知,以便在订阅状态发生变化时通知后端,而不是在 Play 上轮询状态。
- 实现
linkedPurchaseToken
以防止重复订阅。请阅读这篇博文,了解如何正确实现该功能。