更新记录

1.0.0(2026-08-19)

  • 首次发布,支持 uni-app Vue 3 与 uni-app x Android 项目。
  • 支持商品查询、购买、订单恢复、订单确认和商品消耗。
  • 基于 Google Play Billing Library 9.1.0,要求 Android 6.0+、HBuilderX 5.24+。

平台兼容性

uni-app(5.24)

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

uni-app x(5.24)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × × × ×

Google Play 应用内购

基于 Google Play Billing Library 9.1.0 的 Android 应用内购与订阅 UTS 插件,支持 uni-app Vue 3 和 uni-app x。

  • 插件版本:1.0.0
  • Android 最低版本:Android 6.0(API 23)
  • HBuilderX 兼容基线:5.24 及以上版本

本插件封装的是 Google Play Billing,不是 Google Pay Wallet,不适用于线下 支付、银行卡或 NFC 支付。

支持范围

项目 支持情况
uni-app Vue 3 App Android 支持
uni-app x App Android 支持
uni-app Vue 2 / nvue 不支持
iOS / HarmonyOS 不支持,调用时返回 9011002
Web / 小程序 / 快应用 不支持

使用前准备

在测试真实购买前,需要先完成 Google Play Console 配置:

  1. 在 Google Play Console 创建应用,应用包名必须与 Android 项目的包名一致。
  2. 创建并启用应用内商品或订阅,记录商品 ID。
  3. 上传使用正式签名的 APK 或 AAB 到内部测试或封闭测试轨道。
  4. 将测试 Google 账号加入许可测试人员,并在手机 Google Play 中登录同一账号。
  5. 通过 Google Play 测试链接安装应用,再进行购买测试。

侧载安装的调试包可以验证 BillingClient 创建、连接和查询接口,但通常不能完成 真实购买。商品查询为空时,应优先检查商品状态、测试账号、包名、签名和安装来源。

官方测试说明: https://developer.android.com/google/play/billing/test

安装与运行

  1. 从 DCloud 插件市场将 hans-google-pay 导入项目。
  2. Android 调试时生成并使用包含本插件的自定义基座。标准基座不包含 Google Play Billing 原生依赖。
  3. 正式发布时重新云打包 APK 或 AAB,确保本插件被编译进安装包。

插件会自动合并 com.android.vending.BILLING 权限,不需要向用户申请运行时 权限。

导入与类型

uni-app x 页面建议使用 lang="uts",并从插件根目录同时导入 API 与公开类型:

import {
  newBuilder,
  startConnection,
  endConnection,
  isReady,
  queryProductDetailsAsync,
  launchBillingFlow,
  queryPurchasesAsync,
  acknowledgePurchase,
  consumeAsync,
  BillingJsonOptions,
  BillingNewBuilderOptions,
  BillingStartConnectionOptions,
} from '@/uni_modules/hans-google-pay'

不要直接导入 utssdk/interface.uts。标准 uni-app Vue 3 页面使用 JavaScript 时, 只导入所需 API,不需要导入上述类型。

回调约定

所有 API 都接收一个 options 对象:

字段 类型 说明
paramsJson string JSON 字符串;无参数时传 '{}'
success function 调用成功,参数为 JSON 字符串。
fail function 调用失败,参数为 JSON 字符串。
complete function 可选;成功或失败后都会调用。

建议在回调中先解析 JSON:

success: (resJson: string): void => {
  const result = JSON.parse<UTSJSONObject>(resJson)
  console.log(result)
}

newBuilder 额外支持 purchasesUpdateduserChoiceBillingstartConnection 额外支持 disconnected

推荐调用顺序

  1. newBuilder:创建 BillingClient 并注册购买结果回调。
  2. startConnection:连接 Google Play 服务。
  3. queryProductDetailsAsync:查询并缓存商品详情。
  4. launchBillingFlow:使用已查询的商品拉起购买界面。
  5. purchasesUpdated 中处理订单状态和 purchaseToken
  6. 非消耗型商品和订阅调用 acknowledgePurchase;消耗型商品调用 consumeAsync
  7. 启动应用或恢复会话时调用 queryPurchasesAsync 核对有效订单。
  8. 页面或业务生命周期结束时调用 endConnection

必须先查询商品详情,再对同一 productId 调用 launchBillingFlow。插件会在 当前 BillingClient 生命周期内缓存查询结果。

创建和连接 BillingClient

