1. 简介
在此 Codelab 中,您将重点学习如何创建一次性商品、定义其购买选项、设置特定地区的价格,以及测试一次性商品的购买流程。
观众
本 Codelab 适用于想要使用 Play 管理中心管理一次性商品目录的 Android 应用开发者。
学习内容…
- 一次性商品对象模型。
- 如何浏览和使用 Google Play 管理中心来管理一次性商品目录。
- 如何免费将一次性商品详情翻译成多种语言。
- 如何为一次性商品配置地区性库存状况和价格。
- 如何使用 Play 结算库 API 查询一次性商品详情。
- 如何使用 Play Billing Lab 测试一次性商品。
所需条件…
- 使用开发者账号访问 Google Play 管理中心。如果您没有开发者账号,则需要创建账号。
- 此 Codelab 的示例应用,您可以从 GitHub 下载。
- Android Studio。
2. 一次性商品首映
一次性商品对象模型可让您以更灵活的方式销售商品,并降低管理商品的复杂性。对象模型会将销售内容与销售方式分开,支持为同一项使用权设定多个价位并以不同的方式向用户营销。对象模型具有三个层次的层次结构:
- 一次性商品 - 商品对象,用于定义用户购买的商品。
- 购买选项 - 购买选项定义了向用户授予使用权的途径、商品价格以及供应商品的地区。单款商品可设有多个购买选项,在不同地区提供不同价格。
- 优惠 - 优惠会影响所关联购买选项对应的价格,可用于构建折扣或预订模型。单个购买选项可设有多项优惠。
下图显示了一次性商品对象模型。
图 1:一次性对象模型。
如需了解详情,请参阅一次性商品概览。
3. 构建示例应用
此 Codelab 使用一个示例 Android 应用来演示如何管理一次性商品。此示例应用旨在成为一个功能齐全的 Android 应用,其中包含完整的源代码,可展示以下方面:
- 将应用与 PBL 集成
- 获取一次性商品和相关购买选项
- 运行采用区域性价格的购买流程
以下演示视频展示了示例应用在部署和运行后的外观和行为。
如果您已熟悉一次性商品和 Play 结算库 (PBL),可以下载示例应用并试用。
前提条件
在构建和部署示例应用之前,请执行以下操作:
- 创建 Google Play 管理中心开发者账号。如果您已有开发者账号,请跳过此步骤。
- 在 Play 管理中心内创建新应用。创建应用时,您可以为示例应用指定任意应用名称。
- 安装 Android Studio。
构建
此构建步骤的目标是生成示例应用的已签名 Android App Bundle 文件。
如需生成 Android App Bundle,请执行以下步骤:
- 从 GitHub 下载示例应用。
- 构建示例应用。在构建之前,请更改示例应用的软件包名称,然后进行构建。如果您的 Play 管理中心内有其他应用的软件包,请确保您为示例应用提供的软件包名称是唯一的。
注意:构建示例应用只会创建一个可用于本地测试的 APK 文件。不过,运行应用不会提取商品和价格,因为尚未在 Play 管理中心内配置商品。 - 生成已签名的 Android App Bundle。
下一步是将 Android app bundle 上传到 Google Play 管理中心。
4. 在 Play 管理中心内创建一次性商品
如需在 Google Play 管理中心内创建一次性商品,您需要在 Play 管理中心内拥有一个应用。在 Play 管理中心内创建应用,然后上传之前创建的已签名 app bundle。
创建应用
如需创建应用,请执行以下操作:
- 使用您的开发者账号登录 Google Play 管理中心。
- 点击创建应用。系统随即会打开创建应用页面。
- 输入应用名称,选择默认语言,以及其他与应用相关的详细信息。
- 点击创建应用。这会在 Google Play 管理中心内创建一个应用。
现在,您可以上传示例应用的已签名 app bundle。
上传已签名的 app bundle
- 将已签名的 app bundle 上传到 Google Play 管理中心内部测试轨道。只有在上传后,您才能在 Play 管理中心内配置与创收相关的功能。
- 依次点击测试和发布 > 测试 > 内部版本 > 创建新的发布版本。
- 输入版本名称,然后上传已签名的 APK 文件。
- 点击下一步,然后点击保存并发布。
现在,您可以创建一次性商品了。
创建一次性商品
如需创建一次性商品,请执行以下操作:
- 在 Google Play 管理中心内,从左侧导航菜单中依次前往借助 Play 变现 > 商品 > 一次性商品。
- 点击创建一次性商品。
- 输入以下商品详情:
- 商品 ID:输入唯一 ID。例如
trending_movie_1。 - (可选)标签:添加相关标签。
- 名称:输入商品名称。例如
Product Movie。 - 说明:输入商品说明。例如
Product Description。
默认情况下,商品名称和说明采用英语(美国)- en-US 语言。您还可以手动输入其他语言的名称和说明。如需输入详细信息,请点击管理翻译,选择要输入翻译文本的语言,然后点击应用。下图显示了管理翻译选项:
图 2:管理翻译。
您选择的语言将显示在语言下拉菜单中。选择每种语言,然后以所选语言输入相应的名称和说明。您还可以免费自动翻译商品名称和说明。如需了解详情,请参阅本 Codelab 中的翻译一次性商品部分。
注意:在本 Codelab 中,您可以跳过配置图标字段和税务、合规性和计划部分。 - 商品 ID:输入唯一 ID。例如
- 点击下一步。
- 添加购买选项并配置其地区供应情况。一次性商品需要至少一个购买选项,用于定义使用权的授予方式、价格和地区供应情况。在此 Codelab 中,我们将为商品添加标准的购买选项。
在购买选项部分中,输入以下详细信息:- 购买选项 ID:输入唯一 ID。例如
buy-movie。 - 购买类型:选择购买。
- (可选)代码:添加特定于此购买选项的代码。
- (可选)点击高级选项以配置高级选项。在此 Codelab 中,您可以跳过高级选项配置。
- 购买选项 ID:输入唯一 ID。例如
- 接下来,您必须为购买选项配置地区性库存状况和价格。在“地区供应情况”中,您可以指定要在哪些地区销售商品,甚至包括您的应用尚未发布到的地区。默认情况下,购买选项将在所有地区提供。
在适用范围和价格部分,依次点击修改适用范围和可预订状态 > 设为不供应。请注意,默认情况下,所有地区的设置均为可用。- 选择除
France、Spain和United States以外的所有国家/地区,然后点击设为不供应。 - 从所有地区下拉菜单中,选择可用的国家和地区。此页面仅显示您在上一步中选择的国家/地区。
- 对于每个适用的国家/地区,点击价格列中的“修改”图标。系统随即会显示一个用于修改价格的对话框。输入并保存以下价格:
- 对于
France,输入 10 欧元 - 对于
Spain,输入 8 欧元 - 对于
United States,输入 13 美元
- 对于
- 选择除
- 点击 Activate(激活)。这样一来,您的一次性商品便会提供购买购买选项。
注意:系统会根据用户的 Play 国家/地区设置显示地区性价格币种。例如,如果用户的 Play 国家/地区设置为法国,则一次性商品价格以欧元显示。
一次性商品创建视频
以下视频展示了之前介绍的一次性商品创建步骤。
添加“租借”购买选项
现在,为之前创建的一次性商品添加租借购买选项。
- 在 Google Play 管理中心内,从左侧导航菜单中依次前往借助 Play 变现 > 商品 > 一次性商品。
- 点击您在上一步中创建的商品 ID 为
trending_movie_1的商品对应的向右箭头。 - 点击添加购买选项。
- 在购买选项部分中,输入以下详细信息:
- 购买选项 ID:输入
rent-movie。 - 购买类型:选择租借。
- 租期:选择 48 小时。
- 租借启用时限:选择 24 小时。
- (可选)代码:添加特定于此购买选项的代码。
- (可选)点击高级选项以配置高级选项。在此 Codelab 中,您可以跳过高级选项配置。
- 购买选项 ID:输入
- 接下来,与购买购买选项类似,配置租借购买选项的地区性提供情况。请参阅上一部分中的第 6 步和第 7 步。设置地区性价格时,请为租赁交易设置不同的价格。例如:
France- 5 欧元Spain- 4 欧元United States- 7 美元。
5. 翻译一次性商品详情
您可以使用 Google Play 管理中心内提供的机器翻译功能免费翻译商品名称和说明。
如需翻译标题和说明,请执行以下操作:
- 在 Google Play 管理中心内,从左侧导航菜单中依次前往拓展用户群 > 翻译 > 商品详情和应用内商品。
- 点击创建订单。
- 选择免费机器翻译选项,然后点击下一步。
- 在翻译为语言中,选择法语 - fr-FR 和西班牙语 - es-ES,然后点击下一步。
- 选择一次性商品和订阅内容,然后点击翻译并查看翻译。系统会显示一条免责声明横幅。确认免责声明。
- 您现在会看到翻译后的语言列表。点击相应语言的查看并应用。查看文本,然后点击应用所有翻译。针对您选择要翻译的所有语言重复此步骤。
翻译完成后,您可以在 Play 管理中心内修改翻译后的文本。如需修改译文,请执行以下操作:
- 打开一次性商品 > [您的一次性商品] > 修改一次性商品 > 修改一次性商品详情页面。
- 从语言下拉菜单中选择所需语言。这会以所选语言显示文本。下图显示了选择语言以修改翻译后的文本:
图 3:修改翻译后的文本。 - 根据需要修改文字,然后点击保存更改。
用户会根据其手机的语言偏好设置看到翻译后的文本。例如,如果用户手机的语言设置为法语,则一次性商品标题和说明会以法语显示。以下示例图片展示了翻译后的文本将以不同语言显示的方式和位置。
图 4:应用中的翻译文本。
转换配置视频
以下视频展示了前文所述的翻译配置步骤。
6. 与 PBL 集成
如需将应用与 Play 结算库 (PBL) 集成,请按以下步骤操作:
- 向示例应用添加 Play 结算库依赖项。
dependencies { val billing_version = "8.0.0" implementation("com.android.billingclient:billing-ktx:$billing_version") } - 初始化 BillingClient。BillingClient 是位于应用中并与 Play 结算库通信的客户端 SDK。以下代码段展示了如何初始化结算客户端。
private BillingClient createBillingClient() { return BillingClient.newBuilder(activity) .enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build()) // For one-time products, add a listener to process and acknowledge the purchases. This will notify // Google the purchase was processed. // For client-only apps, use billingClient.acknowledgePurchase(). // If you have a secure backend, you must acknowledge purchases on your server using the // server-side API. // See https://developer.android.com/google/play/billing/security#acknowledge // In this sample snippet purchases aren't processed. You must // implement your business logic to process and acknowledge the purchases. .setListener((billingResult, purchases) -> {}) .enableAutoServiceReconnection() .build(); } - 连接到 Google Play。以下代码段展示了如何连接到 Google Play。
/** * Starts the billing connection with Google Play. This method should be called exactly once * before any other methods in this class. * * @param productList The list of products to query for after the connection is established. */ public void startBillingConnection(List<Product> productList) { billingClient.startConnection( new BillingClientStateListener() { @Override public void onBillingSetupFinished(BillingResult billingResult) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { Log.d(TAG, "Billing Client Connection Successful"); queryProductDetails(productList); } else { Log.e(TAG, "Billing Client Connection Failed: " + billingResult.getDebugMessage()); listener.onBillingSetupFailed(billingResult); // Propagate the error to the listener to show a message to the user. } } @Override public void onBillingServiceDisconnected() { Log.e(TAG, "Billing Client Connection Lost"); listener.onBillingError("Billing Connection Lost"); } }); } - 获取一次性商品详情。将应用与 PBL 集成后,您必须将一次性商品详情提取到应用中。以下代码段展示了如何在应用中提取一次性商品详情。
在private void queryProductDetails(List<Product> productList) { QueryProductDetailsParams queryProductDetailsParams = QueryProductDetailsParams.newBuilder().setProductList(productList).build(); billingClient.queryProductDetailsAsync( queryProductDetailsParams, new ProductDetailsResponseListener() { @Override public void onProductDetailsResponse( BillingResult billingResult, QueryProductDetailsResult productDetailsResponse) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { List<ProductDetails> productDetailsList = productDetailsResponse.getProductDetailsList(); listener.onProductDetailsResponse(productDetailsList); } else { Log.e(TAG, "QueryProductDetailsAsync Failed: " + billingResult.getDebugMessage()); listener.onBillingError("Query Products Failed: " + billingResult.getResponseCode()); } } }); }ProductDetails中提取一次性商品(在本例中为trending_movie_1)会得到类似于以下内容的响应: 请注意,购买和租借选项在{ "productId": "trending_movie_1", "type": "inapp", "title": "Purrfect Mayhem: The Rewind Protocol (Movies All Day | Play Samples)", "name": "Purrfect Mayhem: The Rewind Protocol", "description": "Dr. Arid Thorne and a smart tiger named Yolo find a mysterious tape. It's a \"Rewind Protocol\" to fix time. A shadowy group, the Clockinator, hunts them to seize the tape's power.", "skuDetailsToken": "<---skuDetailsToken--->", "oneTimePurchaseOfferDetails": {}, "oneTimePurchaseOfferDetailsList": [ { "priceAmountMicros": 13000000, "priceCurrencyCode": "USD", "formattedPrice": "$13.00", "offerIdToken": "<---buy offerIdToken --->", "purchaseOptionId": "buy-option", "offerTags": [ "adventure", "mystery" ] }, { "priceAmountMicros": 7000000, "priceCurrencyCode": "USD", "formattedPrice": "$7.00", "offerIdToken": "<---rent offerIdToken--->", "purchaseOptionId": "rent-option", "offerTags": [ "adventure", "mystery" ], "rentalDetails": { "rentalPeriod": "P30D", "rentalExpirationPeriod": "PT24H" } } ] }oneTimePurchaseOfferDetailsList中可用。此列表包含在 Play 管理中心内配置的 2 个购买选项(buy-option 和 rent-option)。您可以通过每个购买选项的 offerIdToken 来唯一标识相应购买选项。 - 获取租借和购买优惠的优惠令牌。您需要使用优惠令牌才能在第 6 步中启动结算流程。
@Override public void onProductDetailsResponse(List<ProductDetails> productDetailsList) { if (productDetailsList != null && !productDetailsList.isEmpty()) { // Iterate over all details of the queried product in step 4. for (ProductDetails productDetails : productDetailsList) { // Get the list of all the offers associated with the product. List<ProductDetails.OneTimePurchaseOfferDetails> offerDetailsList = productDetails.getOneTimePurchaseOfferDetailsList(); // Iterate over the offer details for (ProductDetails.OneTimePurchaseOfferDetails offerDetails : offerDetailsList) { // For a Rent purchase option, the // offerDetails.getRentalDetails() method returns // the rent information. If this information is present, // the offer corresponds to a Rent purchsae option. if (offerDetails.getRentalDetails() != null) { rentFormattedPrice = offerDetails.getFormattedPrice(); // Get the offerIdToken for the Rent purchase option rentOfferToken = offerDetails.getOfferToken(); rentMovieTags = offerDetails.getOfferTags(); } // If the offerDetails.getRentalDetails() returns // null, the offer corresponds to a Buy purchsae option. else { buyFormattedPrice = offerDetails.getFormattedPrice(); // Get the offerIdToken for the Buy purchase option buyOfferToken = offerDetails.getOfferToken(); buyMovieTags = offerDetails.getOfferTags(); } } updateUIButtons(); return; } } else { Log.e(TAG, "No product details found for " + productId); } } - 启动结算流程。
/** * Launches the billing flow for the product with the given offer token. * * @param activity The activity instance from which the billing flow will be launched. * @param productDetails The product details of the product to purchase. * @param offerToken The offer token of the product to purchase. * @return The result of the billing flow. */ public void launchPurchase(Activity activity, ProductDetails productDetails, String offerToken) { ImmutableList<BillingFlowParams.ProductDetailsParams> productDetailsParamsList = ImmutableList.of( BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(productDetails) .setOfferToken(offerToken) .build()); BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(productDetailsParamsList) .build(); billingClient.launchBillingFlow(activity, billingFlowParams); }
提示:您还可以设置实时开发者通知 (RTDN),以实施挽回客户的广告系列和其他购买生命周期管理策略。如需了解如何设置 RTDN 并处理通知,以实现准确的跟踪和授权,建议您完成 Maximize Your Play Billing Integration (最大限度地利用 Play 结算集成) Codelab
7. 测试购买选项
在正式版应用中提供一次性商品之前,您可以使用许可测试人员和 Play Billing Lab 测试 PBL 集成。
您将了解如何测试价格本地化和应用上架情况,其中应用仅在部分地区上架,且每个地区的价格各不相同。
前提条件
- 在 Google Play 管理中心内添加许可测试人员,然后为内部测试启用许可测试人员。
- 在手机或模拟器上下载并安装 Play Billing Lab 应用。
- 在手机或模拟器上运行之前创建的示例应用。
测试购买选项的地区定价
如需测试购买选项的区域性价格,请执行以下操作:
- 打开 Play Billing Lab 应用,然后以许可测试者的身份登录。
- 在配置设置中,点击修改,选择国家/地区
France,然后点击应用。在此处,我们选择 Play 国家/地区,该选择决定了应用中显示的币种。 - 关闭并重新打开示例应用。现在,该应用应以欧元显示
France的购买和租赁币种。
如需测试其他国家/地区,请在第 2 步中选择 Spain,然后执行第 3 步。
Play Billing Lab 测试视频
以下视频展示了使用示例应用进行地区价格测试的步骤。
8. 后续步骤
- 了解如何最大限度地利用 Play 结算集成。
- 了解如何分析商品购买流程中的放弃情况。
- 请务必遵循验证和处理购买交易的最佳实践,在用户开始购买这些商品后,在您的安全后端执行这些操作。
参考文档
9. 恭喜!
恭喜!您已成功在 Google Play 管理中心内创建新的一次性商品、配置购买选项,并使用 Play 结算服务实验室测试购买流程。现在,您对 Google Play 灵活的一次性购买商品目录有了更深入的了解。
调查问卷
我们非常重视您对此 Codelab 的反馈。不妨抽出几分钟时间填写我们的调查问卷。