特定网页在WKWebView仅显示白屏的问题排查咨询
以下是针对你遇到的「特定网页在Safari/SFSafariViewController正常加载,但WKWebView白屏且无报错」问题的具体排查步骤和解决方案:
1. 验证User-Agent差异导致的内容适配问题
WKWebView的默认User-Agent与Safari存在差异,部分网站会根据UA返回不同的页面内容,甚至拒绝为非Safari UA提供完整页面。
排查操作:
在makeUIView方法中打印当前WKWebView的UA,并与Safari的UA对比(Safari中访问about:version可查看):
func makeUIView(context: Context) -> WKWebView { let wkwebView = WKWebView() print("WKWebView UA: \(wkwebView.customUserAgent ?? wkwebView.configuration.defaultWebpagePreferences.userAgent ?? "")") wkwebView.navigationDelegate = context.coordinator wkwebView.load(URLRequest(url: url)) return wkwebView }
修复方案:
手动将WKWebView的UA设置为Safari的UA:
func makeUIView(context: Context) -> WKWebView { let config = WKWebViewConfiguration() // 替换为你从Safari获取的实际UA config.defaultWebpagePreferences.userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1" let wkwebView = WKWebView(frame: .zero, configuration: config) wkwebView.navigationDelegate = context.coordinator wkwebView.load(URLRequest(url: url)) return wkwebView }
2. 排查Content Security Policy (CSP) 限制
部分网站的CSP规则可能严格限制WKWebView加载资源(比如内联JS、外部脚本),而Safari对CSP的执行宽松度更高,导致页面白屏但无报错。
排查操作:
扩展Coordinator的功能,监听网页控制台日志,捕获CSP相关错误:
- 让Coordinator实现
WKScriptMessageHandler协议,并添加日志监听:
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler { var parent: WebView init(_ parent: WebView) { self.parent = parent } // 原有导航代理方法... func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { print("loading didFinish") parent.isLoading = false // 注入JS转发控制台日志 webView.evaluateJavaScript(""" console.log = function(message) { window.webkit.messageHandlers.logHandler.postMessage(message); }; console.error = function(message) { window.webkit.messageHandlers.logHandler.postMessage('ERROR: ' + message); }; """) { _, error in if let error = error { print("JS注入失败: \(error)") } } } // 接收网页控制台日志 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "logHandler" { print("网页控制台: \(message.body)") } } }
- 在WKWebView配置中添加消息处理器:
func makeUIView(context: Context) -> WKWebView { let config = WKWebViewConfiguration() let userContentController = WKUserContentController() userContentController.add(context.coordinator, name: "logHandler") config.userContentController = userContentController let wkwebView = WKWebView(frame: .zero, configuration: config) wkwebView.navigationDelegate = context.coordinator wkwebView.load(URLRequest(url: url)) return wkwebView }
通过Xcode控制台输出,查看是否有CSP相关的错误提示。
修复方案:
如果确认是CSP问题,可尝试联系网站管理员调整CSP规则;若网站允许,也可在请求中添加自定义Header(需验证网站是否支持)。
3. 检查ATS(App Transport Security)配置
如果目标网页是HTTP协议,或HTTPS证书存在问题,WKWebView会默认阻止加载,而Safari允许加载这类页面。
排查操作:
完善错误捕获逻辑,打印详细错误信息:
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { print("加载失败: \(error)") if let nsError = error as NSError? { print("错误码: \(nsError.code), 域名: \(nsError.domain)") print("错误详情: \(nsError.userInfo)") } parent.isLoading = false parent.error = error } // 补充捕获导航过程中的错误 func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { print("导航失败: \(error)") parent.isLoading = false parent.error = error }
若错误码为-1022(ATS阻止HTTP)或-1202(证书不被信任),则对应ATS配置问题。
修复方案:
- 针对HTTP页面:在
Info.plist中添加ATS例外(仅针对目标域名,避免全局关闭ATS):
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>你的目标域名.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSAllowsArbitraryLoads</key> <true/> </dict> </dict> </dict>
- 针对自签名证书(仅测试环境使用,生产环境不建议):在导航代理中信任证书:
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { guard let serverTrust = challenge.protectionSpace.serverTrust else { completionHandler(.cancelAuthenticationChallenge, nil) return } let credential = URLCredential(trust: serverTrust) completionHandler(.useCredential, credential) }
4. 确保JavaScript和存储权限开启
部分网页依赖JavaScript或本地存储(localStorage/sessionStorage),WKWebView默认启用JavaScript,但需确认配置未被修改。
修复方案:
在WKWebView配置中明确开启相关权限:
func makeUIView(context: Context) -> WKWebView { let config = WKWebViewConfiguration() // 开启JavaScript config.defaultWebpagePreferences.allowsContentJavaScript = true // 启用本地存储 config.websiteDataStore = WKWebsiteDataStore.default() let wkwebView = WKWebView(frame: .zero, configuration: config) wkwebView.navigationDelegate = context.coordinator wkwebView.load(URLRequest(url: url)) return wkwebView }
5. 修复网页视口适配问题
部分网页对WKWebView的视口适配处理不佳,导致内容被隐藏或缩放异常,看起来是白屏。
修复方案:
注入视口适配的JS代码,强制网页适配设备宽度:
func makeUIView(context: Context) -> WKWebView { let config = WKWebViewConfiguration() let userContentController = WKUserContentController() // 注入视口适配脚本 let viewportScript = WKUserScript( source: """ var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'); document.head.appendChild(meta); """, injectionTime: .atDocumentStart, forMainFrameOnly: true ) userContentController.addUserScript(viewportScript) config.userContentController = userContentController let wkwebView = WKWebView(frame: .zero, configuration: config) wkwebView.navigationDelegate = context.coordinator wkwebView.load(URLRequest(url: url)) return wkwebView }
内容的提问来源于stack exchange,提问作者Sachinthana Aluvihare

