PAYATHON 2026

支付成功后如何重定向回 Cordova 应用?

支付老李

结论

支付完成后返回 Cordova 应用,通常有两种做法:

  1. 在 InAppBrowser 中监听支付网关是否跳转到指定的成功 URL。一旦识别到该地址,就关闭浏览器,并在应用内处理支付结果。
  2. 配置自定义 URL Scheme、Universal Link 或 App Link,让支付完成页通过深链接重新唤起应用。

如果整个支付流程都在 InAppBrowser 中完成,第一种做法更简单。如果支付网关会打开系统浏览器、银行应用或第三方支付应用,就需要使用深链接。

方案一:监听支付成功 URL

创建支付订单时,将支付网关的 return_url 设置为自己控制的 HTTPS 地址,例如:

https://example.com/payment/complete

打开支付页面后监听 loadstart 事件。当浏览器准备跳转到这个地址时,关闭 InAppBrowser,再由 Cordova 应用处理后续逻辑。

const paymentUrl = 'https://payment.example.com/checkout';
const successUrl = 'https://example.com/payment/complete';
const cancelUrl = 'https://example.com/payment/cancel';

const browser = cordova.InAppBrowser.open(
  paymentUrl,
  '_blank',
  'location=yes,clearcache=yes,clearsessioncache=yes'
);

browser.addEventListener('loadstart', function (event) {
  const url = event.url;

  if (url.startsWith(successUrl)) {
    browser.close();

    // 不要仅根据 URL 判断支付成功,应向服务端查询订单状态
    verifyPaymentStatus();
    return;
  }

  if (url.startsWith(cancelUrl)) {
    browser.close();
    showPaymentCancelled();
  }
});

browser.addEventListener('loaderror', function (event) {
  console.error('Payment page failed to load:', event);
});

browser.addEventListener('exit', function () {
  console.log('InAppBrowser closed');
});

async function verifyPaymentStatus() {
  try {
    const response = await fetch(
      'https://api.example.com/orders/ORDER_ID/status',
      {
        method: 'GET',
        headers: {
          Accept: 'application/json'
        }
      }
    );

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }

    const result = await response.json();

    if (result.status === 'paid') {
      showPaymentSuccess();
    } else if (result.status === 'pending') {
      showPaymentPending();
    } else {
      showPaymentFailed();
    }
  } catch (error) {
    console.error('Failed to verify payment status:', error);
    showPaymentPending();
  }
}

这里不需要让支付网关直接跳回某个 Cordova 页面。让它跳转到一个可识别的返回地址,应用拦截该地址后关闭 InAppBrowser 即可。

页面跳转可能触发 beforeload、loadstart 或其他事件,具体取决于插件版本、运行平台和支付网关的跳转方式。实际开发时,应根据当前版本的插件文档验证可用事件。

方案二:通过深链接唤起应用

如果支付流程离开了 InAppBrowser,例如转到系统浏览器、银行应用或第三方支付应用,loadstart 可能无法收到最后一次跳转。这时需要为应用配置深链接,例如:

myapp://payment/complete?orderId=12345

可以按以下流程处理:

  1. 支付完成后,支付网关跳转到一个 HTTPS 返回页。
  2. 返回页尝试打开应用深链接。
  3. Cordova 应用接收深链接并提取订单编号。
  4. 应用向自己的服务端查询订单状态。
  5. 如果用户尚未安装应用,HTTPS 返回页显示支付结果或下载入口。

返回页可以使用类似的逻辑:

<script>
  const params = new URLSearchParams(window.location.search);
  const orderId = params.get('orderId');

  if (orderId) {
    window.location.href =
      'myapp://payment/complete?orderId=' +
      encodeURIComponent(orderId);
  }
</script>

Cordova 不会自动处理所有形式的深链接。项目需要安装并配置适合当前平台和 Cordova 版本的深链接插件,也可以在原生入口中实现 URL 接收逻辑。应用收到 URL 后,可以这样处理:

