利用地区性商品价格开拓新市场

1. 简介

在此 Codelab 中,您将重点学习如何创建一次性商品、定义其购买选项、设置特定地区的价格,以及测试一次性商品的购买流程。

观众

本 Codelab 适用于想要使用 Play 管理中心管理一次性商品目录的 Android 应用开发者。

学习内容…

  • 一次性商品对象模型
  • 如何浏览和使用 Google Play 管理中心来管理一次性商品目录。
  • 如何免费将一次性商品详情翻译成多种语言。
  • 如何为一次性商品配置地区性库存状况和价格
  • 如何使用 Play 结算库 API 查询一次性商品详情。
  • 如何使用 Play Billing Lab 测试一次性商品。

所需条件…

2. 一次性商品首映

一次性商品对象模型可让您以更灵活的方式销售商品,并降低管理商品的复杂性。对象模型会将销售内容与销售方式分开,支持为同一项使用权设定多个价位并以不同的方式向用户营销。对象模型具有三个层次的层次结构:

  • 一次性商品 - 商品对象,用于定义用户购买的商品。
  • 购买选项 - 购买选项定义了向用户授予使用权的途径、商品价格以及供应商品的地区。单款商品可设有多个购买选项,在不同地区提供不同价格。
  • 优惠 - 优惠会影响所关联购买选项对应的价格,可用于构建折扣或预订模型。单个购买选项可设有多项优惠。

下图显示了一次性商品对象模型。

codelab-otp-model.png 图 1:一次性对象模型。

如需了解详情,请参阅一次性商品概览

3. 构建示例应用

此 Codelab 使用一个示例 Android 应用来演示如何管理一次性商品。此示例应用旨在成为一个功能齐全的 Android 应用,其中包含完整的源代码,可展示以下方面:

  • 将应用与 PBL 集成
  • 获取一次性商品和相关购买选项
  • 运行采用区域性价格的购买流程

以下演示视频展示了示例应用在部署和运行后的外观和行为。

如果您已熟悉一次性商品和 Play 结算库 (PBL),可以下载示例应用并试用。

前提条件

在构建和部署示例应用之前,请执行以下操作:

构建

此构建步骤的目标是生成示例应用的已签名 Android App Bundle 文件。

如需生成 Android App Bundle,请执行以下步骤:

  1. 从 GitHub 下载示例应用
  2. 构建示例应用。在构建之前,请更改示例应用的软件包名称,然后进行构建。如果您的 Play 管理中心内有其他应用的软件包,请确保您为示例应用提供的软件包名称是唯一的。

    注意:构建示例应用只会创建一个可用于本地测试的 APK 文件。不过,运行应用不会提取商品和价格,因为尚未在 Play 管理中心内配置商品。
  3. 生成已签名的 Android App Bundle。
    1. 生成上传密钥和密钥库
    2. 使用上传密钥为应用签名
    3. 配置 Play 应用签名功能

下一步是将 Android app bundle 上传到 Google Play 管理中心。

4. 在 Play 管理中心内创建一次性商品

如需在 Google Play 管理中心内创建一次性商品,您需要在 Play 管理中心内拥有一个应用。在 Play 管理中心内创建应用,然后上传之前创建的已签名 app bundle。

创建应用

如需创建应用,请执行以下操作:

  1. 使用您的开发者账号登录 Google Play 管理中心
  2. 点击创建应用。系统随即会打开创建应用页面。
  3. 输入应用名称,选择默认语言,以及其他与应用相关的详细信息。
  4. 点击创建应用。这会在 Google Play 管理中心内创建一个应用。

现在,您可以上传示例应用的已签名 app bundle。

上传已签名的 app bundle

  1. 将已签名的 app bundle 上传到 Google Play 管理中心内部测试轨道。只有在上传后,您才能在 Play 管理中心内配置与创收相关的功能。
  2. 依次点击测试和发布 > 测试 > 内部版本 > 创建新的发布版本
  3. 输入版本名称,然后上传已签名的 APK 文件。
  4. 点击下一步,然后点击保存并发布

