更新记录
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 嵌入)。
为什么需要本插件(作者踩坑经验,望后来者少走弯路)
本插件的诞生源于 Google Play 上架内购 App 时的一系列实际痛点,以下每条都是作者真金白银踩过的坑:
-
云打包无法使用指定版本的 Google Play Billing:DCloud 云打包对 Billing 版本支持受限,无法按你的项目要求锁定版本(如 v8/v9 的官方 API)。本插件在
config.json中直接声明仓储依赖 Billing Library 9.1.0,版本完全由你掌控。 -
云打包混淆度极低(约 3%)且不可配置:云打包默认只做轻度混淆,不支持自定义 R8 / proguard 规则。而 Google Play 上架对构建配置有一堆硬性要求,光靠云打包满足不了。
-
Google Play 上架硬性要求,必须离线打包才能根治:
-
16 KB 内存分页大小支持(需 NDK r28+,或排除旧版 so +
zipalign -P 16对齐); -
排除无用原生库(如广告 SDK 的 so),否则触发 "应用可能在 16 KB 设备上异常终止" 的审核错误;
-
SoLoader 0.10.4+、targetSdk 36、fragment 依赖版本、大屏适配等审核项,都需要自定义构建配置逐一满足。
这些只能通过 离线打包(本地 Gradle + 自定义 R8 / packagingOptions/abiFilters) 根治。
- 结论:要上架 Google Play 且不想被审核问题反复打回、不想 "每次打包都提心吊胆",请购买源码授权版,配合离线打包,按你自己的签名、混淆规则和 ABI 配置构建 —— 这也是作者自己(已上架应用)在用的方式。
功能一览
-
一次性商品(inapp):查询、购买、消耗(consume)
-
订阅(subs)全场景:
-
查询订阅商品(含多优惠方案 offers:试用 / 折扣)
-
发起订阅购买(可选 offerToken 指定优惠方案)
-
订阅确认(acknowledge,订阅 3 天内必须确认)
-
订阅状态查询(isAutoRenewing /isAcknowledged)
-
补单 / 恢复(queryPurchases)
-
订阅换档(升级 / 降级 / 换套餐,SubscriptionUpdateParams,5 种折算模式)
-
-
服务端验单:purchaseToken 透传,配合后端 Google Play Developer API 验单
安装
-
将本目录(
uni_modules/mm-google-billing)放入项目uni_modules目录下。 -
在
manifest.json→ App 模块权限 中勾选 / 添加权限:
\\\<uses-permission android:name="com.android.vending.BILLING"/>
- 使用与 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");productType 为 inapp / 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(补单:启动/后台恢复时调用)
关键约束:
-
launchBillingFlow的 success 只表示支付面板已拉起,不代表支付完成;最终结果必须等onPurchasedUpdated。 -
purchaseState == "pending"的订单不能发放权益(如用户未完成付款 / 等待授权),需等状态变为purchased后再处理。 -
生产环境必须服务端验单:把
purchaseToken发给你的后端,后端调用 Google Play Developer API(purchases.products.get/purchases.subscriptions.get)验证后幂等发放权益,再 consume/acknowledge。不要信任客户端返回的 originalJson/signature。 -
补单:应用启动和从后台恢复时调用
queryPurchases,处理上次未完成的购买(防漏发权益)。 -
订阅:确认使用
acknowledgePurchase(不能 consume);一次性可重复购买商品用consumePurchase。 -
订阅换档:
oldPurchaseToken必须来自queryPurchases("subs")且订阅未过期;折算模式按业务选择(默认 1 最常用)。 -
订阅取消: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 中右键插件目录 → 提交发布到插件市场;插件包不含
unpackage、node_modules、.git等目录。 -
付费销售配置在
package.json的dcloudext.sale(参考文档:https://uniapp.dcloud.net.cn/plugin/publish.html )。

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 0
赞赏 0
下载 12592761
赞赏 1949
赞赏
京公网安备:11010802035340号