更新记录

1.0.0(2026-09-04)

银联 APP 综合支付


平台兼容性

uni-app(3.91)

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

uni-app x(3.91)

Chrome Safari Android iOS 鸿蒙 微信小程序

lxs-unionpay-app · 莉先生银联 APP 综合支付 UTS 插件

莉先生银联 APP 综合支付(银联商务 UMS 移动支付 V3.1.8) 的 uni-app UTS 原生插件封装,覆盖 Android / iOS / 鸿蒙(HarmonyOS) 三端。

封装基于官方 SDK 原生接口:

  • Android:com.chinaums.pppay.unify.UnifyPayPlugin
  • iOS:UMSPPPayUnifyPayPlugin(UMSPosPayOnly)
  • 鸿蒙:UMSPayPlugin(qmf_ppplugin_oh_har)

目录结构

lxs-unionpay-app/
├── package.json
├── README.md
├── example/pages/index.vue        # 调用示例
└── utssdk/
    ├── index.uts                  # 对外类型 + 默认实现
    ├── android.uts                # Android 桥接(Kotlin)
    ├── ios.uts                    # iOS 桥接(Swift)
    ├── ohos.uts                   # 鸿蒙桥接(ArkTS)
    ├── android/libs/
    │   ├── qmf-ppplugin-android-3.1.8.aar
    │   ├── UPPayAssistEx.jar       # 云闪付
    │   └── jniLibs/<abi>/libentryexpro.so
    ├── ios/UMSPosPayOnly.framework/   # .a + 头文件 + Info.plist
    └── ohos/libs/qmf_ppplugin_oh_har_3.1.8.har

使用方式

将整个 lxs-unionpay-app 目录放入你的 uni-app 工程的 uni_modules/ 下,然后按工程类型引用。

⚠️ 普通 uni-app 与 uni-app x 的调用方式不同,别混用。 裸模块 import 只在 uni-app x 下可用;普通 uni-app 用 uni.requireUTSPlugin()。 判断依据:package.json 里是 @dcloudio/uni-app-plus(普通)还是 @dcloudio/uni-app-x

普通 uni-app(vue3,绝大多数工程)

// 字符串必须原样写死字面量,编译器靠它把插件打进基座,不能提取成常量
const unionpay = uni.requireUTSPlugin('lxs-unionpay-app')

// 1) 普通渠道(微信/支付宝/小程序等)
const res = await unionpay.pay({
  channel: 'wechat',                 // wechat | alipay | wechatMini | alipayMini | aliSdk
  appPayRequest: '<后台下单返回的 appPayRequest JSON 字符串>'
})
console.log(res.resultCode, res.resultInfo)

// 2) 云闪付
const res2 = await unionpay.cloudPay({ tn: '<后台返回的 tn>', serverMode: '00' })

uni-app x

import { pay, cloudPay } from 'lxs-unionpay-app'

const res = await pay({ channel: 'wechat', appPayRequest: '<...>' })
const res2 = await cloudPay({ tn: '<...>', serverMode: '00' })

💡 无论哪种方式,集成 UTS 插件后都必须重新制作一次自定义调试基座, 否则原生代码不在基座里,运行时会拿不到插件。

