uniapp 移动端 APP 支付方案(一)

4 阅读9分钟

支付模块说明

本文档描述 src/modules/pay 与收银台、UTS 插件的实际行为,便于团队内分享或复制到博客/文档站。路径均以本仓库为准。
文档路径: docs/payment-module.md

目录


1. 概述

本模块采用策略模式PaymentManager 单例按运行端注册 IPayStrategy,统一入口 pay();与 uni.requestPayment 相关的逻辑集中在 NativePayStrategy 子类中;APP 端还存在拉起小程序支付宝深链(连连)、**企业网银(仅拉配置)**等非单一 requestPayment 路径。

设计要点:

  • 业务接口失败时由 HTTP 层统一 Toast,同时将 errorCode 透传到 PaymentResult,供收银台等页面做跳转/刷新。
  • 支持开发者彩蛋中的假支付(不拉真实 submit-pay、不调 SDK 的独立线路)。
  • 订单维度支持单笔与合并支付orderNoList: string[])。

2. 能力矩阵

运行端微信支付支付宝支付企业网银说明
微信小程序 (MP-WEIXIN)uni.requestPaymentpayInfo-✅ 仅拉 submit-pay 配置,页面展示复制链接策略在 PaymentManager.initStrategies 中注册
APP (APP-PLUS / APP-HARMONY)✅ 拉起微信小程序支付✅ 默认拉起支付宝小程序payChannel === LL_PAY 时走 HTTPS payUrlalipays:// 深链✅ 同左微信固定 AppWxMiniProgramPay;支付宝按渠道在 AppAliMiniProgramPayAppAlipayScanPay 间切换
支付宝小程序 (MP-ALIPAY)-⚠️⚠️getAppType() 会返回 ALI_MINI,但当前 initStrategies 未注册对应策略;若需支持需在 PaymentManager 中补充并引入 NativePayStrategy 实现
H5🚫🚫🚫getAppType() 返回 null,不初始化策略

说明: native-pay.ts 中仍保留 AppWxNativePay / AppAlipayNativePayuni.requestPayment + payUrl)等类,但当前 PaymentManager 未注册,APP 实际走的是小程序拉起与连连深链方案。


3. 架构与目录

3.1 文件结构

src/modules/pay/
├── index.ts                 # PaymentManager 单例、懒初始化、策略注册、resolvePayStrategy
├── types.ts                 # PayPlatform / PayPlatformEnum / PAY_CHANNEL / 错误码常量 / PaymentParams / PaymentResult
├── pay-strategy.ts          # PayStrategy 基类:getPaymentConfig、wrapUniPayment、假支付、handleError
└── strategies/
    ├── native-pay.ts        # NativePayStrategy;WxMiniProgramPay;(另有未注册的 APP 原生支付类)
    ├── app-mini-program-pay.ts   # AppWxMiniProgramPay、AppAliMiniProgramPay(拉起小程序)
    ├── app-alipay-scan-pay.ts    # AppAlipayScanPay(连连 payUrl + alipays 深链)
    └── enterprise-bank-pay.ts    # EnterpriseBankPayStrategy(不调 SDK)

src/hooks/usePayment.ts      # 页面侧:loading、pay、checkIsPayable、availablePlatforms

src/pages-sub/pages/order/cashier/index.vue   # 收银台 UI、轮询、企业网银、路由与来源处理

src/uni_modules/app-miniprogram-launcher/     # UTS:APP 端拉起微信/支付宝小程序
src/uni_modules/harmony-native-kit/           # UTS:鸿蒙 openOuterUrl(外链 / scheme)

3.2 继承与分工(简化)

IPayStrategy
  └── PayStrategy(抽象:buildPaymentConfigRequest、getPaymentConfig、假支付、wrapUniPayment)
        ├── NativePayStrategy(模板:getConfig → buildUniPaymentOptions → requestPayment)
        │     └── WxMiniProgramPay
        ├── AppWxMiniProgramPay / AppAliMiniProgramPay(launchMiniProgram)
        ├── AppAlipayScanPay(openAlipaySchemeUrl)
        └── EnterpriseBankPayStrategy(仅返回 paymentConfig)

