PAYATHON 2026

LINE API 调起支付宝沙箱版后无支付界面是什么原因?

支付老李

结论

问题通常不在于 LINE API 拦截了支付宝回调地址或沙箱网关。

从当前现象看,更可能是接入方式与运行环境不匹配。alipay.trade.app.pay 生成的是供支付宝客户端 SDK 使用的订单字符串,不能在 LINE 内置浏览器、LIFF 页面或普通 WebView 中手工拼接成 alipays://platformapi/startapp?... 后直接跳转。

直接打开 Scheme 可能只能唤起支付宝沙箱版,却没有完成支付宝 SDK 所需的支付调用与结果回传,因此可能出现白屏、只启动 App、不显示收银台等情况。

还需要确认支付宝 SDK 已切换到沙箱环境,并检查 app_id、应用私钥和支付宝公钥是否都属于同一个沙箱应用。

LINE、网关和回调分别负责什么

这三部分的职责不同:

  • LINE 内置浏览器负责打开网页,并决定网页能否跳转到外部 App。
  • 支付宝网关负责处理支付宝交易请求,不由 LINE 调用。
  • notify_url 是支付宝服务器在支付完成后向商户服务器发送异步通知的地址,不会经过 LINE。

所以,即使 notify_url 配置错误,通常也不会导致支付界面无法出现。它影响的是支付完成后的异步通知。

支付宝沙箱网关也不应配置成 LINE 的代理地址。服务端应直接使用支付宝提供的沙箱网关:

https://openapi-sandbox.dl.alipaydev.com/gateway.do

如果 LINE 页面无法打开 alipays://,一般是内置浏览器限制了自定义 Scheme、弹窗或非用户触发的跳转,与支付宝服务器回调无关。

正确的 App 支付流程

标准流程如下:

  1. 商户服务端通过支付宝 SDK 生成并签名订单字符串。
  2. 服务端将订单字符串原样返回给自己的原生 App。
  3. 原生 App 调用支付宝客户端 SDK 的 payV2()。
  4. 支付宝 SDK 唤起支付宝沙箱版并显示收银台。
  5. 支付结束后,SDK 向 App 返回同步结果。
  6. 支付宝服务器向 notify_url 发送异步通知。

服务端返回的是 orderString,不是手工拼接的 alipays:// 地址。

如果支付入口位于 LINE 的 LIFF 页面或内置浏览器中,流程里就没有原生 App 调用支付宝客户端 SDK 这一步。这类场景不适合直接使用 alipay.trade.app.pay,可以考虑改用 alipay.trade.wap.pay,并尽量在系统浏览器中打开支付页面。

PHP 服务端示例

下面的示例使用支付宝 PHP SDK 生成 App 支付订单字符串。不同 SDK 包的类名可能略有差异,但调用方式基本一致:

<?php

$aop = new AopClient();

$aop->gatewayUrl = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do';
$aop->appId = '你的沙箱应用APPID';
$aop->rsaPrivateKey = file_get_contents(__DIR__ . '/keys/app_private_key.pem');
$aop->alipayrsaPublicKey = file_get_contents(__DIR__ . '/keys/alipay_public_key.pem');
$aop->format = 'json';
$aop->charset = 'UTF-8';
$aop->signType = 'RSA2';

$request = new AlipayTradeAppPayRequest();

$bizContent = [
    'out_trade_no' => 'ORDER_' . date('YmdHis') . '_' . random_int(1000, 9999),
    'total_amount' => '60.00',
    'subject' => '高级护肤套装',
    'product_code' => 'QUICK_MSECURITY_PAY',
];

$request->setBizContent(
    json_encode(
        $bizContent,
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
    )
);

$request->setNotifyUrl('https://example.com/alipay/notify');

// 返回已经签名的订单字符串
$orderString = $aop->sdkExecute($request);

header('Content-Type: application/json; charset=utf-8');

