PAYATHON 2026

Ionic 4 中 Alipay 插件无法打开支付页面

支付阿杰

结论

alipay.pay() 不能只接收支付金额。它接收的参数应当是服务端按照支付宝规则生成并签名的完整订单字符串 alipayOrder。

示例中的 alipayOrder 只是一个占位变量。如果变量未定义、内容为空、签名无效或订单参数不完整,插件可能一直停留在“正在打开 Alipay”,无法进入支付页面。

需要检查和修改的是订单生成流程,而不是 Promise 的写法:

  1. 由服务端创建并签名支付宝订单;
  2. 在服务端订单参数 total_amount 中写入总金额;
  3. 将服务端返回的完整订单字符串传给 this.alipay.pay();
  4. 使用真机测试,同时确认插件、平台配置和支付宝客户端均可正常工作。

为什么不能在前端直接传金额

下面的调用通常无法完成支付:

this.alipay.pay('10.00');

10.00 只是金额,不是支付宝可以执行的订单。支付宝 App 支付所需的订单中还要包含商户应用 ID、订单号、商品信息、回调地址、时间戳和签名等参数。

签名必须在可信的服务端完成。不要将支付宝应用私钥、商户密钥或签名逻辑放入 Ionic 应用,否则攻击者可以从安装包中提取密钥。

典型流程如下:

Ionic 应用
  → 请求业务服务端创建订单
  → 服务端生成订单号并设置 total_amount
  → 服务端使用私钥签名
  → 返回 alipayOrder 字符串
  → Ionic 调用 alipay.pay(alipayOrder)
  → 支付宝客户端处理付款
  → 服务端通过异步通知确认最终支付结果

Ionic 端的调用方式

Ionic 应用应先向自己的服务端请求支付订单,再将返回的订单字符串交给插件:

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Alipay } from '@ionic-native/alipay/ngx';

@Component({
  selector: 'app-payment',
  templateUrl: './payment.page.html'
})
export class PaymentPage {
  constructor(
    private http: HttpClient,
    private alipay: Alipay
  ) {}

  pay(): void {
    const request = {
      amount: '99.00',
      subject: '商品订单'
    };

    this.http
      .post<{ orderString: string }>('/api/payments/alipay/order', request)
      .subscribe({
        next: ({ orderString }) => {
          if (!orderString) {
            console.error('服务端未返回支付宝订单字符串');
            return;
          }

          this.alipay.pay(orderString)
            .then(result => {
              console.log('支付宝客户端返回结果:', result);
              // 此处只适合更新界面,最终支付状态应向服务端查询。
            })
            .catch(error => {
              console.error('调用支付宝失败:', error);
            });
        },
        error: error => {
          console.error('创建支付订单失败:', error);
        }
      });
  }
}

对应的按钮可以写成:

<ion-button expand="block" (click)="pay()">
  支付 ¥99.00
</ion-button>

实际项目中,不应由客户端单方面决定金额。更安全的做法是只传商品 ID、套餐 ID 或业务订单号,再由服务端根据数据库中的价格计算应付金额。

服务端需要生成什么

服务端创建支付宝 App 支付订单时,应按照当前使用的支付宝服务端 SDK 和接口要求设置业务参数。常见字段包括:

{
  "out_trade_no": "202608290001",
  "product_code": "QUICK_MSECURITY_PAY",
  "total_amount": "99.00",
  "subject": "商品订单"
}

各字段的含义如下:

  • out_trade_no:商户系统中唯一的订单号;
  • product_code:App 支付场景通常使用 QUICK_MSECURITY_PAY;
  • total_amount:订单总金额,通常是保留两位小数的字符串;
  • subject:订单标题。

这些只是业务参数的一部分。服务端还要按照当前支付宝开放平台和所用 SDK 的要求配置 app_id、签名算法、私钥、公钥及异步通知地址等信息,然后返回 SDK 生成的完整签名订单字符串。不能自行将 JSON 转为字符串后直接传给插件。

服务端响应可以设计为:

{
  "orderString": "app_id=...&biz_content=...&charset=utf-8&method=...&sign=..."
}

Ionic 端应原样传递该字符串,不要再次进行 URL 编码,也不要拼接或修改签名字段。

一直停留在“正在打开 Alipay”时的排查方法

1. 检查实际传入值

在调用插件前输出订单字符串:

console.log('alipayOrder:', orderString);

如果输出的是 undefined、null、空字符串或普通金额,问题出在订单生成或接口取值环节,不是支付插件本身。

2. 使用真机测试

Cordova/Ionic Native 类型的支付插件依赖原生能力,无法在普通浏览器或 ionic serve 中完成真实支付。应构建 Android 或 iOS 应用,并在真机上测试。

3. 确认依赖注入

使用 /ngx 入口时,通常还要在 Angular 模块的 providers 中注册插件:

import { Alipay } from '@ionic-native/alipay/ngx';

@NgModule({
  providers: [
    Alipay
  ]
})
export class AppModule {}

是否需要这样配置,取决于项目采用的 Angular/Ionic Native 结构和插件版本。缺少原生插件或依赖注入配置时,调用无法正常工作。

4. 检查原生插件是否已加入平台

只安装 TypeScript 包装器还不够。项目还必须安装对应的 Cordova 原生插件,并重新构建目标平台。

不同 Alipay 插件实现所使用的插件名称和安装命令可能不同,应以插件仓库中与当前版本匹配的说明为准。

5. 检查订单和签名

逐项确认以下内容:

  • app_id 是否属于当前支付宝开放平台应用;
  • 应用是否已经开通并正确配置 App 支付能力;
  • out_trade_no 是否唯一;
  • total_amount 格式是否正确;
  • 应用私钥是否与平台配置的公钥匹配;
  • 签名字符串在传输过程中是否被转义、截断或重复编码;
  • Android/iOS 的包名、应用签名或回跳配置是否符合所用插件和支付宝平台的要求。

支付成功不能只看客户端回调

this.alipay.pay() 返回成功,只能说明支付宝客户端返回了某个结果,不能将其作为服务端发货或记账的唯一依据。用户可能中断支付流程,客户端结果也可能丢失或被伪造。

完整的支付确认流程应当是:

  1. 服务端接收并验证支付宝异步通知;
  2. 校验签名、商户应用 ID、订单号和金额;
  3. 以幂等方式更新订单状态;
  4. Ionic 应用向服务端查询订单的最终状态。

总金额应由服务端写入 total_amount 并参与签名。前端只负责取得完整的 alipayOrder,再调用:

this.alipay.pay(alipayOrder);

只修改示例中的变量名,或者直接将金额传给插件,都无法完成支付宝付款。

备注:内容仅供参考。