You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

应用内计费技术问询:订阅关联、跨端校验及签名验证等问题

关于应用内计费订阅的几个关键问题解答

作为刚接触应用内计费的开发者,你的这些疑问其实都是新手常会遇到的核心痛点,我来逐个帮你理清:

1. 无自有服务器下,订阅与应用账号关联的问题

首先明确:如果完全没有自有服务器,很难实现订阅权益与你的应用账号(而非Google账号)的稳定关联

Google Play的订阅记录本质是绑定在用户的Google账号上的。如果用户购买后没关联你的应用账号,换设备登录你的应用账号时,你的应用根本无从知晓这个应用账号对应的哪个Google账号买过订阅,自然不会自动授予高级权益——这种情况是完全正常的,因为两者没有绑定关系。

如果不想搭建复杂服务器,有个折中方案:

  • 在应用内引导用户完成「Google账号-应用账号」的绑定(比如登录应用账号后,让用户授权Google Play访问权限);
  • 每次应用启动时,用Google Play Billing Library的queryPurchasesAsync方法查询当前登录Google账号的订阅状态,同步到用户的应用账号本地存储;
    但这个方案有缺陷:本地存储容易被篡改,且如果用户换设备用同一个应用账号但登录了不同的Google账号,还是无法获取权益,必须重新绑定之前购买的Google账号。

2. 跨渠道(非iOS购买,iOS端享权益)的实现

这个需求必须依赖服务器,因为iOS和Android的计费系统完全独立,两端应用无法直接验证对方渠道的购买记录。

具体思路:

  • 搭建一个简单的后端服务,统一存储所有用户的购买记录(不管是Google Play、还是其他安卓渠道、甚至iOS的App Store);
  • 用户在任何渠道购买后,将购买凭证(比如Google的purchase token、苹果的receipt)发送到服务器,服务器验证凭证有效性后,标记该应用账号的权益状态;
  • iOS和安卓应用启动时,都向服务器请求当前应用账号的权益状态,根据返回结果开启高级功能。

3. & 4. 购买校验与签名信息验证的实现

首先纠正一个误区:完全不依赖Google服务器的校验是不可行也不安全的,你提到的tokenId、subscriptionId、purchaseId这些信息,最终还是需要和Google的服务器交互才能验证有效性。

对于新手来说,不建议自己手动处理OAuth token和签名验证,推荐两种简单方案:

方案一:客户端轻量校验(适合快速验证,但不安全)

用Google Play Billing Library提供的API直接在客户端查询订阅状态:

// 示例:Kotlin代码查询订阅
billingClient.queryPurchasesAsync(QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.SUBS).build()) { billingResult, purchases ->
    if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && !purchases.isNullOrEmpty()) {
        for (purchase in purchases) {
            // 获取订阅状态、过期时间
            val isAutoRenewing = purchase.isAutoRenewing
            val expiryTime = purchase.purchaseTime + purchase.subscriptionPeriodMillis
            // 这里可以根据这些信息判断是否授予权益
        }
    }
}

但客户端校验的问题是容易被逆向破解,恶意用户可以篡改本地数据绕过校验,所以只适合临时测试,不适合上线。

方案二:服务器端校验(推荐,安全可靠)

你提到的分析服务器如果是托管的、无法运行自定义服务的话,建议用无服务器函数(比如Firebase Functions、Vercel Functions),这些平台对新手友好,免费额度足够支撑小型应用:

  1. 在Google Cloud控制台创建服务账号,获取JSON密钥,用于调用Google Play Developer API;
  2. 写一个简单的云函数,接收客户端发来的purchaseTokensubscriptionId,调用Google Play的purchases.subscriptions.get接口验证:
// 示例:Node.js云函数验证订阅
const { google } = require('googleapis');
const playDeveloper = google.androidpublisher('v3');

exports.verifySubscription = async (req, res) => {
  const { packageName, subscriptionId, purchaseToken } = req.body;
  const auth = new google.auth.GoogleAuth({
    keyFile: 'service-account-key.json',
    scopes: ['https://www.googleapis.com/auth/androidpublisher'],
  });

  try {
    const response = await playDeveloper.purchases.subscriptions.get({
      auth,
      packageName,
      subscriptionId,
      token: purchaseToken,
    });
    const subscription = response.data;
    // 提取审批状态(比如subscription.status)、过期时间(subscription.expiryTimeMillis)
    res.status(200).json({
      isValid: subscription.status === 'ACTIVE',
      expiryTime: subscription.expiryTimeMillis,
    });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
};
  1. 客户端购买成功后,将purchaseToken发送到这个云函数,根据返回的结果更新用户权益。

最后:权益应该绑定Google账号还是应用账号?

强烈建议绑定你的应用账号,原因有两个:

  1. 用户更习惯使用自己注册的应用账号,而非依赖Google账号(比如有些用户可能有多个Google账号,容易混淆);
  2. 跨设备、跨平台(安卓转iOS)的权益同步必须依赖应用账号,绑定Google账号的话,换设备或换平台就无法延续权益,用户体验极差。

当然,绑定应用账号意味着你需要一个简单的后端来存储用户的权益状态,但现在的无服务器工具已经非常容易上手,新手也能快速搭建起来。

内容的提问来源于stack exchange,提问作者Augodao Aika

火山引擎 最新活动