PAYATHON 2026

鸿蒙应用如何吊起支付宝APP的扫一扫功能完成支付?

支付老李

结论

鸿蒙应用可以通过支付宝 URL Scheme 拉起支付宝,并把收款码中的 HTTPS 链接作为 qrcode 参数传入。支付宝会按照扫码结果处理该参数,用户确认后进入支付流程。

常见写法如下:

alipays://platformapi/startapp?saId=10000007&qrcode=<URL编码后的收款链接>

这种方式不会先打开摄像头扫描屏幕上的二维码,而是直接将二维码承载的内容交给支付宝。

URL Scheme 的兼容性可能因支付宝客户端和鸿蒙系统版本而异。正式商用前,应查阅支付宝开放平台的当前文档,并在实际设备上测试。标准商户支付应优先使用支付宝官方支付 SDK 或官方网页支付方案。

实现思路

假设收款码对应的原始链接是:

https://example.com/pay?orderNo=202609090001&amount=10.00

先对整个 HTTPS 链接进行 URL 编码,再将其拼接到支付宝 Scheme 中:

alipays://platformapi/startapp?saId=10000007&qrcode=https%3A%2F%2Fexample.com%2Fpay%3ForderNo%3D202609090001%26amount%3D10.00

参数含义如下:

  • saId=10000007 通常用于进入支付宝扫一扫相关页面。
  • qrcode 是二维码实际承载的内容。
  • encodeURIComponent() 可防止原链接中的 ?、&、= 等字符破坏 Scheme 的参数结构。

ArkTS 示例

下面的示例适用于基于 Stage 模型的 HarmonyOS ArkTS 应用。不同 API 版本的类型定义和行为可能略有差异,需要按照项目使用的 SDK 版本调整。

import { common, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

async function openAlipay(
  context: common.UIAbilityContext,
  paymentUrl: string
): Promise<void> {
  if (!paymentUrl.startsWith('https://')) {
    throw new Error('收款链接必须使用 HTTPS');
  }

  const encodedPaymentUrl = encodeURIComponent(paymentUrl);
  const alipayUrl =
    `alipays://platformapi/startapp?saId=10000007&qrcode=${encodedPaymentUrl}`;

  const want: Want = {
    action: 'ohos.want.action.viewData',
    uri: alipayUrl
  };

  try {
    await context.startAbility(want);
  } catch (error) {
    const err = error as BusinessError;
    console.error(`拉起支付宝失败,code=${err.code}, message=${err.message}`);

    // 可在这里提示用户安装或升级支付宝,
    // 也可以展示二维码,让用户使用其他设备扫码。
  }
}

在页面或组件中调用时,传入当前的 UIAbilityContext 和后端生成的收款链接:

const paymentUrl =
  'https://example.com/pay?orderNo=202609090001&amount=10.00';

await openAlipay(this.context, paymentUrl);

如果组件没有直接保存 UIAbilityContext,可以根据项目结构获取上下文,但不要随意把普通组件上下文强制转换成 UIAbilityContext。

只打开扫一扫页面

如果只需要让用户进入支付宝扫一扫,不需要自动处理当前链接,可以省略 qrcode:

const want: Want = {
  action: 'ohos.want.action.viewData',
  uri: 'alipays://platformapi/startapp?saId=10000007'
};

await context.startAbility(want);

这样会打开扫码界面,但支付宝不能自动扫描当前手机屏幕上显示的二维码。用户通常需要扫描另一台设备上的二维码,所以同机支付更适合传入 qrcode 参数。

支付结果不能只看页面返回

成功拉起支付宝并不代表支付成功。应用切回前台、页面完成跳转,或者用户点击了“支付”,都不能证明订单已经支付。

较为可靠的流程是:

  1. 鸿蒙应用向业务服务端申请创建订单。
  2. 服务端生成带有唯一订单号的支付链接。
  3. 应用对链接编码后,将其交给支付宝处理。
  4. 支付渠道异步通知业务服务端。
  5. 服务端验签并更新订单状态。
  6. 应用调用订单查询接口,获取最终支付结果。

示例:

type OrderStatus = 'PENDING' | 'PAID' | 'CLOSED' | 'FAILED';

async function queryOrderStatus(orderNo: string): Promise<OrderStatus> {
  const response = await fetch(
    `https://api.example.com/orders/${encodeURIComponent(orderNo)}/status`
  );

  if (!response.ok) {
    throw new Error(`查询订单失败:HTTP ${response.status}`);
  }

  const result = await response.json() as { status: OrderStatus };
  return result.status;
}

应用恢复到前台后,可以主动查询一次订单状态。如果支付仍在处理中,可在合理时间内进行有限次数的轮询,避免频繁请求。

注意事项

不要重复编码或漏编码

需要编码的是完整的收款链接:

const qrcode = encodeURIComponent(paymentUrl);

不要只手动替换其中几个字符,也不要对已经编码的链接重复调用 encodeURIComponent(),否则支付宝可能无法还原原始地址。

不要信任客户端传入的金额

金额、商户号、订单号和签名都应由服务端生成。客户端只能提交商品或订单标识,不应自行拼接可能被篡改的支付金额。

校验链接来源

如果支付链接来自接口响应,至少需要检查以下内容:

  • 链接必须使用 https://。
  • 域名必须在业务允许列表中。
  • 订单号必须与当前订单一致。
  • 不能使用用户输入的内容直接拼接链接。
  • 链接应设有有效期,并避免重复使用。

处理支付宝未安装的情况

如果系统无法处理 alipays:// Scheme,startAbility() 可能会失败。应用应捕获异常,并明确提示用户采取以下操作之一:

  • 安装或升级支付宝。
  • 改用浏览器支付。
  • 使用其他设备扫描展示的二维码。
  • 选择其他支付方式。

拉起失败后不要直接宣布支付失败,因为订单可能仍处于待支付状态。

Scheme 兼容性需要实机验证

alipays://platformapi/startapp 和 saId=10000007 是常见的支付宝客户端调用形式。不过,它们是否对当前 HarmonyOS 版本、支付宝版本和具体业务链接开放,仍需参考支付宝当前公开能力,并通过真机测试确认。

上线前至少需要覆盖以下情况:

  • 已安装或未安装支付宝。
  • 支付宝已登录或未登录。
  • 不同的支付宝客户端版本。
  • 用户取消支付。
  • 链接过期或订单已经关闭。
  • 应用被系统回收后重新进入。
  • 支付完成,但客户端没有正常返回。

如果支付宝开放平台为当前产品提供了正式的 HarmonyOS 支付接入方案,应优先采用官方方案,不宜长期依赖没有明确稳定性承诺的客户端 Scheme。

备注:内容仅供参考。