现在,您可以创建一次性商品了。

创建一次性商品

如需创建一次性商品,请执行以下操作:

  1. Google Play 管理中心内,从左侧导航菜单中依次前往借助 Play 变现 > 商品 > 一次性商品
  2. 点击创建一次性商品
  3. 输入以下商品详情:
    • 商品 ID:输入唯一 ID。例如 trending_movie_1
    • (可选)标签:添加相关标签。
    • 名称:输入商品名称。例如 Product Movie
    • 说明:输入商品说明。例如 Product Description
    手动翻译商品名称和说明
    默认情况下,商品名称和说明采用英语(美国)- en-US 语言。您还可以手动输入其他语言的名称和说明。如需输入详细信息,请点击管理翻译,选择要输入翻译文本的语言,然后点击应用。下图显示了管理翻译选项:manage-translations.png图 2:管理翻译。

    您选择的语言将显示在语言下拉菜单中。选择每种语言,然后以所选语言输入相应的名称和说明。您还可以免费自动翻译商品名称和说明。如需了解详情,请参阅本 Codelab 中的翻译一次性商品部分。

    注意:在本 Codelab 中,您可以跳过配置图标字段和税务、合规性和计划部分。
  4. 点击下一步
  5. 添加购买选项并配置其地区供应情况。一次性商品需要至少一个购买选项,用于定义使用权的授予方式、价格和地区供应情况。在此 Codelab 中,我们将为商品添加标准的购买选项。

    购买选项部分中,输入以下详细信息:
    • 购买选项 ID:输入唯一 ID。例如 buy-movie
    • 购买类型:选择购买
    • (可选)代码:添加特定于此购买选项的代码。
    • (可选)点击高级选项以配置高级选项。在此 Codelab 中,您可以跳过高级选项配置。
  6. 接下来,您必须为购买选项配置地区性库存状况和价格。在“地区供应情况”中,您可以指定要在哪些地区销售商品,甚至包括您的应用尚未发布到的地区。默认情况下,购买选项将在所有地区提供。

    适用范围和价格部分,依次点击修改适用范围和可预订状态 > 设为不供应。请注意,默认情况下,所有地区的设置均为可用
    1. 选择除 FranceSpainUnited States 以外的所有国家/地区,然后点击设为不供应
    2. 所有地区下拉菜单中,选择可用的国家和地区。此页面仅显示您在上一步中选择的国家/地区。
    3. 对于每个适用的国家/地区,点击价格列中的“修改”图标。系统随即会显示一个用于修改价格的对话框。输入并保存以下价格:
      • 对于 France,输入 10 欧元
      • 对于 Spain,输入 8 欧元
      • 对于 United States,输入 13 美元
  7. 点击 Activate(激活)。这样一来,您的一次性商品便会提供购买购买选项。

注意:系统会根据用户的 Play 国家/地区设置显示地区性价格币种。例如,如果用户的 Play 国家/地区设置为法国,则一次性商品价格以欧元显示。

一次性商品创建视频

以下视频展示了之前介绍的一次性商品创建步骤。

添加“租借”购买选项

现在,为之前创建的一次性商品添加租借购买选项。

  1. Google Play 管理中心内,从左侧导航菜单中依次前往借助 Play 变现 > 商品 > 一次性商品
  2. 点击您在上一步中创建的商品 ID 为 trending_movie_1 的商品对应的向右箭头。
  3. 点击添加购买选项
  4. 购买选项部分中,输入以下详细信息:
    • 购买选项 ID:输入 rent-movie
    • 购买类型:选择租借
    • 租期:选择 48 小时。
    • 租借启用时限:选择 24 小时。
    • (可选)代码:添加特定于此购买选项的代码。
    • (可选)点击高级选项以配置高级选项。在此 Codelab 中,您可以跳过高级选项配置。
  5. 接下来,与购买购买选项类似,配置租借购买选项的地区性提供情况。请参阅上一部分中的第 6 步和第 7 步。设置地区性价格时,请为租赁交易设置不同的价格。例如:
    • France - 5 欧元
    • Spain - 4 欧元
    • United States - 7 美元。

