安卓使用 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
标准流程是:
- App 请求业务服务端创建支付订单。
- 服务端调用支付宝接口,生成并签名
orderInfo。 - App 通过支付宝 SDK 发起支付。
- 支付流程结束后,SDK 返回原 App 并提供同步结果。
- 服务端接收支付宝异步通知,验签后更新订单状态。
- 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 向服务端查询订单状态。
备注:内容仅供参考。
