更新记录

1.1.0(2026-09-12)

  • 订阅全场景补全:
    • 新增 launchBillingFlow 第 4 可选参数 subscriptionUpdate:订阅升级/降级/换套餐(SubscriptionUpdateParams,支持 5 种折算模式,向后兼容)
    • 商品详情新增 offers 字段:订阅商品多优惠方案(offerId/offerToken/price),可自由选择试用/折扣方案
  • 更新文档与示例

平台兼容性

uni-app(4.0)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - - - 6.0 - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

mm-google-billing

Google Play 应用内购买(In-App Billing)UTS 插件(自研,基于 Google Play Billing Library 9.1.0)。

适用场景:出海 App(Google Play 上架)需要接入 Google 内购、且希望自行掌控实现细节、支持离线打包时,使用本插件。 已通过真机 + 离线打包(AAB)全链路验证:查询商品 → 拉起支付面板 → 付款回调 → 消耗 / 确认。 生产环境实例:已在 Google Play 上架的小说阅读类 App 中稳定运行,支持多地区购买。


平台支持

项目 支持
应用框架 uni-app(Vue3,Android App)
Android 版本 Android 6.0(API 23)及以上
打包方式 云打包 / 离线打包 / 自定义调试基座
iOS / Web / 小程序 不支持

特别注意:本插件为 API 插件(在 script 中调用),不是组件插件(不能用于 template 嵌入)。


为什么需要本插件(作者踩坑经验,望后来者少走弯路)

Play 后台警告:混淆度仅 3%

本插件的诞生源于 Google Play 上架内购 App 时的一系列实际痛点,以下每条都是作者真金白银踩过的坑:

  1. 云打包无法使用指定版本的 Google Play Billing:DCloud 云打包对 Billing 版本支持受限,无法按你的项目要求锁定版本(如 v8/v9 的官方 API)。本插件在 config.json 中直接声明仓储依赖 Billing Library 9.1.0,版本完全由你掌控。

  2. 云打包混淆度极低(约 3%)且不可配置:云打包默认只做轻度混淆,不支持自定义 R8 / proguard 规则。而 Google Play 上架对构建配置有一堆硬性要求,光靠云打包满足不了。

  3. Google Play 上架硬性要求,必须离线打包才能根治

  • 16 KB 内存分页大小支持(需 NDK r28+,或排除旧版 so + zipalign -P 16 对齐);

  • 排除无用原生库(如广告 SDK 的 so),否则触发 "应用可能在 16 KB 设备上异常终止" 的审核错误;

  • SoLoader 0.10.4+targetSdk 36fragment 依赖版本大屏适配等审核项,都需要自定义构建配置逐一满足。

    这些只能通过 离线打包(本地 Gradle + 自定义 R8 / packagingOptions/abiFilters) 根治。

  1. 结论:要上架 Google Play 且不想被审核问题反复打回、不想 "每次打包都提心吊胆",请购买源码授权版,配合离线打包,按你自己的签名、混淆规则和 ABI 配置构建 —— 这也是作者自己(已上架应用)在用的方式。

功能一览

  • 一次性商品(inapp):查询、购买、消耗(consume)

  • 订阅(subs)全场景

    • 查询订阅商品(含多优惠方案 offers:试用 / 折扣)

    • 发起订阅购买(可选 offerToken 指定优惠方案)

    • 订阅确认(acknowledge,订阅 3 天内必须确认)

    • 订阅状态查询(isAutoRenewing /isAcknowledged)

    • 补单 / 恢复(queryPurchases)

    • 订阅换档(升级 / 降级 / 换套餐,SubscriptionUpdateParams,5 种折算模式)

  • 服务端验单:purchaseToken 透传,配合后端 Google Play Developer API 验单


安装

  1. 将本目录(uni_modules/mm-google-billing)放入项目 uni_modules 目录下。

  2. manifest.json → App 模块权限 中勾选 / 添加权限:

\\\<uses-permission android:name="com.android.vending.BILLING"/>
  1. 使用与 Play Console 一致的包名和签名,制作自定义调试基座或打包。

快速开始

import {

    connect,

    disconnect,

    isReady,

    queryProductDetails,

    launchBillingFlow,

    queryPurchases,

    acknowledgePurchase,

    consumePurchase,

    onPurchasedUpdated,

    offPurchasedUpdated

} from "@/uni\\_modules/mm-google-billing"

// ① 页面加载:注册购买结果监听 + 连接

