iOS WKWebView 调用 AlipaySDK 无法拉起支付宝客户端
结论
这段 WKNavigationDelegate 拦截代码的整体逻辑没有明显问题。payInterceptorWithUrl:fromScheme:callback: 返回 YES 时取消当前导航,否则继续加载,这种处理是正确的。
支付宝客户端无法拉起,通常不是 decisionHandler 或回调代码本身导致的。建议重点检查以下几项:
fromScheme与 App 实际注册的 URL Scheme 不一致;- H5 跳转 URL 不是 AlipaySDK 能识别的支付宝收银台 URL;
- App 没有配置支付宝回跳所需的 URL Scheme;
- AppDelegate 或 SceneDelegate 没有将回跳 URL 交给 AlipaySDK;
- 支付页面通过
target="_blank"、window.open()或新窗口发起跳转,没有进入当前导航代理; - AlipaySDK 版本过旧,与当前 iOS 或 WKWebView 的行为不兼容。
Android 能正常拉起,只能说明 H5 支付链路基本可用,不能证明 iOS 端的 Scheme、SDK 接入和回跳配置没有问题。
首先检查 fromScheme
示例中的:
fromScheme:@"alisdkdemo"
是支付宝示例工程使用的 Scheme。业务 App 不能直接照搬,必须替换为自己在 Xcode 中注册的 URL Scheme,例如:
fromScheme:@"myappalipay"
Target 中也要配置相同的值:
Target
→ Info
→ URL Types
→ URL Schemes
还可以检查 Info.plist 中是否有对应配置:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myappalipay</string>
</array>
</dict>
</array>
代码、Info.plist 和支付请求使用的 Scheme 必须完全一致,大小写也要相同。建议使用与 Bundle ID 相关的唯一值,避免和其他 App 冲突。
推荐的 WKWebView 拦截写法
调用 SDK 前,可以输出实际导航 URL 和拦截结果,确认支付 URL 是否确实进入代理:
- (void)webView:(WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSURL *URL = navigationAction.request.URL;
NSString *urlString = URL.absoluteString;
NSLog(@"WKWebView navigation URL: %@", urlString);
if (urlString.length == 0) {
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
__weak typeof(self) weakSelf = self;
BOOL intercepted = [[AlipaySDK defaultService]
payInterceptorWithUrl:urlString
fromScheme:@"myappalipay"
callback:^(NSDictionary *result) {
NSLog(@"Alipay interceptor result: %@", result);
BOOL processed = [result[@"isProcessUrlPay"] boolValue];
NSString *returnURL = result[@"returnUrl"];
if (processed && returnURL.length > 0) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf loadWithUrlStr:returnURL];
});
}
}];
NSLog(@"Alipay intercepted: %@", intercepted ? @"YES" : @"NO");
if (intercepted) {
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
需要注意:
- 每条执行路径只能调用一次
decisionHandler; - SDK 返回
YES后,必须取消 WebView 当前导航; - 不要自行根据 URL 中是否包含
alipay来决定是否拦截,应以 SDK 返回值为准; returnUrl可能为空,使用前要先判断;- 更新 UI 或重新加载页面时,应切换到主线程。
配置支付宝回跳处理
App 从支付宝客户端返回时,需要把 URL 交给 AlipaySDK。使用 AppDelegate 生命周期的项目可以这样配置:
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
if ([url.host isEqualToString:@"safepay"]) {
[[AlipaySDK defaultService]
processOrderWithPaymentResult:url
standbyCallback:^(NSDictionary *resultDic) {
NSLog(@"Alipay result: %@", resultDic);
}];
}
return YES;
}
如果项目还需要兼容旧版 AppDelegate 回调,也要确保对应入口能正常转发:
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
if ([url.host isEqualToString:@"safepay"]) {
[[AlipaySDK defaultService]
processOrderWithPaymentResult:url
standbyCallback:^(NSDictionary *resultDic) {
NSLog(@"Alipay result: %@", resultDic);
}];
}
return YES;
}
采用 Scene 生命周期的项目,还要检查 SceneDelegate:
- (void)scene:(UIScene *)scene
openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
{
NSURL *url = URLContexts.allObjects.firstObject.URL;
if (!url) {
return;
}
if ([url.host isEqualToString:@"safepay"]) {
[[AlipaySDK defaultService]
processOrderWithPaymentResult:url
standbyCallback:^(NSDictionary *resultDic) {
NSLog(@"Alipay result: %@", resultDic);
}];
}
}
具体使用哪个 AlipaySDK 结果处理 API,要以项目当前集成版本的 SDK 文档和头文件为准。不同版本可能还提供授权结果、通用链接等入口,不能将其他业务的回调方法用于处理支付结果。
检查 H5 支付 URL 是否被 SDK 识别
payInterceptorWithUrl:fromScheme:callback: 不是用于唤起任意 URL 的通用接口。它只能处理符合支付宝 H5 支付流程,并且能被当前 SDK 识别的 URL。
建议记录这些信息:
NSLog(@"request URL: %@", navigationAction.request.URL.absoluteString);
NSLog(@"navigationType: %ld", (long)navigationAction.navigationType);
NSLog(@"targetFrame: %@", navigationAction.targetFrame);
NSLog(@"intercepted: %@", intercepted ? @"YES" : @"NO");
可以根据日志判断问题所在:
- 如果代理方法没有执行,问题出在 WKWebView 导航链路;
- 如果代理执行了,但
intercepted == NO,说明 SDK 没有识别该 URL,需要检查服务端返回的支付链接、产品类型和签约能力; - 如果
intercepted == YES,但客户端没有拉起,应重点检查 Scheme、SDK 版本、设备环境和系统日志; - 如果能拉起支付宝,但无法返回 App,需要检查 URL Types 和回跳处理。
不要在客户端拼接、修改支付 URL,也不要解码后再重新组装。支付宝返回的跳转地址通常带有签名和编码参数,任何改动都可能导致 SDK 无法识别。
处理 target="_blank" 和 window.open()
部分 H5 收银台会通过新窗口打开支付链接。此时 navigationAction.targetFrame 可能为 nil。如果没有实现 WKUIDelegate,这次跳转可能直接丢失。
先设置代理:
webView.UIDelegate = self;
再处理新窗口请求:
- (WKWebView *)webView:(WKWebView *)webView
createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
forNavigationAction:(WKNavigationAction *)navigationAction
windowFeatures:(WKWindowFeatures *)windowFeatures
{
if (navigationAction.targetFrame == nil) {
NSURLRequest *request = navigationAction.request;
if (request.URL) {
[webView loadRequest:request];
}
}
return nil;
}
这样,新窗口请求会重新交给当前 WKWebView,随后进入 decidePolicyForNavigationAction:,支付宝 SDK 才能进行拦截。
如果 H5 使用 JavaScript 生成中间页,还要确认 JavaScript 没有被禁用:
WKWebViewConfiguration *configuration =
[[WKWebViewConfiguration alloc] init];
configuration.defaultWebpagePreferences.allowsContentJavaScript = YES;
检查 URL 查询白名单
如果业务代码或某个 SDK 版本会通过 canOpenURL: 检查支付宝客户端,需要在 Info.plist 中配置被查询的 Scheme。具体 Scheme 列表应以当前 AlipaySDK 接入文档为准,不建议凭经验随意添加。
常见配置如下:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>alipay</string>
<string>alipays</string>
</array>
这项配置主要影响 canOpenURL: 查询。缺少白名单不一定会阻止所有 openURL: 调用,因此它不能代替 URL Types、回跳处理和正确的支付 URL。
还需要排除的环境问题
建议使用真机测试,并逐项确认:
- 真机已经安装可以正常使用的支付宝客户端;
- App 使用当前官方渠道提供的 AlipaySDK;
- SDK 依赖的系统库、
-ObjC等工程配置符合对应版本的接入说明; - 没有其他 WKWebView 代理或中间层提前调用
decisionHandler; - 支付 URL 没有被交给错误的 WebView 实例;
fromScheme不是示例值,并且与 App 的实际配置一致;- 服务端创建的订单适用于当前 H5 支付场景,而不是只适用于 Android 或其他产品的调用方式。
建议的排查顺序
按照以下顺序检查,通常可以较快找到问题:
- 打印每一次
navigationAction.request.URL; - 确认支付 URL 是否进入
decidePolicyForNavigationAction:; - 记录
payInterceptorWithUrl:的布尔返回值; - 将
alisdkdemo替换为业务 App 的真实 URL Scheme; - 核对 Xcode 中的 URL Types 配置;
- 补充 AppDelegate 或 SceneDelegate 的支付宝回跳处理;
- 处理
target="_blank"和window.open(); - 使用当前 AlipaySDK 版本在真机上重新测试;
- 如果 SDK 始终返回
NO,将脱敏后的原始支付 URL、SDK 版本、iOS 版本和完整控制台日志提交给支付宝技术支持,由其核对支付产品和链接格式。
仅凭现有代码,还不能断定问题出在支付宝客户端或 SDK 内部。排查时最需要确认的是:支付 URL 是否进入代理,SDK 返回 YES 还是 NO,以及 fromScheme 是否与 App 注册的 URL Scheme 完全一致。
备注:内容仅供参考。