const builderOptions: BillingNewBuilderOptions = {
  paramsJson: JSON.stringify({
    enablePendingPurchases: true,
    pendingPurchases: {
      oneTimeProducts: true,
      prepaidPlans: false,
    },
    enableAutoServiceReconnection: true,
  }),
  purchasesUpdated: (eventJson: string): void => {
    const event = JSON.parse<UTSJSONObject>(eventJson)
    console.log('购买结果', event)
  },
  success: (_resJson: string): void => {
    const connectionOptions: BillingStartConnectionOptions = {
      paramsJson: '{}',
      disconnected: (_eventJson: string): void => {
        console.warn('Google Play Billing 服务已断开')
      },
      success: (resJson: string): void => {
        console.log('连接成功', JSON.parse<UTSJSONObject>(resJson))
      },
      fail: (errJson: string): void => {
        console.error('连接失败', JSON.parse<UTSJSONObject>(errJson))
      },
    }
    startConnection(connectionOptions)
  },
  fail: (errJson: string): void => {
    console.error('创建失败', JSON.parse<UTSJSONObject>(errJson))
  },
}

newBuilder(builderOptions)

newBuilder.paramsJson 支持:

字段 说明
enablePendingPurchases 是否启用待处理订单,默认 true
pendingPurchases.oneTimeProducts 是否支持一次性商品待处理订单,默认 true
pendingPurchases.prepaidPlans 是否支持预付费订阅待处理订单,默认 false
enableAutoServiceReconnection 是否自动重连,建议设为 true
enableAlternativeBillingOnly 仅在账号和地区符合 Google Play 替代计费政策时启用。
enableBillingProgram 是否启用 Billing Program。
billingProgram Billing Program 原始整数值。
enableUserChoiceBilling 仅在符合用户选择计费政策时启用。

查询商品

一次性商品使用 inapp,订阅使用 subs

const queryOptions: BillingJsonOptions = {
  paramsJson: JSON.stringify({
    productType: 'inapp',
    productIds: [ 'coin_pack_100' ],
  }),
  success: (resJson: string): void => {
    console.log('商品详情', JSON.parse<UTSJSONObject>(resJson))
  },
  fail: (errJson: string): void => {
    console.error(JSON.parse<UTSJSONObject>(errJson))
  },
}

queryProductDetailsAsync(queryOptions)

订阅购买需要从 subscriptionOfferDetails 中选择对应的 offerToken。一次性 商品的新优惠模型也可能返回 offerToken,应使用商品查询结果中的实际值。

拉起购买

一次性商品:

const purchaseOptions: BillingJsonOptions = {
  paramsJson: JSON.stringify({
    productId: 'coin_pack_100',
    obfuscatedAccountId: 'hash-of-your-user-id',
  }),
  success: (resJson: string): void => {
    console.log('购买界面已拉起', JSON.parse<UTSJSONObject>(resJson))
  },
  fail: (errJson: string): void => {
    console.error('无法拉起购买界面', JSON.parse<UTSJSONObject>(errJson))
  },
}

launchBillingFlow(purchaseOptions)

订阅:

const subscriptionOptions: BillingJsonOptions = {
  paramsJson: JSON.stringify({
    productId: 'premium_monthly',
    offerToken: 'offer-token-from-product-details',
  }),
  success: (resJson: string): void => {
    console.log(JSON.parse<UTSJSONObject>(resJson))
  },
  fail: (errJson: string): void => {
    console.error(JSON.parse<UTSJSONObject>(errJson))
  },
}

launchBillingFlow(subscriptionOptions)

launchBillingFlow.success 只表示购买界面成功拉起。最终购买结果由 newBuilder.purchasesUpdated 返回。同一时间只能存在一个购买流程。

恢复、确认和消耗订单

查询当前有效订单:

const restoreOptions: BillingJsonOptions = {
  paramsJson: JSON.stringify({
    productType: 'inapp',
    includeSuspendedSubscriptions: false,
  }),
  success: (resJson: string): void => {
    console.log('有效订单', JSON.parse<UTSJSONObject>(resJson))
  },
  fail: (errJson: string): void => {
    console.error(JSON.parse<UTSJSONObject>(errJson))
  },
}

queryPurchasesAsync(restoreOptions)

确认非消耗型商品或订阅:

const acknowledgeOptions: BillingJsonOptions = {
  paramsJson: JSON.stringify({
    purchaseToken: 'purchase-token-from-purchasesUpdated',
  }),
  success: (resJson: string): void => {
    console.log('订单已确认', JSON.parse<UTSJSONObject>(resJson))
  },
  fail: (errJson: string): void => {
    console.error(JSON.parse<UTSJSONObject>(errJson))
  },
}

acknowledgePurchase(acknowledgeOptions)

消耗可重复购买的商品:

const consumeOptions: BillingJsonOptions = {
  paramsJson: JSON.stringify({
    purchaseToken: 'purchase-token-from-purchasesUpdated',
  }),
  success: (resJson: string): void => {
    console.log('商品已消耗', JSON.parse<UTSJSONObject>(resJson))
  },
  fail: (errJson: string): void => {
    console.error(JSON.parse<UTSJSONObject>(errJson))
  },
}

consumeAsync(consumeOptions)

API 参数速查