onPurchasedUpdated((res) => {

    console.log("购买结果 responseCode=", res.responseCode, res.debugMessage)

    if (res.responseCode === 0 && res.purchases && res.purchases.length > 0) {

        const purchase = res.purchases\\\[0]

        // ② 发送 purchaseToken 到服务端验单(Google Play Developer API)

        //    验单通过后:幂等发放权益,再 consume / acknowledge

        consumePurchase(purchase.purchaseToken, (r) => {

            console.log("消耗结果", r.code, r.msg)

        })

    } else if (res.responseCode === 1) {

        console.log("用户取消购买")

    } else {

        console.log("购买失败", res.responseCode, res.debugMessage)

    }

})

connect((res) => {

    console.log("Billing 连接结果", res.code, res.msg)

    if (res.code === 0) {

        // ③ 查询商品(productIds 用逗号分隔的字符串!)

        queryProductDetails("hk\\_gg001,hk\\_gg002,hk\\_gg003", "inapp", (res2) => {

            console.log("商品查询结果", res2.code, res2.products)

        })

        // 查询订阅商品(含多优惠方案)

        queryProductDetails("sub\\_month,sub\\_year", "subs", (res2) => {

            console.log("订阅商品", res2.products)

            // 每个订阅商品带 offers 数组,可查看试用/折扣方案

            const sub = res2.products\\\[0]

            console.log("优惠方案", sub.offers)

        })

    }

})

// ④ 发起购买(success 仅代表支付面板已拉起)

launchBillingFlow("hk\\_gg001", "", (res) => {

    console.log("拉起结果", res.code, res.msg)

})

// ⑤ 订阅换档:把已有订阅 sub\\_month 升级到 sub\\_year(立即生效,按时段按比例折算)

//    先 queryPurchases("subs") 拿到原订阅的 purchaseToken

launchBillingFlow("sub\\_year", "", (res) => {

    console.log("换档拉起结果", res.code, res.msg)

}, {

    oldPurchaseToken: "原订阅的purchaseToken",

    prorationMode: 1   // 1=按时段按比例(默认) 2=立即并按比例收费 3=立即不折算 4=续订时生效 5=立即全价

})

// ⑥ 页面卸载:移除监听 + 断开连接

// onUnload(() => { offPurchasedUpdated(); disconnect() })

API 说明

API 说明
connect(callback) 连接 Google Play Billing 服务,成功(code=0)后才可查询 / 购买
disconnect() 断开连接并清理商品缓存
isReady() 是否已连接
queryProductDetails(productIds, productType, callback) 查询商品详情并缓存。productIds逗号分隔字符串(如 "hk_gg001,hk_gg002");productTypeinapp / subs
launchBillingFlow(productId, offerToken, callback, subscriptionUpdate?) 拉起购买界面。offerToken 可传空字符串("")表示标准商品;订阅换档传第 4 参数 subscriptionUpdate;结果由 onPurchasedUpdated 返回
queryPurchases(productType, callback) 查询当前未消耗 / 未确认的购买(用于补单、恢复权益、取订阅 purchaseToken)
acknowledgePurchase(purchaseToken, callback) 确认购买(非消耗型一次性商品、订阅)
consumePurchase(purchaseToken, callback) 消耗购买(可重复购买的消耗型商品,如金币)
onPurchasedUpdated(callback) 注册购买结果监听(发起购买前必须先注册)
offPurchasedUpdated() 移除购买结果监听

类型说明

结果对象 GoogleBillingResult

字段 类型 说明
code number 0 = 成功,其他为失败(本地错误码)
msg string 描述信息
billingResponseCode number? Google Billing 响应码(本地错误时为 null)
debugMessage string? Google Play 诊断信息

商品 GoogleBillingProduct

字段 类型 说明
productId string 商品 ID
productType string inapp / subs
title string 标题
price string 本地化价格文本(展示用)
offerToken string 默认方案的 offerToken(可能为空)
offers GoogleBillingOffer[] 订阅多优惠方案(试用 / 折扣);一次性商品为空数组

订阅优惠方案 GoogleBillingOffer

字段 类型 说明
offerId string offer 标识(可能为空)
offerToken string 发起购买时透传(选中该方案必填)
price string 本地化价格文本

订阅换档参数 GoogleBillingSubscriptionUpdateOptions

字段 类型 说明
oldPurchaseToken string 原订阅的 purchaseToken(从 queryPurchases("subs") 获取,须未过期)
prorationMode number? 折算模式:1 = 按时段按比例立即生效(默认)2 = 立即生效并收取按比例差价 3 = 立即生效不折算 4 = 延迟到续订时生效 5 = 立即生效收取全价

购买事件 GoogleBillingEvent(onPurchasedUpdated 回调)

字段 类型 说明
responseCode number 0=OK;1=USER_CANCELED;其余见 BillingResponseCode
debugMessage string 诊断信息
purchases GoogleBillingPurchase[]? 购买记录(取消 / 失败时为 null)

购买记录 GoogleBillingPurchase

