鸿蒙支付宝支付成功后未回调客户端
结论
支付成功但客户端没有收到结果,通常不代表交易失败,更可能是“支付宝返回应用”这条链路没有处理好。建议重点检查以下三项:
- 发起支付的
UIAbility是否正确接收了返回的Want,特别是应用已经运行时触发的onNewWant()。 - 支付回调、Promise 或事件监听是否在返回前被销毁、覆盖或重复注册。
module.json5中用于唤起应用的 URI、包名和签名等配置,是否与支付宝开放平台及 SDK 配置一致。
客户端回调只能用来更新页面状态。订单是否支付成功,最终应由服务端根据支付宝异步通知或主动查询结果确认。
为什么支付成功却没有客户端回调
支付宝收银台完成付款后,交易处理和应用唤起是两条相对独立的链路:
- 交易已经完成时,支付宝内部日志会显示支付成功。
- 如果返回链路失败,应用可能没有被唤起,也可能已经唤起,但返回参数没有传给 SDK。
- 应用已经运行时,系统通常不会再次执行
onCreate(),而是将新的Want交给onNewWant()。 - 页面、组件或回调对象提前销毁,也可能出现 SDK 已经返回结果,但业务代码没有收到通知的情况。
所以,SDK 内部出现支付成功日志,不等于业务层回调已经执行。
排查步骤
1. 确认应用是否被支付宝重新唤起
分别在 UIAbility 的 onCreate()、onNewWant() 和 onForeground() 中记录日志:
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
console.info('[PayDebug] EntryAbility.onCreate');
console.info(`[PayDebug] want.uri=${want.uri ?? ''}`);
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
console.info('[PayDebug] EntryAbility.onNewWant');
console.info(`[PayDebug] want.uri=${want.uri ?? ''}`);
}
onForeground(): void {
console.info('[PayDebug] EntryAbility.onForeground');
}
}
测试时需要覆盖这些场景:
- 应用留在前台时发起支付;
- 应用进入后台后完成支付;
- 应用进程被系统回收后完成支付;
- 已安装和未安装支付宝客户端。
如果支付后没有出现任何生命周期日志,先检查应用跳转 URI、包名、签名和 module.json5 配置。如果 onNewWant() 已经执行,但业务回调没有执行,再检查返回参数是否传给了支付宝 SDK。
2. 在 onNewWant() 中处理返回参数
应用已经运行时,支付返回信息通常会通过新的 Want 送达,因此不能只在 onCreate() 中初始化或解析。
不同版本的支付宝鸿蒙 SDK 可能使用不同的返回处理 API,具体应以当前接入版本的官方文档为准。代码结构可以统一成下面这样:
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
this.handlePayReturn(want);
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
this.handlePayReturn(want);
}
private handlePayReturn(want: Want): void {
console.info(`[PayDebug] receive pay return: ${want.uri ?? ''}`);
// 在这里调用当前支付宝 SDK 提供的返回参数处理接口。
// 不要自行猜测或修改支付宝返回参数。
}
}
如果 SDK 文档要求将 Want、URI 或回调参数传给指定接口,应在两个入口中调用同一套处理逻辑。
3. 检查支付调用的异步处理
如果 SDK 的支付接口返回 Promise,需要同时处理成功结果和异常,避免异常被静默忽略:
async function startPay(orderInfo: string): Promise<void> {
try {
// pay() 的导入方式和参数以实际使用的支付宝 SDK 为准。
const result = await alipay.pay(orderInfo);
console.info(`[PayDebug] pay result=${JSON.stringify(result)}`);
handleClientPayResult(result);
} catch (error) {
console.error(`[PayDebug] pay failed: ${JSON.stringify(error)}`);
showPayPendingAndQueryOrder();
}
}
不要在调用支付接口后立即销毁页面,也不要忽略返回的 Promise:
// 不推荐:调用结果没有被等待,也没有异常处理
alipay.pay(orderInfo);
router.back();
如果使用事件监听,还要确认监听器没有在页面的 aboutToDisappear()、onPageHide() 等生命周期中过早注销。
4. 核对应用唤起配置
检查 module.json5 中目标 UIAbility 的 skills 配置。URI 的 scheme、host、path 等字段必须与实际回跳地址一致。
以下配置仅作示意,具体值不能直接照用:
{
"abilities": [
{
"name": "EntryAbility",
"exported": true,
"skills": [
{
"actions": [
"ohos.want.action.viewData"
],
"entities": [
"entity.system.browsable"
],
"uris": [
{
"scheme": "your-app-scheme",
"host": "pay-result"
}
]
}
]
}
]
}
还需要检查:
- 调试包和正式包是否使用了不同的包名或签名;
- 支付宝开放平台配置是否对应当前应用;
- 回跳 URI 的大小写、路径和特殊字符是否完全一致;
- 目标
UIAbility是否允许外部唤起; - 是否有多个
UIAbility同时匹配同一个 URI,导致返回信息进入错误页面。
5. 确认回调对象没有失效
支付期间,用户会暂时离开当前应用,原页面可能被销毁或重新创建。因此,不要只将回调保存在页面组件的临时变量中。
可以将订单状态暂存在应用级状态中,等应用恢复后再查询:
interface PendingPayOrder {
orderNo: string;
startedAt: number;
}
let pendingPayOrder: PendingPayOrder | undefined;
function rememberPayOrder(orderNo: string): void {
pendingPayOrder = {
orderNo,
startedAt: Date.now()
};
}
async function resumePendingPayment(): Promise<void> {
if (!pendingPayOrder) {
return;
}
// 请求业务服务端查询订单状态。
await queryOrderStatus(pendingPayOrder.orderNo);
}
推荐的兜底处理
客户端恢复到前台后,如果在合理时间内仍未收到支付回调,应显示“支付结果确认中”,并向业务服务端查询订单状态,不要直接提示支付失败:
async function confirmPayment(orderNo: string): Promise<void> {
const order = await queryOrderStatus(orderNo);
switch (order.status) {
case 'PAID':
showPaySuccess();
break;
case 'CLOSED':
showPayFailed();
break;
default:
showPayPending();
break;
}
}
服务端需要校验支付宝异步通知的签名、商户订单号、金额、商户身份和交易状态,同时保证通知处理具有幂等性。
注意事项
- 不要仅根据客户端返回字段将订单标记为已支付。
- 不要把支付宝 SDK 日志中的“支付成功”视为业务服务端已经确认到账。
- 不要在日志中完整输出订单字符串、签名、用户标识或支付凭证。
- 如果问题只出现在混淆后的正式包中,应检查支付宝 SDK 相关类是否需要配置保留规则。
- 如果
onNewWant()已经收到返回信息,但传给 SDK 后仍然没有业务回调,需要记录 SDK 版本、HarmonyOS 版本、设备型号、应用前后台状态和脱敏后的Want信息,再向支付宝技术支持核对该版本的接入要求。
备注:内容仅供参考。
