更新记录
1.3.2(2026-08-04)
升级 Google Play Billing Library 至 9.1.0
1.2.0(2025-08-28)
初始化增加参数配置,优化插件代码,demo增加vue页面示例
1.1.1(2025-08-26)
删除无用的jar依赖
查看更多平台兼容性
uni-app(4.27)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| × | × | × | × | √ | √ | 6.0 | × | × |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | - | × | × |
uni-app x(4.27)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | 6.0 | × | × | × |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | √ | √ |
Google Play Billing UTS 插件
基于 Google Play Billing Library 9.1.0,支持 Android 端一次性商品和订阅,适用于 uni-app x。
- 仅支持 Android。
- 最低 Android API 23(Android 6.0),不支持 API 21/22。
- Google Play Billing 9 的新应用和更新截止期限为 2028 年 8 月 31 日,延期截止日期为 2028 年 11 月 1 日。
安全提示:支付成功后,应把
purchaseToken发送到可信服务端,通过 Google Play Developer API 验证购买并授予权益,再消耗或确认交易。不要仅根据客户端回调发放权益。
升级与兼容说明
- 新版插件始终使用 Billing 9.1.0,不会回退或调用旧版 Billing SDK 的订阅替换逻辑。
doPay和doPayAll使用同一套支付实现,参数及行为完全一致;保留两个方法名是为了兼容已有项目。doUpdateSubs只接受 Billing 9 商品级replacementMode:1–6,0无效。doAcknowledgePurchase推荐直接传purchaseToken。旧项目仍可传original + signature,插件会从original中提取purchaseToken,最终仍使用 Billing 9 API 确认交易。
非 UTS 版本插件:插件市场
相关文档
API 说明
doInit(params, callback)
初始化并连接 BillingClient。
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
enableAutoServiceReconnection |
boolean | 否 | true |
启用 Google Play 自动服务重连 |
enablePrepaidPlans |
boolean | 否 | false |
支持订阅预付方案的待处理交易 |
enableExternalOffer |
boolean | 否 | false |
启用外部优惠计划 |
enableAlternativeBillingOnly |
boolean | 否 | false |
启用仅限备选结算模式 |
enableUserChoiceBilling |
boolean | 否 | false |
启用用户选择结算方式 |
doRelease(callback)
结束 BillingClient 连接并释放插件持有的商品及支付回调数据。
getConnectionState(callback)
检查 BillingClient 是否已连接并可用。
doQuerySku(params, callback)
查询商品详情。方法名中的 Sku 为兼容已有项目而保留,底层使用 Billing 9 ProductDetails。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
inapp |
string[] | 否 | 一次性商品 ID 列表 |
subs |
string[] | 否 | 订阅商品 ID 列表 |
至少需要传入一个商品 ID。返回值中的 data 是成功获取的商品,unfetchedProducts 是未能获取的商品及状态码。
doPay(params, callback) / doPayAll(params, callback)
两个方法参数和行为一致。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
productId |
string | 是 | doQuerySku 返回的商品 ID |
offerToken |
string | 订阅必填 | 订阅优惠令牌;一次性商品选择指定购买选项或优惠时传入 |
accountId |
string | 否 | 混淆后的账号 ID,不要传明文用户信息 |
profileId |
string | 否 | 混淆后的资料 ID,不要传明文用户信息 |
isOfferPersonalized |
boolean | 否 | 是否为个性化价格,用于欧盟价格披露 |
doUpdateSubs(params, callback)
使用 Billing 9 SubscriptionProductReplacementParams 更新订阅。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
productId |
string | 是 | 新订阅商品 ID,调用前必须通过 doQuerySku 查询 |
offerToken |
string | 是* | 新订阅优惠令牌;replacementMode = 6 时不要传 |
oldPurchaseToken |
string | 是 | 当前订阅的购买令牌 |
oldProductId |
string | 否 | 当前订阅商品 ID;建议传入。仅单商品订阅可省略,插件会根据 oldPurchaseToken 自动查询 |
replacementMode |
number | 是 | Billing 9 商品级替换模式,只允许 1–6,不允许 0 |
accountId |
string | 否 | 混淆后的账号 ID |
profileId |
string | 否 | 混淆后的资料 ID |
isOfferPersonalized |
boolean | 否 | 是否为个性化价格 |
externalTransactionId |
string | 否 | 原订阅来自备选结算时的外部交易 ID |
replacementMode 取值:
| 值 | Billing 9 模式 | 说明 |
|---|---|---|
1 |
WITH_TIME_PRORATION |
立即替换,按剩余时间折算 |
2 |
CHARGE_PRORATED_PRICE |
立即替换并收取剩余周期差价 |
3 |
WITHOUT_PRORATION |
立即替换,下个续订日按新价格收费 |
4 |
CHARGE_FULL_PRICE |
立即替换并收取新方案全价 |
5 |
DEFERRED |
延后到旧方案到期时生效 |
6 |
KEEP_EXISTING |
保持现有方案;oldProductId 必须等于 productId,并且不要传 offerToken |
其他方法
doConsume({ purchaseToken }, callback):消耗一次性商品。doAcknowledgePurchase({ purchaseToken }, callback):确认非消耗型一次性商品或订阅;兼容{ original, signature }。doQueryPurchases({ productType, includeSuspendedSubscriptions? }, callback):查询当前拥有的商品。productType为inapp或subs;查询订阅时可传includeSuspendedSubscriptions: true。doShowInAppMessages({ inAppMessageCategoryId }, callback):显示 Google Play 应用内消息。
通用返回值
code:插件结果码,200表示插件调用成功。errorCode:Google Play BillingBillingResponseCode。subResponseCode:购买失败细分原因;0无细分原因、1余额不足、2用户不符合订阅优惠资格。data:接口返回的数据。unfetchedProducts:doQuerySku未能获取的商品列表及状态码。
引用插件
import {
doInit,
doRelease,
getConnectionState,
doQuerySku,
doPay,
doPayAll,
doUpdateSubs,
doConsume,
doAcknowledgePurchase,
doQueryPurchases,
doShowInAppMessages,
GtCommonResult,
} from "@/uni_modules/gt-google-pay"
uni-app x 示例
以下代码基于 uni-app x,完整用法请查看项目 Demo;uni-app 项目需要按自身类型系统调整。
const isInapp = ref<boolean>(true)
const payList = ref<UTSJSONObject[]>([])
const prdList = ref<UTSJSONObject[]>([])
/**
* 显示提示
*/
const showToast = (title : string) => {
uni.showToast({
title: title,
mask: true,
duration: 1500,
icon: 'none'
});
}
/**
* 初始化
*/
const handleInit = () => {
// 参考链接:https://developer.android.com/reference/com/android/billingclient/api/BillingClient.Builder
doInit({
enableAutoServiceReconnection:true, //自动服务重连,不传默认为true
enablePrepaidPlans:false, //是否支持订阅预付方案的待处理交易
enableExternalOffer:false , //启用外部优惠,不传默认为false
enableAlternativeBillingOnly:false, //仅使用备选结算,不传默认为false
enableUserChoiceBilling:false, //用户选择支付方式,适用于 EEA、印度、韩国等要求支持 UCB 的市场,不传默认为false
}, e => {
console.log("doInit: ", e);
if (e.code == 200) {
// 初始化成功
console.log('初始化成功');
showToast('初始化成功');
} else {
// 初始化失败
console.log('初始化失败');
showToast('初始化失败');
}
});
}
const handleRelease = () => {
doRelease((result : GtCommonResult) => {
console.log('释放连接:', result)
})
}
const handleGoodsTypeChange = (e : RadioGroupChangeEvent) => {
console.log("handleGoodsTypeChange: ", e);
isInapp.value = e.detail.value == 'true'
prdList.value = [] as UTSJSONObject[]
}
/**
* 查询商品
*/
const handleQuerySku = () => {
let params : UTSJSONObject;
if (isInapp.value) { //消耗商品
params = {
inapp: ["google_product_22", "google_product_21", "google_product_11",
"google_product_12", "google_product_15"
]
}
} else { //订阅商品
params = {
// subs: ["10000", "10001"],
subs: ["10000", "10001", "svip_month", "vip_month"],
}
}
doQuerySku(params, (result : GtCommonResult) => {
console.log('查询结果:', result);
showToast('查询结果:' + JSON.stringify(result));
if (result.code == 200 && result.data != null) {
// 查询成功
prdList.value = result.data as UTSJSONObject[];
// console.log('that.prdList : ', prdList.value);
// const list = JSON.parse<UTSJSONObject[]>(result.data['list'])
// const list = JSON.parse<UTSJSONObject[]>(JSON.stringify(result.data['list']))
} else {
console.log('查询失败');
}
});
}
/**
* 发起支付
* 支付参数为查询sku结果的某一项
*/
const handlePay = () => {
console.log('do pay function.');
// console.log("that.prdList: ", prdList.value)
if (prdList.value.length == 0 || prdList.value[0].productId == null) {
showToast('产品不能为空,不可支付');
return;
}
let payPrams = {
productId: prdList.value[0].productId,
accountId: "test-accountId-00000001", // 可选,用户Id
profileId: "test-profileId-00000001", // 可选,个人资料Id
isOfferPersonalized: false //欧盟个性化定价披露
}
// Billing 9:订阅商品必须传offerToken;一次性商品选择特定优惠时也要传offerToken
if (!isInapp.value) {
// payPrams.offerToken = "AQ2SJC/E1M9cIzCkpjba57hkz81a4vr9sGx7BKy+agizCT2IVOBCdMsYO3xiozVv01+0XYNhbKfZpAGUJkys"
const subscriptionOfferDetails = prdList.value[0].subscriptionOfferDetails as UTSJSONObject[]
if (subscriptionOfferDetails.length == 0 || subscriptionOfferDetails[0].offerToken == null) {
showToast('找不到offerToken');
return
}
payPrams.offerToken = subscriptionOfferDetails[0].offerToken;
}
console.log('payPrams: ', payPrams);
doPay(payPrams, result => {
console.log('支付结果:', result);
showToast('支付结果:' + JSON.stringify(result));
if (result.code == 200 && result.data != null) {
const payResult = result.data as UTSJSONObject[];
// 支付成功,可以确认交易,必须purchaseState才调用
if (payResult[0].purchaseState as Number == 1) {
console.log("支付成功,可以确认交易");
payList.value = payResult;
} else { // purchaseState==2
// 调用doQueryPurchases方法查询订单状态,purchaseState==1后才可以确认
console.log("支付成功,订单状态为等待中,暂不可确认交易");
}
} else {
// 支付失败
console.log('支付失败');
}
});
}
/**
* 发起支付
* 支付参数为查询sku结果的某一项
*/
const handlePayAll = () => {
console.log('do pay function.');
console.log("that.prdList: ", prdList.value)
if (prdList.value.length == 0 || prdList.value[0].productId == null) {
showToast('产品不能为空,不可支付');
return;
}
let payPrams = {
productId: prdList.value[0].productId,
accountId: "test-accountId-00000001", // 可选,用户Id
profileId: "test-profileId-00000001", // 可选,个人资料Id
isOfferPersonalized: false //欧盟个性化定价披露
}
// Billing 9:订阅商品必须传offerToken;一次性商品选择特定优惠时也要传offerToken
if (!isInapp.value) {
// payPrams.offerToken = "AQ2SJC/E1M9cIzCkpjba57hkz81a4vr9sGx7BKy+agizCT2IVOBCdMsYO3xiozVv01+0XYNhbKfZpAGUJkys"
const subscriptionOfferDetails = prdList.value[0].subscriptionOfferDetails as UTSJSONObject[]
if (subscriptionOfferDetails.length == 0 || subscriptionOfferDetails[0].offerToken == null) {
showToast('找不到offerToken');
return
}
payPrams.offerToken = subscriptionOfferDetails[0].offerToken;
}
console.log('payPrams: ', payPrams);
doPayAll(payPrams, result => {
console.log('支付结果:', result);
showToast('支付结果:' + JSON.stringify(result));
if (result.code == 200 && result.data != null) {
const payResult = result.data as UTSJSONObject[];
// 支付成功,可以确认交易,必须purchaseState才调用
if (payResult[0].purchaseState as Number == 1) {
console.log("支付成功,可以确认交易");
payList.value = payResult;
} else { // purchaseState==2
// 调用doQueryPurchases方法查询订单状态,purchaseState==1后才可以确认
console.log("支付成功,订单状态为等待中,暂不可确认交易");
}
} else {
// 支付失败
console.log('支付失败');
}
});
}
/**
* 确认交易,消耗品
*/
const handleConsume = () => {
console.log('do consume function.');
if (payList.value.length == 0 || (payList.value[0].purchaseToken ?? payList.value[0].token) == null) {
showToast('支付信息不能为空');
return;
}
if (payList.value[0].purchaseState != 1) {
showToast("订单状态未就绪")
return
}
doConsume({
purchaseToken: payList.value[0].purchaseToken ?? payList.value[0].token
}, result => {
console.log('Consume结果:', result);
showToast('Consume结果:' + JSON.stringify(result));
if (result.code == 200) {
console.log('Consume成功');
} else {
console.log('Consume失败');
}
});
}
/**
* 确认交易,非消耗品
*/
const handleAcknowledgePurchase = () => {
console.log('do pay function.');
if (payList.value.length == 0 || (payList.value[0].purchaseToken ?? payList.value[0].token) == null) {
showToast('支付信息不能为空');
return;
}
if (payList.value[0].purchaseState != 1) {
showToast("订单状态未就绪")
return
}
if (payList.value[0].acknowledged as boolean) {
showToast("该订单已确认交易过了")
return
}
// Billing 9 推荐直接使用 purchaseToken;授权商品前仍应先在服务端验签
doAcknowledgePurchase({
purchaseToken: payList.value[0].purchaseToken ?? payList.value[0].token
}, result => {
console.log('acknowledgePurchase结果:', result);
showToast('acknowledgePurchase结果:' + JSON.stringify(result));
if (result.code == 200) {
console.log('acknowledgePurchase成功');
} else {
console.log('acknowledgePurchase失败');
}
});
}
/**
* 查询购买交易
* 返回您在应用内购买的当前拥有的商品的购买详情。
* 仅返回有效订阅和未消费的一次性购买。
*
* acknowledged 字段是是否已确认交易 true false
* purchaseState 是订单状态 1--支付成功,可确认交易,2--等待中
*/
const handleQueryPurchases = () => {
console.log("do doQueryPurchases function.");
//参数inapp或subs
doQueryPurchases({
productType: isInapp.value ? "inapp" : "subs",
includeSuspendedSubscriptions: false //订阅传true时包含暂停状态
}, (result) => {
console.log("queryPurchases结果:", result);
showToast("queryPurchases结果:" + JSON.stringify(result));
if (result.data != null) {
// 支付成功后,如果没确认交易,doQueryPurchases查询到订单且订单purchaseState==1,再调用确认交易方法
payList.value = result.data as UTSJSONObject[]
}
});
}
/**
* 更新订阅,更新订阅后,也要确认交易才可以
*/
const handleUpdateSubs = () => {
console.log('do updateSubs function.');
if (isInapp.value) {
showToast("应用内商品不支持更新订阅")
return
}
if (prdList.value.length < 2 || prdList.value[1].productId == null || payList.value.length == 0) {
showToast('产品不能为空,不可支付');
return;
}
const oldProducts = payList.value[0].getArray<string>("products")
if (oldProducts == null || oldProducts.length == 0) {
showToast('找不到当前订阅商品ID');
return
}
const subscriptionOfferDetails = prdList.value[1].getArray<UTSJSONObject>("subscriptionOfferDetails")
if (subscriptionOfferDetails == null || subscriptionOfferDetails.length == 0 || subscriptionOfferDetails[0].offerToken == null) {
showToast('找不到offerToken');
return
}
// Billing 9 使用商品级 SubscriptionProductReplacementParams
let params = {
productId: prdList.value[1].productId,
offerToken: subscriptionOfferDetails[0].offerToken,
oldProductId: oldProducts[0],
// 要更改的订阅的PurchaseToken
oldPurchaseToken: payList.value[0].purchaseToken ?? payList.value[0].token,
replacementMode: 3, //WITHOUT_PRORATION;Billing 9只允许1-6,0无效
accountId: "test-accountId-00000001", // 可选,混淆后的用户Id
profileId: "test-profileId-00000001", // 可选,混淆后的资料Id
isOfferPersonalized: false, //欧盟个性化定价披露
externalTransactionId:"" //可选,外部交易Id
}
console.log('doUpdateSubs params: ', params);
doUpdateSubs(params, result => {
console.log('更新订阅结果:', result);
showToast('更新订阅结果:' + JSON.stringify(result));
if (result.code == 200 && result.data != null) {
// 支付成功
console.log('更新订阅成功');
payList.value = result.data as UTSJSONObject[];;
} else {
// 支付失败
console.log('更新订阅失败');
}
});
}
/**
* 显示应用内消息
*/
const handleShowInAppMessages = () => {
console.log("do doShowInAppMessages function.");
//参数inapp或subs
doShowInAppMessages({
inAppMessageCategoryId: 2, //0或2,详情参考谷歌文档
},
(result) => {
console.log("doShowInAppMessages结果:", result);
showToast("doShowInAppMessages结果:" + JSON.stringify(result));
if (result.code == 200 && result.data != null) {
const mResultData = result.data as UTSJSONObject
// responseCode为谷歌返回的结果码,详情参考谷歌文档
if (mResultData.responseCode == 0) {
// NO_ACTION_NEEDED
// The flow has finished and there is no action needed from developers.
} else if (mResultData.responseCode == 1) {
// SUBSCRIPTION_STATUS_UPDATED
}
}
}
);
}

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 110
赞赏 0
下载 12481572
赞赏 1937
赞赏
京公网安备:11010802035340号