返回

WKWebView 拦截资源请求的唯一姿势

iOS

拦截 WKWebView 资源请求的进阶指南

踩坑之旅

使用 WKWebView 拦截资源请求时,一个常见的陷阱是使用 loadHTMLString 方法加载网页内容。loadHTMLString 直接将 HTML 代码加载到 WKWebView 中,绕过正常的请求-响应流程。要拦截请求,必须使用 loadRequest 方法加载网页内容。

唯一路径

iOS 中拦截 WKWebView 资源请求的唯一途径是使用 URLProtocol 类。URLProtocol 是一个抽象类,允许拦截和处理 URL 请求。要使用 URLProtocol,需要创建一个继承自 URLProtocol 的子类,并实现 canInit(with request:)startLoading()stopLoading() 等方法。

在 canInit(with request:) 中检查请求

canInit(with request:) 方法中,检查请求是否符合要拦截的条件。符合则返回 true,否则返回 false

在 startLoading() 中处理请求

startLoading() 方法中,开始处理请求。在此,可以发送请求、修改响应或注入 JavaScript 代码。

在 stopLoading() 中停止请求

stopLoading() 方法中,停止处理请求。在此,可以释放资源、关闭连接或执行清理工作。

常见的陷阱

  • 忘记在 Info.plist 中注册 URLProtocol
  • 忘记实现所有必需的 URLProtocol 方法

结论

使用 URLProtocol 拦截 WKWebView 资源请求是优化性能的有效方法。然而,使用 URLProtocol 时要注意一些常见的陷阱,以确保 WKWebView 正确加载网页内容。

常见问题解答

1. 如何检查请求是否属于某个主机?
let url = request.url!
let host = url.host!
if host == "example.com" { ... }

2. 如何修改响应中的内容?
let response = URLResponse(url: url, mimeType: "text/html", expectedContentLength: 100, textEncodingName: "UTF-8")
connection?.response = response

3. 如何注入 JavaScript 代码?
let script = "console.log('Hello, world!');"
let userScript = WKUserScript(source: script, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
WKWebViewConfiguration.userContentController.addUserScript(userScript)

4. 如何避免加载本地文件?
if request.url!.isFileURL {
connection?.cancel()
return
`}

5. 如何处理 WKWebView 以外的请求?
guard let session = request.sessionTaskMetrics.task?.session else { return }
let delegate = URLSessionDelegate()
session.delegateQueue.addOperation {
session.invalidateAndCancel()
delegate.sessionDidInvalidate(session)
`}