3.3 分层调用

页面(收银台 / 订单列表…)
  → usePayment.pay / checkIsPayable
  → paymentManager.pay / isPayable
  → 具体 IPayStrategy
  → API:submit-pay、is-payable、query payment result 等

4. 核心流程

4.1 原生小程序支付(微信)

WxMiniProgramPay.pay()

  1. 若开启假支付 → fakeSubmitPayment,直接成功。
  2. 否则 submitPayRequest,取 model.payInfo,组装 uni.requestPaymentprovider: 'wxpay'timeStamp / nonceStr / package / signType / paySign)。

4.2 APP 微信支付

AppWxMiniProgramPaysubmit-pay 得到 payUrl 作为小程序 path,调用 launchMiniProgram({ type: 'wechat', userName, appId, path, miniProgramType })。成功时返回 { success: true, errorCode: 'APP_LAUNCH_SUCCESS', paymentConfig }由收银台在 onShow 后轮询支付结果

iOS APP-PLUS: 使用项目内 launch-miniprogram(plus.share);Android / 鸿蒙: 使用 app-miniprogram-launcher UTS 插件。

4.3 APP 支付宝支付

  • 通联等渠道(非连连): AppAliMiniProgramPay,将 payUrl 编码进支付宝小程序 path(含 thirdPartSchema 回跳等),launchMiniProgram({ type: 'alipay', alipayAppId, path })。成功码同为 APP_LAUNCH_SUCCESS,收银台同样可轮询。
  • 连连 LL_PAY AppAlipayScanPay,将 payUrl(须为 http(s))拼为 alipays://platformapi/startapp?saId=10000007&qrcode= + URL,再调起支付宝客户端。
    • APP-PLUS: plus.runtime.openURL(错误码 -3 视为未安装支付宝)。
    • APP-HARMONY: openOuterUrl(schemeUrl)harmony-native-kit)。

4.4 企业网银

EnterpriseBankPayStrategy 只请求 submit-pay,返回 { success: true, errorCode: 'ENTERPRISE_BANK_SUCCESS', paymentConfig }。收银台根据 expireTime 计算倒计时,展示 payUrl 供用户复制到 PC 浏览器;到期可再次 handlePayment 刷新配置。

4.5 假支付

PayStrategy.runFakePaymentIfEnabled:读取开发者选项 fakePayment,走 fakeSubmitPayment,不调用真实 submit-pay 的完整调款链路(与真实支付配置拉取分离)。


5. usePayment 与页面职责

文件: src/hooks/usePayment.ts

5.1 usePayment(options?)

说明
options.onSuccess / onError / onFinally支付结束回调;pay() 内根据 result.success 分发
返回 loadingpay() 执行期间为 true
返回 availablePlatformspaymentManager.getAvailablePlatforms(),与当前包编译平台有关
返回 isPlatformAvailable(platform)是否已注册该 PayPlatform
返回 pay(params)转调 paymentManager.pay
返回 checkIsPayable(params)见下

5.2 checkIsPayable(跳转收银台前)

参数类型 CheckIsPayableParams(与历史文档差异:使用 orderNoList,不是单个 orderNo):

字段说明
orderNoList订单号数组(必填)
amount金额(必填)
closeCurrentPage默认 false;确认订单页建议 true,用 redirectTo 进收银台
source来源标识,会带到收银台 URL:order-list / order-detail / confirm-order
platform可选;传入则收银台默认勾选对应支付方式
onOrderStatusChangederrorCode 属于「订单状态变更」类时,延迟约 1.5s 回调(用于刷新列表/详情)
onNeedRedirecterrorCode 属于「需跳转订单列表」类时,延迟约 1.5s 回调

