App 拉起支付宝小程序支付后如何返回 App?
结论
支付宝小程序支付完成后,不会默认跳回原 App。my.exitMiniProgram() 只能退出当前小程序,无法保证重新唤起之前的 App。
要让用户稳定返回 App,需要同时满足以下条件:
- 原 App 已配置支持外部唤起的 Universal Link、App Link 或 URL Scheme。
- 支付所在的支付宝小程序有权使用支付宝提供的外部 App 唤起能力。
如果小程序由第三方支付服务商控制,服务商必须配合接入返回链接。只修改原 App,无法让第三方小程序主动跳转回来。若服务商不支持这项能力,可在退出小程序后提示用户手动切回 App,再由 App 在恢复前台时查询支付结果。
为什么不能直接返回
App 拉起支付宝小程序后,支付页面运行在支付宝客户端内。原 App 和支付宝小程序是两个独立应用,支付宝不会在支付完成后自动执行“返回原 App”的操作。
下面的代码只能退出小程序:
my.exitMiniProgram();
退出后显示哪个页面,取决于支付宝客户端和用户进入小程序的路径。用户可能回到支付宝首页,也可能回到上一个支付宝页面,因此不能把这个 API 当作“返回商户 App”的接口。
支付成功页面也不能作为确认支付结果的依据。用户可能取消跳转、关闭支付宝或遇到网络中断,也可能有人通过伪造 Deep Link 向 App 传入 status=success。最终支付状态必须由 App 或业务服务端根据订单号向支付服务端查询。
推荐实现流程
完整流程可以这样设计:
- App 创建业务订单并保存
orderNo。 - App 调用第三方支付服务,拉起对应的支付宝小程序。
- 用户在支付宝小程序中完成支付。
- 小程序通过支付宝允许的外部应用唤起能力,打开 App Link 或 Universal Link。
- App 收到链接后进入支付结果页。
- App 使用
orderNo请求业务服务端查询订单状态。 - 业务服务端根据第三方支付回调或主动查询结果,返回最终状态。
返回地址可以使用类似下面的格式:
https://app.example.com/pay/return?orderNo=ORDER_123456
建议优先使用经过域名校验的 Universal Link 或 Android App Link。也可以使用 URL Scheme,例如:
merchantapp://pay/return?orderNo=ORDER_123456
不过,URL Scheme 可能被其他应用声明,其安全性和唯一性通常不如经过验证的 HTTPS Link。
小程序侧处理
如果支付宝小程序属于第三方服务商,需要向服务商确认:
- 是否支持传入商户 App 的返回链接;
- 是否具备支付宝平台允许的外部 App 唤起能力;
- 是否需要配置 App 标识、包名、域名或白名单;
- 支付完成页能否显示“返回商户 App”按钮;
- 返回参数能否携带商户订单号或支付流水号。
具体使用哪个 API、传递哪些参数,取决于支付宝当前开放的能力以及小程序所属主体拥有的权限。普通页面跳转 API 不能代替外部 App 唤起接口。若支付宝没有向该小程序开放相关能力,可以只退出小程序:
Page({
handleFinish() {
my.exitMiniProgram({
success() {
console.log('小程序已退出');
},
fail(error) {
console.error('退出小程序失败', error);
}
});
}
});
采用这种方案时,页面应明确提示用户:“支付完成后请返回商户 App 查看结果”。
Android 接收返回链接
使用 Android App Link 时,可以在 AndroidManifest.xml 中配置:
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="app.example.com"
android:pathPrefix="/pay/return" />
</intent-filter>
</activity>
App 需要处理冷启动和已经启动这两种情况:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleReturnLink(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleReturnLink(intent)
}
private fun handleReturnLink(intent: Intent?) {
val uri = intent?.data ?: return
if (uri.host != "app.example.com" ||
uri.path != "/pay/return"
) {
return
}
val orderNo = uri.getQueryParameter("orderNo") ?: return
// 不要直接显示支付成功,应向业务服务端查询订单状态。
queryOrderStatus(orderNo)
}
private fun queryOrderStatus(orderNo: String) {
// 调用业务服务端接口查询最终支付状态。
}
}
配置 android:autoVerify="true" 后,还需要在对应的 HTTPS 域名上部署正确的 assetlinks.json。否则,链接可能会在浏览器中打开,也可能弹出应用选择框。
iOS 接收返回链接
使用 Universal Link 时,需要为 App 配置 Associated Domains,并在对应域名上部署正确的 apple-app-site-association 文件。
接收链接的示例代码如下:
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
guard
userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL,
url.host == "app.example.com",
url.path == "/pay/return",
let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let orderNo = components.queryItems?
.first(where: { $0.name == "orderNo" })?
.value
else {
return false
}
// 根据 orderNo 请求业务服务端,确认最终支付状态。
queryOrderStatus(orderNo: orderNo)
return true
}
如果项目使用 Scene 生命周期,还要在 scene(_:continue:) 中处理 Universal Link。
无法主动唤起 App 时的兜底方案
即使已经配置返回链接,也要考虑用户没有点击返回按钮的情况。App 每次从后台恢复到前台时,可以检查是否有待确认订单,并查询订单状态:
override fun onResume() {
super.onResume()
pendingOrderNo?.let { orderNo ->
queryOrderStatus(orderNo)
}
}
查询次数和时间间隔需要合理设置。支付渠道的异步通知可能尚未完成,不应立即把订单判定为失败。状态可以设计为:
PAYING:支付处理中;SUCCESS:服务端确认支付成功;FAILED:服务端确认支付失败;CLOSED:订单已关闭;UNKNOWN:暂时无法确认,允许稍后刷新。
注意事项
- 不要信任返回链接中的
status=success。它只能用于页面导航,不能作为到账依据。 - 返回参数应尽量只包含订单号或一次性凭证,不要传递密钥、支付密码等敏感信息。
- 服务端收到支付回调后必须校验签名,并对重复通知做幂等处理。
- App 需要处理冷启动、后台恢复以及返回链接被重复打开的情况。
- 如果支付宝小程序属于第三方主体,外部 App 唤起能力、白名单和页面代码通常都要由第三方服务商处理。
- 如果第三方服务商明确不支持返回 App,仅靠 App 端无法强制跳回。此时应采用“退出小程序+用户手动切回+App 前台查单”的方案。
- 如果业务条件允许,直接接入支付宝面向 App 的支付产品,通常比“App 拉起小程序支付再返回”更容易形成完整闭环。能否调整接入方式,仍取决于第三方服务和业务条件。
备注:内容仅供参考。
