WKWebView 拦截资源请求的唯一姿势
2023-02-21 16:49:30
拦截 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)
`}