5. 翻译一次性商品详情

您可以使用 Google Play 管理中心内提供的机器翻译功能免费翻译商品名称和说明。

如需翻译标题和说明,请执行以下操作:

  1. Google Play 管理中心内,从左侧导航菜单中依次前往拓展用户群 > 翻译 > 商品详情和应用内商品
  2. 点击创建订单
  3. 选择免费机器翻译选项,然后点击下一步
  4. 翻译为语言中,选择法语 - fr-FR西班牙语 - es-ES,然后点击下一步
  5. 选择一次性商品和订阅内容,然后点击翻译并查看翻译。系统会显示一条免责声明横幅。确认免责声明。
  6. 您现在会看到翻译后的语言列表。点击相应语言的查看并应用。查看文本,然后点击应用所有翻译。针对您选择要翻译的所有语言重复此步骤。

翻译完成后,您可以在 Play 管理中心内修改翻译后的文本。如需修改译文,请执行以下操作:

  1. 打开一次性商品 > [您的一次性商品] > 修改一次性商品 > 修改一次性商品详情页面。
  2. 从语言下拉菜单中选择所需语言。这会以所选语言显示文本。下图显示了选择语言以修改翻译后的文本:

    edit-translations.png 图 3:修改翻译后的文本。
  3. 根据需要修改文字,然后点击保存更改

用户会根据其手机的语言偏好设置看到翻译后的文本。例如,如果用户手机的语言设置为法语,则一次性商品标题和说明会以法语显示。以下示例图片展示了翻译后的文本将以不同语言显示的方式和位置。

post-translation.png图 4:应用中的翻译文本。

转换配置视频

以下视频展示了前文所述的翻译配置步骤。

6. 与 PBL 集成

如需将应用与 Play 结算库 (PBL) 集成,请按以下步骤操作:

  1. 向示例应用添加 Play 结算库依赖项。
    dependencies {
    val billing_version = "8.0.0"
    
    implementation("com.android.billingclient:billing-ktx:$billing_version")
    }
    
  2. 初始化 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();
     }
    
  3. 连接到 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");
            }
            });
    }
    
  4. 获取一次性商品详情。将应用与 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-optionrent-option)。您可以通过每个购买选项的 offerIdToken 来唯一标识相应购买选项。
  5. 获取租借和购买优惠的优惠令牌。您需要使用优惠令牌才能在第 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);
        }
    }
    
  6. 启动结算流程。
    /**
     * 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 集成。

您将了解如何测试价格本地化和应用上架情况,其中应用仅在部分地区上架,且每个地区的价格各不相同。

前提条件

测试购买选项的地区定价

如需测试购买选项的区域性价格,请执行以下操作:

  1. 打开 Play Billing Lab 应用,然后以许可测试者的身份登录。
  2. 配置设置中,点击修改,选择国家/地区 France,然后点击应用。在此处,我们选择 Play 国家/地区,该选择决定了应用中显示的币种。
  3. 关闭并重新打开示例应用。现在,该应用应以欧元显示 France 的购买和租赁币种。

如需测试其他国家/地区,请在第 2 步中选择 Spain,然后执行第 3 步。

Play Billing Lab 测试视频

以下视频展示了使用示例应用进行地区价格测试的步骤。

8. 后续步骤

参考文档

9. 恭喜!

恭喜!您已成功在 Google Play 管理中心内创建新的一次性商品、配置购买选项,并使用 Play 结算服务实验室测试购买流程。现在,您对 Google Play 灵活的一次性购买商品目录有了更深入的了解。

调查问卷

我们非常重视您对此 Codelab 的反馈。不妨抽出几分钟时间填写我们的调查问卷。