在WKWebView中加载登录页后,能否获取登录成功的JSON数据?
在WKWebView中获取登录成功后的JSON数据
可以获取,下面是两种实用的实现方案:
方案一:JS注入与原生交互
这种方法适配性强,不管前端是否可控都能实现:
1. 配置原生消息处理器
先给WKWebView添加消息监听,接收前端传递的登录数据:
class LoginWebVC: UIViewController, WKScriptMessageHandler { private var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() let config = WKWebViewConfiguration() // 注册接收JS消息的处理器 config.userContentController.add(self, name: "loginSuccessBridge") webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self view.addSubview(webView) // 加载目标登录页面 webView.load(URLRequest(url: URL(string: "你的登录页面地址")!)) } // 接收JS发送的登录数据 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard message.name == "loginSuccessBridge", let loginJSON = message.body as? [String: Any] else { return } // 这里拿到登录相关的JSON数据,做后续处理 print("登录返回数据:\(loginJSON)") } }
2. 注入JS监听登录请求
在页面加载完成后,注入JS脚本拦截登录接口的响应,自动把数据传给原生:
extension LoginWebVC: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // 注入监听XMLHttpRequest的脚本,替换成你的登录接口路径 let injectScript = """ const originSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function() { const xhr = this; xhr.addEventListener('load', function() { if (xhr.responseURL.includes('/api/user/login')) { try { const loginData = JSON.parse(xhr.responseText); window.webkit.messageHandlers.loginSuccessBridge.postMessage(loginData); } catch(e) {} } }); originSend.apply(this, arguments); }; """ webView.evaluateJavaScript(injectScript) { _, error in if let err = error { print("JS注入失败:\(err)") } } } }
如果前端是你可控的,也可以让前端在登录成功后直接调用window.webkit.messageHandlers.loginSuccessBridge.postMessage(loginResult)传递数据,省去注入脚本的步骤。
方案二:拦截网络请求响应
通过自定义WKURLSchemeHandler拦截WKWebView的登录接口请求,直接获取响应数据:
1. 实现自定义Scheme处理器
class LoginSchemeHandler: NSObject, WKURLSchemeHandler { func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { let request = urlSchemeTask.request guard let url = request.url, url.path.contains("/api/user/login") else { // 非登录接口,直接转发请求 let task = URLSession.shared.dataTask(with: request) { data, resp, err in self.forwardResponse(to: urlSchemeTask, data: data, response: resp, error: err) } task.resume() return } // 处理登录接口请求,提取响应数据 let task = URLSession.shared.dataTask(with: request) { data, resp, err in if let data = data, let httpResp = resp as? HTTPURLResponse, httpResp.statusCode == 200 { do { let loginJSON = try JSONSerialization.jsonObject(with: data) as? [String: Any] print("登录数据:\(loginJSON ?? [:])") // 可通过通知或闭包把数据传递给控制器 NotificationCenter.default.post(name: .loginSuccess, object: loginJSON) } catch { print("解析登录数据失败:\(error)") } } self.forwardResponse(to: urlSchemeTask, data: data, response: resp, error: err) } task.resume() } func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {} // 把响应转发给WKWebView,保证页面正常流程 private func forwardResponse(to task: WKURLSchemeTask, data: Data?, response: URLResponse?, error: Error?) { if let resp = response { task.didReceive(resp) } if let data = data { task.didReceive(data) } if let err = error { task.didFailWithError(err) } else { task.didFinish() } } } // 定义通知名 extension Notification.Name { static let loginSuccess = Notification.Name("LoginSuccessNotification") }
2. 配置WKWebView使用自定义处理器
// 在控制器中创建WKWebView时 let config = WKWebViewConfiguration() // 给https协议(或你的接口协议)绑定自定义处理器 config.setURLSchemeHandler(LoginSchemeHandler(), forURLScheme: "https") webView = WKWebView(frame: view.bounds, configuration: config)
内容的提问来源于stack exchange,提问作者Arun
相关产品推荐
相关产品推荐