参数 说明
channel wechat 微信APP / alipay 支付宝直连 / wechatMini 微信小程序 / alipayMini 支付宝小程序 / aliSdk 支付宝间连原生 / unionpay 云闪付
appPayRequest 商户后台下单后应答中的 appPayRequest 字段(JSON 字符串,原样透传
tn 云闪付下单报文中 appPayRequest 内的 tn
serverMode 云闪付接入模式,00 正式 / 01 测试(默认 00

⚠️ resultCode === '0000' 仅表示 SDK 成功发起支付,最终是否支付成功必须以商户后台的异步通知或查单接口为准,切勿以客户端返回作为发货依据。


各端必须完成的宿主集成

Android

  1. UnifyPayPlugin 的微信结果回调依赖 WXEntryActivity:在 App 包名对应路径下建立 wxapi/WXEntryActivity.java 并在 AndroidManifest.xml 配置 android:exported="true"android:launchMode="singleTask"android:taskAffinity="应用包名"
  2. 云闪付(关键,必须接)UPPayAssistEx.startPay 的支付结果通过宿主 Activity.onActivityResult 返回,UTS 无法自动拦截,必须手动桥接,否则前端 cloudPay() 的 Promise 永远 pending、拿不到结果。 在 uni-app 业务工程的 App-Android(离线 / 自定义基座)中,找到主 Activity(继承 IOUniActivity 的类,通常叫 PandoraEntry),在其 onActivityResult 里调用插件导出的 onCloudPayResult

    import android.content.Intent;
    // 包名规则:插件 id(lxs-unionpay-app)转下划线 → lxs_unionpay_app + 文件名 android + "Kt"
    import uts.sdk.plugins.lxs_unionpay_app.androidKt;
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       super.onActivityResult(requestCode, resultCode, data);
       // 把云闪付结果转交 UTS 插件,插件据此 resolve cloudPay() 的 Promise
       androidKt.onCloudPayResult(requestCode, resultCode, data);
    }

    ⚠️ 若 import 报包名错误,先编译一次,到 unpackage/.../uts/sdk/plugins/lxs_unionpay_app/ 确认实际类名;或用反射兜底(见 example/native/CloudPayAndroidActivity.java)。 完整可复制模板:example/native/CloudPayAndroidActivity.java

  3. 云闪付需 libentryexpro.so(已在 jniLibs 内置全架构)。

iOS

  1. 集成微信 SDKUMSPosPayOnly 头文件 import <WXApi.h>,需在 iOS 工程链接 WechatOpenSDK(libWeChatSDK),并在 AppDelegate 中调用:
    [UMSPPPayUnifyPayPlugin registerApp:@"微信AppId" universalLink:@"你的UniversalLink"];

    并在 openURL / continueUserActivity 中调用对应的 handleOpenURL: / handleOpenUniversalLink:

  2. 支付宝小程序 / 间连支付宝 / 云闪付回调需按官方文档在 AppDelegate 转发 openURL
  3. Info.plist 配置 CFBundleURLTypes(URL Scheme),插件会自动读取第一个 Scheme 用于 aliSafePay / 云闪付。
  4. 云闪付 iOS 端结果通过 callbackBlock 自动回到 cloudPay() 的 Promise,宿主只需把 openURL / Universal Link 转发给 UMSPPPayUnifyPayPlugin(见 example/native/CloudPayIOSAppDelegate.m):
    - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
     sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
       [UMSPPPayUnifyPayPlugin handleOpenURL:url];
       return YES;
    }

鸿蒙(HarmonyOS)

  1. EntryAbility 中按官方 demo 处理回调:
    // 云闪付
    if (want?.uri?.includes('uppayresult')) {
     UMSPayPlugin.getInstance(ctx).handleUMSPayResult(UMSPayChannel.UnionPay, want)
    }
    // 支付宝小程序 / 微信小程序
    if (want?.uri?.includes('qmfpppay://backfromalipay')) {
     UMSPayPlugin.getInstance(ctx).handleUMSPayResult(UMSPayChannel.AliMini, want)
    }
    UMSPayPlugin.getInstance(ctx).handleUMSPayResult(UMSPayChannel.WechatMini, want)
  2. 微信小程序需 registerOnWXRespCallback / unregisterOnWXRespCallback(见官方 demo Index.ets)。
  3. qmf_ppplugin_oh_har.har 已放在 utssdk/app-harmony/libs/
  4. 云闪付结果回调模板见 example/native/CloudPayHarmonyEntryAbility.ets(在 EntryAbilityonCreate / onNewWant 里处理 uppayresult URI)。