echo json_encode([
    'order_string' => $orderString,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

不要对 $orderString 再次排序、重新签名或整体进行 URL 编码。支付宝 SDK 返回的字符串应原样交给客户端 SDK。

Android 客户端示例

调试沙箱时,需要在调用 PayTask 前切换到沙箱环境:

import com.alipay.sdk.app.EnvUtils
import com.alipay.sdk.app.PayTask

fun startAlipay(activity: Activity, orderString: String) {
    // 仅用于沙箱调试,正式环境必须删除或切换回正式环境
    EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX)

    Thread {
        val payTask = PayTask(activity)
        val result = payTask.payV2(orderString, true)

        activity.runOnUiThread {
            val resultStatus = result["resultStatus"]
            val memo = result["memo"]
            val rawResult = result["result"]

            Log.d(
                "Alipay",
                "resultStatus=$resultStatus, memo=$memo, result=$rawResult"
            )
        }
    }.start()
}

不要在 Android 代码中自行构造:

alipays://platformapi/startapp?...

Scheme 的生成、支付宝客户端检测、调用参数封装和结果回传,都应交给支付宝客户端 SDK 处理。

如果入口是 LINE 或 LIFF 页面

如果支付按钮位于 LINE 内置浏览器中,这就是网页支付入口,并非商户自己的原生 App。可以选择以下两种方案。

方案一:改用手机网站支付

服务端使用:

alipay.trade.wap.pay

由支付宝生成跳转表单或支付页面,在用户点击按钮后打开。必要时可改用外部系统浏览器,以减少 LINE WebView 对弹窗、Cookie 和自定义 Scheme 的限制。

方案二:跳转到自己的原生 App

通过 Universal Link、App Link 或自定义 Deep Link 打开商户自己的 App,再由该 App 调用支付宝客户端 SDK。

流程如下:

LINE / LIFF
    -> 打开商户自己的 App
    -> 商户 App 请求服务端订单字符串
    -> 商户 App 调用支付宝 SDK
    -> 支付宝沙箱版显示收银台

仅在 LINE 页面中执行下面的跳转并不可靠:

window.location.href = "alipays://platformapi/startapp?...";

LINE 内置浏览器可能要求跳转由用户点击触发,也可能直接限制未知 Scheme。即使成功启动了支付宝 App,也不能证明 App 支付协议已经正确执行。

针对当前参数的重点排查项

1. 不要重复使用示例订单

现有参数中包含固定值:

out_trade_no=ALIPAY_445_1753860214
timestamp=2025-07-30 15:23:34

每次测试都应重新生成订单号和时间戳。旧订单、重复订单号或过期请求不能反复作为新的支付请求使用。

2. 确认沙箱环境完全一致

以下内容必须属于同一个支付宝沙箱应用:

  • app_id
  • 应用私钥
  • 上传到支付宝开放平台的应用公钥
  • 用于验签的支付宝公钥
  • 支付宝沙箱客户端及沙箱账号
  • 客户端 SDK 的沙箱环境设置

常见错误是使用沙箱 app_id,却配上了正式环境的密钥或 SDK 环境。

3. 签名后不要修改参数

RSA2 签名应由支付宝 SDK 完成。签名后修改以下任何内容,都可能导致验签失败:

  • biz_content
  • 参数顺序或编码方式
  • 空格与 + 的处理
  • 中文编码
  • notify_url
  • timestamp
  • sign_type

不要先进行 URL 编码再签名,也不要重复编码 SDK 的输出结果。

4. 检查真实的 SDK 返回值

不能只看支付宝 App 是否被唤起,还应记录 payV2() 返回的以下字段:

resultStatus
memo
result

如果绕过 payV2() 直接打开 Scheme,就无法获得可靠的 SDK 错误信息,也很难分辨问题出在验签、环境配置还是订单本身。

5. 单独验证 LINE 是否影响跳转

可以做两组对照测试:

  • 在最小化的原生 Android 测试程序中调用 payV2()。
  • 在 LINE 或 LIFF 页面中执行当前跳转。

如果原生 SDK 能正常显示收银台,而 LINE 页面不能,问题多半出在 WebView 或 Scheme 跳转方式。如果原生 SDK 也失败,则应继续检查沙箱环境、密钥和订单签名。

6. notify_url 需要公网可访问

ngrok 地址可以用于临时联调,但需要确认:

  • 支付宝服务器可以直接访问;
  • HTTPS 证书有效;
  • 接口允许匿名 POST;
  • 不需要登录、验证码或浏览器确认;
  • 地址没有过期或发生变化;
  • 验签成功后返回纯文本 success。

即使 notify_url 暂时不可用,通常也不会造成支付宝收银台完全不显示,所以它不是当前问题的首要排查项。

最可能的修正方向

如果使用的是原生 App 支付,应停止手工打开 alipays://,改为“PHP SDK 生成订单字符串 + Android/iOS 支付宝 SDK 调用”的标准流程,同时确保客户端已切换到沙箱环境。

如果支付入口只能运行在 LINE 页面中,就不能把 alipay.trade.app.pay 当作普通网页链接使用。可以改用 alipay.trade.wap.pay,或者先打开商户自己的原生 App,再由原生 App 调用支付宝 SDK。

从目前的现象判断,LINE 拦截支付宝回调地址的可能性较低。应优先检查通过 LINE WebView 直接打开 App 支付 Scheme 的做法,以及支付宝沙箱环境和密钥是否一致。

备注:内容仅供参考。