API paramsJson 字段
newBuilder 见“创建和连接 BillingClient”。
startConnection {}
endConnection {}。结束连接并清空商品缓存。
isReady {}。返回 ready
getConnectionState {}。返回 BillingClient 原始连接状态值。
isFeatureSupported feature:能力名称或 Billing Library 原始值。
queryProductDetailsAsync productTypeproductIds
queryPurchasesAsync productType,可选 includeSuspendedSubscriptions
launchBillingFlow 必填 productId;可选 offerTokenobfuscatedAccountIdobfuscatedProfileIdisOfferPersonalizedreplacementParamssubscriptionUpdateParams
acknowledgePurchase purchaseToken
consumeAsync purchaseToken
getBillingConfigAsync {}。返回 Google Play 国家或地区代码。
showInAppMessages 可选 categories 整数数组;不传时显示所有支持的类别。
launchExternalLink 按政策场景传 billingProgramlaunchModelinkTypelinkUri
isAlternativeBillingOnlyAvailableAsync {}
showAlternativeBillingOnlyInformationDialog {}
createAlternativeBillingOnlyReportingDetailsAsync {}
isBillingProgramAvailableAsync 必填 billingProgram 整数值。
createBillingProgramReportingDetailsAsync 必填 billingProgram 整数值。

replacementParams 支持 oldProductIdreplacementModesubscriptionUpdateParams 支持 oldPurchaseTokenoriginalExternalTransactionId

替代计费、外部链接、用户选择计费和 Billing Program API 受 Google Play 账号、地区与政策限制。不要仅因为 SDK 接口可用就直接在生产环境启用。

返回结果

billingResult 通常包含:

字段 说明
responseCode Google Play Billing 响应码;0 表示 OK。
debugMessage Google Play 返回的调试信息。
onPurchasesUpdatedSubResponseCode 购买失败的细分原因。

商品详情常用字段:

  • productIdproductTypetitlenamedescription
  • oneTimePurchaseOfferDetailsoneTimePurchaseOfferDetailsList
  • subscriptionOfferDetails,其中包含 basePlanIdofferIdofferTokenpricingPhases

购买记录常用字段:

  • purchaseTokenproductspurchaseStatepurchaseTimequantity
  • isAcknowledgedisAutoRenewingisSuspendedorderId
  • originalJsonsignature 仅用于校验,不应直接作为客户端授予权益的依据。

插件错误码

错误码 说明
9011001 paramsJson 格式错误或缺少必要参数。
9011002 当前平台不支持。
9011003 BillingClient 尚未创建、未连接或未查询到商品详情。
9011004 当前 Android Activity 不可用。
9011005 已有购买流程正在进行。
9011006 当前能力尚未实现。
9011099 原生层内部错误。

插件错误通过 errCodeerrMsg 返回;Google Play 服务错误通过 billingResult.responseCodedebugMessage 返回,两者需要分别处理。

生产环境注意事项

  1. 不要信任客户端自行上报的购买成功结果。将 purchaseToken 发送到业务服务端, 使用 Google Play Developer API 验证订单后再授予权益。
  2. 只有订单处于已购买状态时才授予权益;待处理订单完成前不要发货。
  3. 非消耗型商品和订阅需要确认,消耗型商品需要消耗。Google Play 要求在规定 时间内完成处理,否则订单可能被退款。
  4. obfuscatedAccountIdobfuscatedProfileId 应使用不可逆、稳定且不包含明文 个人信息的业务标识。
  5. 应同时处理 purchasesUpdatedqueryPurchasesAsync,避免应用重启、断网或 回调丢失导致漏单。

Google Play 官方安全建议: https://developer.android.com/google/play/billing/security

Google Play 购买生命周期: https://developer.android.com/google/play/billing/lifecycle/one-time

常见问题

商品查询成功但列表为空

检查商品是否已启用、productType 是否正确、测试账号是否已加入、包名和签名 是否与 Play Console 一致,以及应用是否通过测试轨道安装。未取得的商品会出现在 unfetchedProducts 中。

startConnection 返回非 0

检查手机是否安装并登录 Google Play、当前地区和账号是否支持 Billing,以及网络 是否能访问 Google Play 服务。具体原因以 debugMessage 为准。

标准基座中调用失败

标准基座不包含本插件的 Maven 依赖。请重新生成包含本插件的 Android 自定义基座, 并确认运行时选择了该基座。

页面提示 BillingClient 未就绪

先调用 newBuilder,再等待 startConnection.success,之后才能查询商品、恢复 订单或拉起购买。

隐私、权限声明

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

com.android.vending.BILLING:用于通过 Google Play 完成应用内商品与订阅购买。

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

插件本身不向插件作者服务器采集或上传用户数据;Google Play Billing Library 会与 Google Play 服务通信,以查询商品、处理购买和管理订单。

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

暂无用户评论。