逻辑: 调用 paymentManager.isPayable({ orderNoList })(即 getIsPayable 接口)。succeed === true 则拼接
/pages-sub/pages/order/cashier/index?orderNoList=...&amount=...&source=...&platform=...navigateTo / redirectTo

5.3 pay(params)PaymentParams

(定义见 types.ts

  • platform: PayPlatform'wxpay' | 'alipay' | 'enterprise-bank'
  • orderNoList: string[]
  • amount?: number
  • payChannel?: PayChannel | string收银台从 getBuyerCashierpayChannel 传入,供 APP 解析支付宝策略)

6. 收银台页面 cashier/index.vue

6.1 路由参数

参数说明
orderNoList逗号分隔;页面内 split(',') 得到数组(合并支付为多笔)
amount应付总额
source来源;影响返回与成功后的导航
platform可选;可为后端支付方式编码 100/110/120PayPlatform 枚举值,解析后仅展示该支付方式

6.2 支付方式列表

  • 优先使用 getBuyerCashier 返回的 payMethodList,映射 PayMethodMap100→微信,110→支付宝,120→企业网银)。
  • 微信小程序端仅展示微信 + 企业网银(即使后端返回支付宝也会过滤掉)。
  • APP / 鸿蒙:后端列表为空时回退为 availablePlatforms(微信、支付宝、企业网银由 PaymentManager 注册决定)。

6.3 确认支付 handlePayment

清除轮询定时器后调用 pay({ platform, orderNoList, amount, payChannel: cashierInfo?.payChannel })