已知待你确认的点(按平台编译时可能需要微调)

  • iOS 方法名:UTS 调用 ObjC 用「选择器拼接」命名(如 payWithPayChannelPayDatacallbackBlock)。若编译报找不到方法,可改写为 Swift 风格 payWithPayChannel(_:payData:_:)
  • iOS 获取 UIViewControllertopViewController()keyWindow.rootViewController 遍历,必要时按你工程的实际窗口结构微调。
  • Android 渠道常量值:直接引用 UnifyPayRequest.CHANNEL_* 静态字段,无需手填数值;若 SDK 版本升级导致字段名变化请同步。
  • UTS 全局对象名UTSAndroid / UTSOhos 为 UTS 标准全局对象;个别 UTS 版本 API 命名若有差异,以你本机 HBuilderX 版本为准。

故障排查:自定义调试基座里「检测不到插件」

症状:制作自定义调试基座后,getPluginStatus() 报「插件方法缺失 / 基座未包含该插件」, 或 android_debug.apk 里搜不到 libentryexpro.so

1. 先验证基座里到底有没有(最硬的判据)

# 有 so / aar / jar → 插件进去了;一条都没有 → 没进去
unzip -l unpackage/debug/android_debug.apk | grep -iE "entryexpro|chinaums|unionpay|UPPay"

2. 先分清你用的是 uni-app 还是 uni-app x

这是最容易踩的坑,两种工程的 UTS 插件调用方式完全不同。

普通 uni-app(vue3 + @dcloudio/uni-app-plus uni-app x(@dcloudio/uni-app-x
调用方式 uni.requireUTSPlugin('插件id') import { xxx } from '插件id'
平台条件编译 APP-PLUS / APP-PLUS-NVUE / APP-NVUE APP-ANDROID / APP-IOS / APP-HARMONY
UTS 文件后缀 业务代码用 .js / .vue .uts / .uvue

判定方法:看 package.json 的依赖是 @dcloudio/uni-app-plus 还是 @dcloudio/uni-app-x

3. 普通 uni-app 下的正确写法

// 字符串字面量必须原样写死,不能提取成常量(编译器只扫描字面量)
const plugin = uni.requireUTSPlugin('lxs-unionpay-app')
await plugin.cloudPay({ tn, serverMode: '00' })

requireUTSPlugin 有两个作用:

  • 运行时:返回 utssdk/<平台>/index.uts 导出的对象(pay / cloudPay / onCloudPayResult
  • 编译期:uni-app / HBuilderX 在做自定义基座和云打包时,静态扫描这个字符串字面量, 命中就把插件的原生代码(aar / jar / so / framework / har)注册进原生工程

4. 已验证行不通的写法(别再试)

写法 结果
import { pay } from 'lxs-unionpay-app' 构建直接失败:[vite]: Rollup failed to resolve import "lxs-unionpay-app"(裸模块 id 是 uni-app x 专用)
import { pay } from '../uni_modules/.../utssdk/app-android/index.uts' 不报错,但只当普通 .uts 源文件处理,不注册插件、不合并 build.gradle、不拷贝 libs → 基座里没有 so
#ifdef APP-ANDROID 包裹 import 普通 uni-app 下条件恒假,import 整段被剔除,pay 变成未定义
vite.config.js 里给裸模块配 alias(按 UNI_PLATFORM 切平台目录) 走错方向;UNI_PLATFORM 真实取值是 app / app-android / ...,不是 app-plus,判断恒 false 会让 alias 对 App 平台也生效,把模块定死到 utssdk/index.uts(reject 实现)

DCloud 官方对 import 方式还有一条硬性要求:只能 import 到插件根目录, 不能指到 utssdk/ 内部的具体文件。

5. 改完必须做的清理

自定义基座有缓存,不清理会一直用旧的:

  1. 删除 unpackage/debug/unpackage/cache/(至少删掉 android_debug.apk
  2. HBuilderX:运行 → 运行到手机或模拟器 → 制作自定义调试基座
  3. 打完再用第 1 步的命令验证一遍

6. 还要看控制台

如果 utssdk/app-android/index.uts 编译成 Kotlin 时报错(例如 com.chinaums.pppay.unify.UnifyPayPlugin 无法解析),HBuilderX 会静默跳过该插件继续出包, 表现就是「基座里没有插件」。所以制作基座时务必把控制台日志看完,搜 uts / lxs_unionpay / error

隐私、权限声明

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

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

插件不采集任何数据

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

暂无用户评论。