更新记录

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 的订阅替换逻辑。
  • doPaydoPayAll 使用同一套支付实现,参数及行为完全一致;保留两个方法名是为了兼容已有项目。
  • doUpdateSubs 只接受 Billing 9 商品级 replacementMode1–60 无效。
  • 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):查询当前拥有的商品。productTypeinappsubs;查询订阅时可传 includeSuspendedSubscriptions: true
  • doShowInAppMessages({ inAppMessageCategoryId }, callback):显示 Google Play 应用内消息。

通用返回值

  • code:插件结果码,200 表示插件调用成功。
  • errorCode:Google Play Billing BillingResponseCode
  • subResponseCode:购买失败细分原因;0 无细分原因、1 余额不足、2 用户不符合订阅优惠资格。
  • data:接口返回的数据。
  • unfetchedProductsdoQuerySku 未能获取的商品列表及状态码。

引用插件

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
                }
            }
        }
    );
}

隐私、权限声明

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

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

插件支付功能使用Google SDK,参考其官方网站 https://policies.google.com/privacy

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