字段 类型 说明
purchaseToken string 服务端验单的唯一键
products string[] 本次购买关联的商品 ID
purchaseState string purchased / pending / unspecified
orderId string 订单号
originalJson string 原始 JSON(仅诊断,不能替代服务端验证)
signature string 签名(仅诊断,不能替代服务端验证)
isAcknowledged boolean 是否已确认
isAutoRenewing boolean 是否自动续订
isSuspended boolean 是否被暂停

业务流程(重要)

onPurchasedUpdated(注册监听)

→ connect(连接)

→ queryProductDetails(查询商品)

→ launchBillingFlow(拉起支付面板)

→ onPurchasedUpdated(收到最终购买结果)

→ 发送 purchaseToken 到服务端验单(Google Play Developer API)

→ 验单通过后幂等发放权益

→ consumePurchase / acknowledgePurchase(消耗或确认)

→ queryPurchases(补单:启动/后台恢复时调用)

关键约束

  1. launchBillingFlow 的 success 只表示支付面板已拉起,不代表支付完成;最终结果必须等 onPurchasedUpdated

  2. purchaseState == "pending" 的订单不能发放权益(如用户未完成付款 / 等待授权),需等状态变为 purchased 后再处理。

  3. 生产环境必须服务端验单:把 purchaseToken 发给你的后端,后端调用 Google Play Developer API(purchases.products.get / purchases.subscriptions.get)验证后幂等发放权益,再 consume/acknowledge。不要信任客户端返回的 originalJson/signature。

  4. 补单:应用启动和从后台恢复时调用 queryPurchases,处理上次未完成的购买(防漏发权益)。

  5. 订阅:确认使用 acknowledgePurchase(不能 consume);一次性可重复购买商品用 consumePurchase

  6. 订阅换档:oldPurchaseToken 必须来自 queryPurchases("subs") 且订阅未过期;折算模式按业务选择(默认 1 最常用)。

  7. 订阅取消:Google 规则由用户在 Play 商店管理,App 不提供取消 API(本插件遵循该规则)。


授权与打包方式(付费版)

本插件为付费 UTS 插件,分两档授权(官方规则):

授权 价格 能否看到源码 打包方式
普通授权版 ¥99 不能(云端加密编译) 仅云端传统打包(HBuilderX 云打包 / 自定义基座,最低 HBuilderX 3.7.2+)
源码授权版 ¥499 完整源码 云打包 + 离线打包均可用(含 utssdk/app-android 下 kt 混编源码)

重要

  • 两种授权均绑定唯一的 appid + 包名,更换任一需重新购买授权。

  • 试用插件:仅可用于本地运行或打包自定义基座,不能用于正式发布

  • 需要离线打包(本地 Gradle 构建 AAB)的开发者,请购买源码授权版

  • 本插件已在生产环境(Google Play 上架应用)以离线打包方式稳定运行。


常见问题

1. 查询商品报 code=3 / Billing Unavailable

原因:Google Play 内购有地区限制

  • 商品 / 账号限区时,受限区 Play 账号 + 受限区 IP 会返回 code=3(Billing Unavailable)

  • 排查顺序:① 确认 Play 账号国家 / 地区(Play 商店 → 头像 → 设置 → 账号和设备偏好)② 确认网络节点地区(需整机代理,Play 商店也走代理)③ 才怀疑代码。

2. 真机拉起支付面板失败 / 找不到对应商品

  • 确认测试账号已加入 Play 测试轨道(内部测试 / 封闭测试 / 开放测试),且通过 Play 商店安装(不要 adb 直装签名不一致的包)。

  • 确认商品已在 Play Console 创建并激活,ID 与代码一致(区分大小写)。

3. offerToken 什么时候用

  • 一次性标准商品:传 "" 即可;

  • 订阅商品:若想选择指定优惠方案(试用 / 折扣),从 queryProductDetails 结果的 offers 数组取对应 offerToken 传入。

4. 回调不触发

  • 确认调用了 onPurchasedUpdated 注册监听(且发起购买前已注册);

  • HBuilderX 4.25+ 回调默认单次触发,本插件已用 @UTSJS.keepAlive 保证持续触发,无需额外处理。


变更记录

changelog.md


发布到插件市场(作者须知)

  • 插件 ID:mm-google-billing(格式:作者 ID - 插件英文名称,作者 ID 至少 2 位字符,不能包含 DCloud/uni 关键字)。

  • 提交:在 HBuilderX 中右键插件目录 → 提交发布到插件市场;插件包不含 unpackagenode_modules.git 等目录。

  • 付费销售配置在 package.jsondcloudext.sale(参考文档:https://uniapp.dcloud.net.cn/plugin/publish.html )。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

com.android.vending.BILLING

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

Google Play Billing 会采集购买相关信息,参考 https://play.google.com/about/play-terms/

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。