function handleDeepLink(url) {
  const parsedUrl = new URL(url);

  if (
    parsedUrl.protocol === 'myapp:' &&
    parsedUrl.hostname === 'payment' &&
    parsedUrl.pathname === '/complete'
  ) {
    const orderId = parsedUrl.searchParams.get('orderId');

    if (orderId) {
      verifyOrder(orderId);
    }
  }
}

回调函数的具体名称由深链接插件决定。示例中的 handleDeepLink() 不是 Cordova 内置 API,不能直接照搬。

在条件允许时,iOS 更适合使用 Universal Links,Android 更适合使用 App Links。这两种方式使用 HTTPS 地址,并通过域名关联文件验证应用身份,比任何应用都能尝试注册的自定义 URL Scheme 更可靠。

为什么不能只设置一个应用内路径

支付网关通常只接受 HTTP 或 HTTPS 类型的 return_url,不一定允许:

file:///android_asset/www/index.html

也不一定允许:

myapp://payment/complete

即使网关接受自定义 Scheme,浏览器安全策略、用户手势限制或平台配置也可能阻止跳转。兼容性较好的办法是先返回自己控制的 HTTPS 页面,再由该页面唤起应用。如果支付流程始终停留在 InAppBrowser 中,则可以直接拦截这个 HTTPS 地址。

支付结果必须由服务端确认

返回地址只能说明浏览器到达了某个页面,不能证明支付已经成功。用户可以手动构造成功 URL,网络中断也可能让应用收不到跳转。

可靠的处理流程如下:

  1. 服务端创建订单并生成支付参数。
  2. 支付网关通过服务端通知地址发送异步回调。
  3. 服务端校验签名、订单号、金额、币种和商户信息。
  4. 服务端以幂等方式更新订单状态。
  5. Cordova 应用返回前台后,使用订单 ID 查询服务端状态。

不要将支付密钥、签名私钥或网关密钥写入 Cordova 的 JavaScript 代码。Cordova 应用资源可以被提取,敏感凭据必须保存在服务端。

常见问题

监听不到跳转

支付页面可能打开了新窗口,也可能已经转到系统浏览器或第三方应用。可以先记录 loadstart 收到的 URL,确认最后的跳转是否仍发生在当前 InAppBrowser 实例中。

同时检查实际返回地址是否经过多次重定向、是否附加了查询参数,以及路径末尾是否多了斜杠。建议解析 URL 后分别比较协议、域名和路径,不要使用过于严格的完整字符串相等判断。

关闭浏览器后页面没有更新

browser.close() 只会关闭 InAppBrowser。应用内的页面跳转、订单刷新和成功提示仍需单独处理。如果项目使用前端框架,还要确保状态更新进入框架的变更检测或响应式流程。

用户提前关闭支付窗口

可以监听 exit 事件,但不要立刻将订单判定为失败。用户可能已经付款,只是在页面回跳前手动关闭了窗口。此时应查询服务端订单状态。如果状态仍是 pending,可以提示用户稍后刷新。

支付状态短时间内仍是 pending

支付网关发送服务端通知的时间可能晚于浏览器返回。应用可以进行有限次数的轮询,并设置合适的间隔和超时时间。超时后应显示”支付结果确认中”,不要直接判定支付失败。

推荐实现

大多数 Cordova 支付场景可以采用以下组合:

  • 使用 HTTPS return_url。
  • 在 InAppBrowser 中监听该 URL,并在识别后关闭窗口。
  • 对于会离开应用的支付流程,配置 Universal Link、App Link 或自定义 URL Scheme。
  • 应用返回后只传递订单 ID,不直接相信 URL 中的支付状态。
  • 最终支付结果以服务端校验和支付网关的异步通知为准。

这套方式既能让界面在支付后返回应用,也能避免将一次浏览器跳转当成可信的支付凭证。

备注:内容仅供参考。