You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS WKWebView冷启动后显示about:blank问题解决求助

冷启动后WKWebView显示about:blank的排查与解决

问题背景

iOS应用中使用WKWebView加载网页,后台或运行状态下加载正常,但强制退出(上滑关闭)后重启,WebView仅显示about:blank空白页;删除重装应用后可恢复正常加载。

相关代码

WebView.swift

struct WebView: UIViewRepresentable {
    
    var url: URL?
    
    var redirect: ((URL) -> Void)?
    
    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        webView.isInspectable = true
        webView.navigationDelegate = context.coordinator
        return webView
    }
    
    func updateUIView(_ webView: WKWebView, context: Context) {
        if let url = url {
            webView.load(URLRequest(url: url))
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, WKNavigationDelegate {
        
        var parent: WebView
        
        init(parent: WebView) {
            self.parent = parent
        }
    
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            let javascript = """
                if (document.querySelector('meta[name="viewport"]')) {
                    document.querySelector('meta[name="viewport"]').setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no');
                } else {
                    const 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.getElementsByTagName('head')[0].appendChild(meta);
                }
                true;
            """
            
            webView.evaluateJavaScript(javascript) { result, error in
                if let error = error {
                    print("Error injecting JavaScript: \(error)")
                } else {
                    print("JavaScript executed successfully.")
                }
            }
            print("WebView finished loading.")
        }

        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
            print("WebView failed with error: \(error.localizedDescription)")
        }

        func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
            print("WebView provisional load failed: \(error.localizedDescription)")
        }
        
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            if let url = navigationAction.request.url, url.scheme == "oauthapp" {
                parent.redirect?(url)  // Pass deep link to your SwiftUI view
                decisionHandler(.cancel) // Cancel navigation
                return
            }
            decisionHandler(.allow)
        }
    }

}

ContentView

func buildAuthURL() -> URL? {
    var components = URLComponents(string: authURL)
    components?.queryItems = [
        URLQueryItem(name: "response_type", value: "code"),
        URLQueryItem(name: "client_id", value: clientID),
        URLQueryItem(name: "redirect_uri", value: redirectURI),
        URLQueryItem(name: "code_challenge", value: codeChallenge),
        URLQueryItem(name: "code_challenge_method", value: "S256"),
        URLQueryItem(name: "scope", value: scopes)
    ]
    return components?.url
}

var body: some View {
    if accessToken == nil {
        WebView(url: buildAuthURL()){ url in
            if let components = URLComponents(string: url.absoluteString),
               let code = components.queryItems?.first(where: { $0.name == "code" })?.value {
                print("Authorization code: \(code)")
                authCode = code
                requestAccessToken(code: code)
            } else {
                print("Failed to extract code from URL.")
            }
        }.ignoresSafeArea()
    } else {
        Text("Authorization Code: \((authCode ?? "").prefix(15))...")
        Text("Access Token: \((accessToken ?? "").prefix(15))...")
    }
}

问题现象

  • 冷启动(强制退出后启动)时,WebView显示空白,地址为about:blank
  • 应用无崩溃,其他功能正常

排查与修复方案

1. 验证URL生成是否正常

冷启动时可能authURL、clientID等配置项未完成初始化,导致buildAuthURL()返回nil,updateUIView未执行加载逻辑。

  • 调试:在buildAuthURL()中添加日志,确认URL生成状态:
    func buildAuthURL() -> URL? {
        print("Auth URL base: \(authURL ?? "nil")")
        var components = URLComponents(string: authURL)
        print("Generated components: \(components ?? nil)")
        components?.queryItems = [
            URLQueryItem(name: "response_type", value: "code"),
            URLQueryItem(name: "client_id", value: clientID),
            URLQueryItem(name: "redirect_uri", value: redirectURI),
            URLQueryItem(name: "code_challenge", value: codeChallenge),
            URLQueryItem(name: "code_challenge_method", value: "S256"),
            URLQueryItem(name: "scope", value: scopes)
        ]
        print("Final URL: \(components?.url ?? nil)")
        return components?.url
    }
    
  • 修复:确保authURL等配置项在冷启动时已从本地存储/配置文件中正确加载,避免依赖运行时动态赋值。

2. 强化WebView初始化时的加载逻辑

SwiftUI的updateUIView可能因冷启动时视图刷新时机问题未触发,导致URL未加载。可在makeUIView中直接添加初始加载逻辑:

func makeUIView(context: Context) -> WKWebView {
    let webView = WKWebView()
    webView.isInspectable = true
    webView.navigationDelegate = context.coordinator
    // 初始化时直接加载URL,避免依赖updateUIView
    if let url = url {
        webView.load(URLRequest(url: url))
    }
    return webView
}

同时保留updateUIView中的逻辑,应对后续URL变化场景。

3. 排查异常缓存影响

冷启动时WKWebView可能残留异常缓存,导致加载失败。可临时添加缓存清除逻辑排查:

func makeUIView(context: Context) -> WKWebView {
    // 清除WKWebView缓存(仅作为排查手段,正式环境按需使用)
    let websiteDataTypes: Set<String> = [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache]
    WKWebsiteDataStore.default().removeData(ofTypes: websiteDataTypes, modifiedSince: .distantPast) {
        print("Cache cleared")
    }
    
    let webView = WKWebView()
    webView.isInspectable = true
    webView.navigationDelegate = context.coordinator
    if let url = url {
        webView.load(URLRequest(url: url))
    }
    return webView
}

4. 细化错误日志排查

当前错误回调仅打印简单描述,可补充详细错误信息定位问题:

func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
    let nsError = error as NSError
    print("Provisional load failed: \(error.localizedDescription) | Code: \(nsError.code) | Domain: \(nsError.domain)")
}

常见冷启动错误包括:ATS配置未授权网络请求、证书信任问题、URL Scheme未正确配置等,可根据错误码针对性处理。

内容的提问来源于stack exchange,提问作者Source

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 05:54:55