6.4 成功回调分支(onSuccess

情况行为
errorCodeAPP_LAUNCH_SUCCESS写入 paymentConfigshouldPollOnShow = true,用户从支付宝/微信返回后在 onShow每 2 秒轮询,最多 30 秒;成功则 payResultSuccessRedirect
errorCodeENTERPRISE_BANK_SUCCESS写入 paymentConfig 并计算 expireDurationMs,展示复制地址 UI,不展示底部确认支付按钮
其他成功navigateToPayResult({ status: 'success' })

轮询使用 getPaymentResultSafepayStatus130 成功、140 失败、170 关闭等(见页面内常量)。

6.5 失败回调(onError

  • errorCode:调用 handlePayErrorRedirect,将 REDIRECT_TO_ORDER_LIST_CODESORDER_STATUS_CHANGED_CODES 合并判断,命中则约 3s 后跳转订单列表。
  • errorCode:视为用户取消或网络等 → navigateToPayResult({ status: 'error' })
  • 微信小程序 + source === 'app-share' + 用户取消(USER_CANCELwx.exitMiniProgram() 回到 APP。

6.6 其他交互

  • 导航栏返回: source === 'app-share' 时同样 exitMiniProgram
  • 微信场景值 1036: App 打开小程序收银台等场景;页面会执行 handleAppLaunchWechatCashier(改标题、默认选微信等,与产品配置联动)。

7. 业务错误码与表现层处理

定义位置:src/modules/pay/types.ts

7.1 ORDER_STATUS_CHANGED_CODES(订单状态变更 → 宜刷新)

含例如:BU-APP-013BU-APP-021BU-APP-022(具体以源码为准)。

  • checkIsPayable 中:触发 onOrderStatusChanged(延迟 ~1.5s)。
  • 收银台 handlePayErrorRedirect 中:与下列组合判断,延迟 ~3s 跳转订单列表。

7.2 REDIRECT_TO_ORDER_LIST_CODES(宜回列表)

含例如:BU-APP-016BU-APP-027BU-APP-018BU-APP-019BU-APP-020BU-APP-028BU-APP-029 等(不包含上一节的变更码,但收银台会把两类合并用于跳转)。

  • checkIsPayable 中:触发 onNeedRedirect(延迟 ~1.5s)。

7.3 用户取消

PaymentErrorCodes.USER_CANCELwrapUniPaymenterrMsgcancel 时写入,便于小程序 app-share 场景关闭小程序。


8. 支付渠道 payChannel 与 APP 策略解析

types.tsPAY_CHANNEL

  • ALLINPAY:通联收银宝
  • ALLIN_PAY_YST:通联云商通
  • LL_PAY:连连支付

PaymentManager.resolvePayStrategy(APP):

  • 微信: 始终 AppWxMiniProgramPay
  • 支付宝: params.payChannel === PAY_CHANNEL.LL_PAYAppAlipayScanPay;否则 → AppAliMiniProgramPay

小程序跳转的 userName / appId / miniProgramType / 支付宝 pagePath 等由 app-mini-launch-config(支付模块侧配置)按 payChannel 区分,此处不展开。


9. 原生插件与鸿蒙

9.1 app-miniprogram-launcher

  • 作用: 在 Android / iOS / HarmonyOS 上统一调用 launchMiniProgram(options) 打开微信或支付宝小程序。
  • Harmony: 支持微信不支持支付宝小程序(插件 README 明确说明)。
  • 调用约定: 策略内使用 await Promise.resolve(launchMiniProgram(...)),兼容同步与异步返回值。
  • 更完整的配置说明、错误码、manifest 示例:src/uni_modules/app-miniprogram-launcher/readme.md

9.2 harmony-native-kit

  • 作用: openOuterUrl(url: string): Promise<void>,鸿蒙侧用系统能力打开外链;支付里用于打开 alipays://... 深链。
  • 类型: src/uni_modules/harmony-native-kit/index.d.ts

10. 扩展与维护

10.1 新增一种 APP 支付宝形态

resolvePayStrategy 增加 payChannel 分支,并实现新的 IPayStrategy(或复用 PayStrategy / NativePayStrategy)。

10.2 恢复 APP uni.requestPayment 原生微信/支付宝

PaymentManager.initStrategiesAppType.APP 分支中,将 PayPlatform.WECHAT / ALIPAY 改为 new AppWxNativePay() / new AppAlipayNativePay()(需确认后端 payUrl 与客户端 manifest 能力一致)。

10.3 支持支付宝小程序包

AppType.ALI_MINI 增加 #ifdef MP-ALIPAY 分支,注册 NativePayStrategy 子类(参考 WxMiniProgramPay 实现支付宝 provider: 'alipay'orderInfo)。

10.4 新增支付方式枚举

types.ts 增加 PayPlatform / PayPlatformEnum / PayMethodMap / 名称图标颜色,并在对应端的 initStrategies 注册策略。


11. 常见问题

Q:为什么 APP 不直接用 uni.requestPayment
A:当前产品策略是拉起小程序或连连深链;仓库中仍保留原生类便于切换。

Q:合并支付如何传参?
A:全程使用 orderNoList;路由里用逗号拼接多个订单号。

Q:REDIRECT_TO_ORDER_LIST_CODES 是否包含订单状态变更码?
A:类型定义上互不包含;收银台错误跳转时会把两类合并判断。checkIsPayable 则分别触发 onNeedRedirectonOrderStatusChanged

Q:假支付如何开?
A:开发者彩蛋页 fakePayment 开关;开启后走 fakeSubmitPayment,不调真实调起。

Q:鸿蒙上支付宝小程序?
A:isSupportLaunch('alipay') 为 false,当前应依赖连连深链或其它非支付宝小程序路径。


12. 相关文件索引

用途路径
支付管理器src/modules/pay/index.ts
类型与常量src/modules/pay/types.ts
页面 Hooksrc/hooks/usePayment.ts
收银台src/pages-sub/pages/order/cashier/index.vue
支付 APIsrc/api/pay/
小程序拉起插件src/uni_modules/app-miniprogram-launcher/
鸿蒙外链src/uni_modules/harmony-native-kit/

更新记录(摘要)

  • 当前版本(文档同步代码): APP 微信/支付宝以拉起小程序为主,连连支付宝走 AppAlipayScanPay;微信小程序支持企业网银;PaymentParams 使用 orderNoListPayPlatformEnum100/110/120