PAYATHON 2026

如何修改 Android 应用中订阅产品的价格?

支付阿杰

结论

订阅价格应在 Google Play Console 中修改,而不是通过 In-App Billing API 调整。原则上,能否改价与应用使用新版还是旧版 Billing API 无关。Billing API 用于查询商品、发起购买和处理交易,商品价格则由 Play Console 管理。

需要分别考虑两类用户:

  • 新订阅用户:新价格生效后,通常会按新价格购买。
  • 现有订阅用户:是否保留旧价格、何时迁移到新价格,以及是否需要用户确认,取决于 Play Console 当前提供的价格迁移选项、用户所在地区和 Google Play 的订阅价格变更政策。

旧版 In-App Billing API 可能无法完整支持现行的价格变更确认流程。因此,除了修改后台价格,还要检查现有订阅者的迁移方式,并尽快升级到当前受支持的 Google Play Billing Library。

操作步骤

1. 在 Play Console 中修改价格

进入对应应用,找到订阅产品的价格配置。Play Console 的菜单名称可能随界面更新而变化,相关设置通常位于:

应用 → 变现产品 → 订阅

选择目标订阅或相应的基础方案,修改各个国家或地区的价格并保存。

修改前需要确认:

  • 新价格何时生效;
  • 新价格是否仅适用于新订阅者;
  • 现有订阅者是否保留旧价格;
  • 迁移现有订阅者时,是否需要用户明确同意;
  • 用户未同意价格变更时,订阅是否会被取消。

不要根据后台显示的默认价格推断所有地区的实际售价。Google Play 可能按照税费、币种和当地定价规则生成不同的区域价格。

2. 检查应用是否动态读取价格

应用界面中的价格应来自 Google Play 返回的商品信息,不要写死在代码或资源文件中,例如:

priceTextView.setText("$49.99/year");

否则,在 Play Console 改价后,购买页面可能已经采用新价格,而应用自己的界面仍然显示旧价格。

旧版 In-App Billing API 一般通过 getSkuDetails() 查询商品详情。示意代码如下:

ArrayList<String> skuList = new ArrayList<>();
skuList.add("annual_subscription");

Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);

Bundle skuDetails = billingService.getSkuDetails(
        3,
        getPackageName(),
        "subs",
        querySkus
);

int responseCode = skuDetails.getInt("RESPONSE_CODE");

if (responseCode == 0) {
    ArrayList<String> detailsList =
            skuDetails.getStringArrayList("DETAILS_LIST");

    if (detailsList != null) {
        for (String detailsJson : detailsList) {
            JSONObject details = new JSONObject(detailsJson);

            String productId = details.getString("productId");
            String formattedPrice = details.getString("price");

            if ("annual_subscription".equals(productId)) {
                priceTextView.setText(formattedPrice);
            }
        }
    }
}

重点是直接使用 Google Play 返回的格式化价格 price,不要自行拼接货币符号,也不要用浮点数重新计算显示价格。

这段代码只用于说明旧接口的查询方式。实际字段和返回结构应以项目当前使用的 Billing API 版本为准。

3. 处理现有订阅者

改价时,已经订阅的用户最容易被忽略。

如果 Play Console 允许现有订阅者继续使用旧价格,应用一般不需要立即处理价格确认,但必须能够接受同一个订阅产品对不同用户显示不同价格。

如果要将现有订阅者迁移到新价格,需要先在 Play Console 中查看迁移规则。部分涨价场景可能要求用户确认,而旧版 Billing API 对相关确认流程的支持可能有限。此时需要:

  1. 确认 Google Play 是否会通过 Play Console 直接通知用户;
  2. 检查应用当前使用的 Billing API 是否支持相应的价格变更确认流程;
  3. 如果旧接口无法满足要求,先升级 Billing Library,再迁移现有用户;
  4. 在测试环境中验证用户同意、拒绝、未响应以及订阅取消等状态。

不要通过删除旧订阅商品,再创建同 ID 商品的方式强制改价。删除或停用订阅可能影响现有订阅关系,而且商品 ID 通常不能按预期重复使用。

是否必须升级 Billing API

仅修改 Play Console 中的商品价格,通常不需要先升级 Billing API。不过,继续使用旧版接口会遇到一些实际问题:

  • 可能无法使用新的订阅模型和价格确认流程;
  • 旧接口的数据结构与当前 Billing Library 不同;
  • Google Play 会持续调整 Billing Library 的支持范围和发布要求;
  • 后续提交应用更新时,旧版本可能不再符合 Play Console 的要求。

可以分两步处理:

  1. 先在 Play Console 中配置目标价格和现有用户的迁移策略;
  2. 将应用升级到当前受支持的 Google Play Billing Library,并改为动态查询订阅价格。

新版 Billing Library 通常通过 queryProductDetailsAsync() 查询订阅信息,例如:

val product = QueryProductDetailsParams.Product.newBuilder()
    .setProductId("annual_subscription")
    .setProductType(BillingClient.ProductType.SUBS)
    .build()

val params = QueryProductDetailsParams.newBuilder()
    .setProductList(listOf(product))
    .build()

billingClient.queryProductDetailsAsync(params) { billingResult, queryResult ->
    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
        val productDetails = queryResult.productDetailsList.firstOrNull()
        val pricingPhase = productDetails
            ?.subscriptionOfferDetails
            ?.firstOrNull()
            ?.pricingPhases
            ?.pricingPhaseList
            ?.firstOrNull()

        val formattedPrice = pricingPhase?.formattedPrice
        if (formattedPrice != null) {
            priceTextView.text = formattedPrice
        }
    }
}

真实项目中可能有多个基础方案、优惠和计费阶段,不能一律直接取第一个 subscriptionOfferDetails。应根据 basePlanId、offerId、资格条件以及购买时使用的 offerToken,选择正确的报价。

注意事项

  • 在 Play Console 改价,不会自动更新应用中写死的价格文案。
  • 新用户和现有订阅者的价格可能在一段时间内不同。
  • 涨价和降价的处理规则可能不同。
  • 用户是否需要确认,不能只看 Billing API 版本,还要考虑地区、迁移方式和 Google Play 当前政策。
  • 不要通过自定义支付接口修改 Google Play 订阅的续费金额。
  • 改价后,应使用测试账号验证商品查询、购买页面、续订状态和服务端订单处理。
  • 如果服务端会校验订阅,不要只根据价格判断订阅是否有效。还应校验购买令牌、产品 ID、订阅状态和有效期。

备注:内容仅供参考。