PAYATHON 2026

安卓使用 alipays:// 支付成功后如何返回原 app?

支付阿杰

结论

alipays://platformapi/startapp?saId=10000007&qrcode=... 只能唤起支付宝并打开二维码对应的页面,无法建立“支付完成后返回原 App”的回调关系。因此,支付成功后,支付宝通常不会自动跳回发起支付的 App。

如需自动返回并可靠获取支付结果,应接入支付宝 App 支付 SDK。原 App 通过 PayTask.payV2() 发起支付,并处理 SDK 返回的同步结果。订单的最终支付状态仍要以服务端收到的异步通知为准。

为什么无法自动返回

Android 通过 Intent 打开 alipays:// 时,只是启动了支付宝中的指定页面:

alipays://platformapi/startapp?saId=10000007&qrcode=...

支付宝只知道需要打开哪个二维码页面,并不知道:

  • 支付请求由哪个 App 发起;
  • 支付完成后应返回哪个 Activity;
  • 原 App 使用哪种回调协议;
  • 返回时需要携带哪些支付结果。

即使原 App 仍留在后台任务栈中,用户通常也需要手动切回。支付宝客户端是否显示“返回商家”按钮取决于具体页面和产品能力,不能把它当作稳定的回调机制。

推荐方案:使用支付宝 App 支付 SDK

标准流程是:

  1. App 请求业务服务端创建支付订单。
  2. 服务端调用支付宝接口,生成并签名 orderInfo。
  3. App 通过支付宝 SDK 发起支付。
  4. 支付流程结束后,SDK 返回原 App 并提供同步结果。
  5. 服务端接收支付宝异步通知,验签后更新订单状态。
  6. App 向业务服务端查询最终支付结果。

Android 端可以这样调用:

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.alipay.sdk.app.PayTask
import java.util.concurrent.Executors

class PayActivity : AppCompatActivity() {

    private val executor = Executors.newSingleThreadExecutor()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    private fun startAlipay(orderInfo: String) {
        executor.execute {
            val result = PayTask(this).payV2(orderInfo, true)

            runOnUiThread {
                handlePayResult(result)
            }
        }
    }

    private fun handlePayResult(result: Map<String, String>) {
        when (result["resultStatus"]) {
            "9000" -> {
                // 同步结果表示支付流程成功返回。
                // 此处仍应请求业务服务端确认订单最终状态。
                queryOrderStatus()
            }

            "8000" -> {
                // 结果处理中,稍后向业务服务端查询订单状态。
                queryOrderStatus()
            }

            "6001" -> {
                // 用户取消支付。
            }

            else -> {
                // 支付失败或状态未知。
                // 可提示用户,并允许重新查询订单状态。
                queryOrderStatus()
            }
        }
    }

    private fun queryOrderStatus() {
        // 调用业务服务端的订单查询接口。
    }
}

Java 示例:

ExecutorService executor = Executors.newSingleThreadExecutor();

executor.execute(() -> {
    PayTask payTask = new PayTask(PayActivity.this);
    Map<String, String> result = payTask.payV2(orderInfo, true);

    runOnUiThread(() -> {
        String resultStatus = result.get("resultStatus");

        if ("9000".equals(resultStatus) || "8000".equals(resultStatus)) {
            // 向业务服务端查询订单最终状态
            queryOrderStatus();
        } else if ("6001".equals(resultStatus)) {
            // 用户取消
        } else {
            // 失败或状态未知
            queryOrderStatus();
        }
    });
});

orderInfo 必须由服务端生成并签名。不要将支付宝应用私钥写入 APK,也不要在客户端拼装或签名正式支付订单。

如果必须继续使用 alipays://

如果二维码来自普通收款码、网页支付页或第三方页面,并且只能通过 alipays:// 打开,通常无法强制支付宝在支付成功后返回原 App。

可以采用以下方式处理:

  • 发起支付前记录业务订单号。
  • 原 App 进入后台后,在 onResume() 中向业务服务端查询订单状态。
  • 在页面中明确提示用户,支付完成后需要手动返回。
  • 如果二维码对应的支付产品支持 return_url 或商户回跳地址,可以将其配置为 App 的 Universal Link、App Link 或自定义 Scheme。该方案必须以具体支付产品提供的接口能力为前提,不能直接给 alipays://platformapi/startapp 添加自定义参数来实现回跳。

用户手动切回原 App 时,可以查询订单状态:

class PayActivity : AppCompatActivity() {

    private var waitingForPayment = false

    private fun openAlipay(uri: String) {
        waitingForPayment = true

        val intent = Intent(Intent.ACTION_VIEW, Uri.parse(uri))
        startActivity(intent)
    }

    override fun onResume() {
        super.onResume()

        if (waitingForPayment) {
            queryOrderStatus()
        }
    }

    private fun queryOrderStatus() {
        // 使用业务订单号查询服务端状态。
        // 确认成功后再更新页面,避免仅凭客户端状态判断。
    }
}

onResume() 只能说明用户回到了当前 Activity,不能证明支付已经成功。

注意事项

  • 不要根据“成功页面已出现”“支付宝已打开”或 Activity 生命周期变化判断支付是否成功。
  • 客户端同步结果可能因断网、进程被杀或用户中断而缺失。最终结果应以服务端验签后的异步通知或主动查询结果为准。
  • 服务端处理支付通知时必须验签,同时校验商户号、应用 ID、订单号、金额和订单状态。
  • 支付通知可能重复发送,因此订单更新逻辑必须保证幂等。
  • 自定义 Scheme 可能被其他应用声明。条件允许时,应优先使用经过域名验证的 Android App Links。
  • 不要依赖未公开的 alipays:// 参数或支付宝客户端的页面行为。这些行为不属于稳定的支付回调接口。

问题不在 Android 返回栈,而在于当前 alipays://...&qrcode= 方式没有建立支付回调通道。如果需要自动返回并可靠获取支付结果,应改用支付宝 App 支付 SDK。暂时无法改造时,只能提示用户手动返回,再由原 App 向服务端查询订单状态。

备注:内容仅供参考。