首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WKWebView不使用URLCache

WKWebView不使用URLCache
EN

Stack Overflow用户
提问于 2020-05-08 06:21:06
回答 3查看 1.3K关注 0票数 2

我有一个应用程序,它使用UIWebView显示一些本地内容。我还有一个定制的URLCache来拦截请求并将它们替换为本地内容:

代码语言:javascript
复制
class LocalWebViewCache: URLCache {
    open override func cachedResponse(for request: URLRequest) -> CachedURLResponse? {
    if url.absoluteString.range(of: "http://localhost") != nil {
            return cacheDelegate?.handleRequest(request)
        }

        return nil
    }
}

我在AppDelagate中将这个缓存注册为:

代码语言:javascript
复制
var cache: LocalWebViewCache = LocalWebViewCache(memoryCapacity: 20 * 1024 * 1024,
                                         diskCapacity: 100 * 1024 * 1024,
                                         diskPath: nil)
URLCache.shared = cache

现在一切都很好。但是苹果拒绝了新版本的应用程序,因为我使用的是UIWebView,它被废弃了,所以我用WKWebView代替了UIWebView,似乎webkit并不尊重共享缓存(URLCache.shared)。

我试着用URLProtocolWKURLSchemeHandler拦截URLProtocol请求,但没有任何结果。

我很感谢你的任何帮助或建议.

URLProtocol 代码:

Appdelagate

代码语言:javascript
复制
URLProtocol.registerClass(MyProtocol.self)
代码语言:javascript
复制
class MyProtocol: URLProtocol {
    override class func canInit(with request: URLRequest) -> Bool {
        print("canInit: \(String(describing: request.url))")
        return true
    }

    override init(request: URLRequest, cachedResponse: CachedURLResponse?, client: URLProtocolClient?) {
        print("init: \(String(describing: request.url))")

        super.init(request: request, cachedResponse: cachedResponse, client: client)
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        print("canonicalRequest: \(String(describing: request.url))")

        return request
    }

    override func startLoading() {
        print("startLoading: \(String(describing: request.url))")
    }
}

在所有这些方法中,只有canInit(with request: URLRequest)被调用,这不是很有帮助。

WKURLSchemeHandler 代码:

代码语言:javascript
复制
class MySchemeHandler: NSObject, WKURLSchemeHandler {
    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        print("start: \(String(describing: urlSchemeTask.request.url?.absoluteString))")
    }

    func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
        print("stop: \(String(describing: urlSchemeTask.request.url?.absoluteString))")
    }
}
代码语言:javascript
复制
webkit.configuration.setURLSchemeHandler(MySchemeHandler(), forURLScheme: "localhost")

webkit.load(URLRequest(url: URL(string: "localhost://google.com")!))

但是webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask)webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask)都没有被调用。

编辑1:通过在url开头附加localhost://来加载本地资源,并通过WKURLSchemeHandler处理它:

代码语言:javascript
复制
let testStr = """
            <!DOCTYPE html>
            <html>
            <head>
            <title></title>
            <link href="localhost://../styles/style.css" type="text/css" rel="stylesheet"/>
            </head>
            <body>

            <p class="test_class1">This is a paragraph.</p>
            <p class ="test_class2">This is another paragraph.</p>

            </body>
            </html>
    """
代码语言:javascript
复制
lazy var webView: WKWebView = {
        let webConfiguration = WKWebViewConfiguration()
        webConfiguration
            .setURLSchemeHandler(MySchemeHandler(), forURLScheme: "localhost")
        let webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.translatesAutoresizingMaskIntoConstraints = false
        return webView
    }()
代码语言:javascript
复制
webView.loadHTMLString(testStr, baseURL: URL(string: "localhost"))
代码语言:javascript
复制
class MySchemeHandler: NSObject, WKURLSchemeHandler {
    let testCss = """
            @font-face{
                font-family: 'Special';
                font-weight: normal;
                font-style: normal;
                src: url(../fonts/special.ttf);
            }

            .test_class1 {
                font-weight: bold;
                color: #007D6E;
                font-family: 'Special' !important;
                text-align: center !important;
            }

            .test_class2 {
                font-weight: bold;
                color: #FF7D6E;
                text-align: center !important;
            }
    """

    func webView(_: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        print("start: \(String(describing: urlSchemeTask.request.url?.absoluteString))")

        guard let url = urlSchemeTask.request.url else {
            return
        }

        if url.absoluteString.contains("style.css") {
            let data = Data(testCss.utf8)

            urlSchemeTask.didReceive(URLResponse(url: url,
                                                 mimeType: "text/css",
                                                 expectedContentLength: data
                                                     .count,
                                                 textEncodingName: nil))
            urlSchemeTask.didReceive(data)
            urlSchemeTask.didFinish()
        }
    }

    func webView(_: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
        print("stop: \(String(describing: urlSchemeTask.request.url?.absoluteString))")
    }
}

在日志中,我可以看到本地资源触发了start方法:

代码语言:javascript
复制
start: Optional("localhost://../styles/style.css")
start: Optional("localhost://../fonts/special.ttf")

但是,如果我将localhost://<link href="localhost://../styles/style.css" type="text/css" rel="stylesheet"/>中删除,则根本不会触发start方法。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-05-18 21:20:43

由于要返回副本,因此对调用WKWebView.configuration的结果设置处理程序没有任何效果。相反,您应该创建WKWebViewConfiguration的一个新实例,在其上设置处理程序,然后将其传递给WKWebView.init(frame:, configuration:)

代码语言:javascript
复制
self.schemeHandler = MySchemeHandler()
self.webview = WKWebView(frame: .zero, configuration: {
    let webConfiguration = WKWebViewConfiguration()
    webConfiguration.setURLSchemeHandler(self.schemeHandler, 
                                         forURLScheme: "localhost")
    return webConfiguration
}())
票数 1
EN

Stack Overflow用户

发布于 2020-05-12 09:32:12

关于自iOS 10 WKWebview support AppCache以来我所理解的内容

试试这段代码

代码语言:javascript
复制
let webview: WKWebView
let config = WKWebViewConfiguration()
config.setValue(true, forKey: "_setOfflineApplicationCacheIsEnabled")
webview = WKWebView(frame: .zero, configuration: config)
票数 0
EN

Stack Overflow用户

发布于 2020-05-17 19:06:14

WKNavigationDelegate有一个函数来决定如何导航到一个页面,您可以在这里进行过滤和重定向。就像这样:

代码语言:javascript
复制
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    // you may need to use .linkActivated depending on how users are navigating
    if navigationAction.navigationType == .other  {
        if let request = navigationAction.request.url {
            if request.absoluteString.hasPrefix("https://somePrefix") {
                // for test
               // guard let localRedirect = URL.init(string: "https://google.com") else {
                guard let localRedirect = URL.init(string: "localhost://someUrl") else {
                    decisionHandler(.allow)
                    return
                }
                decisionHandler(.cancel)
                // for test
                // webView.load(URLRequest.init(url: URL.init(string: "https://www.google.com")!))
                webView.loadFileURL(localRedirect, allowingReadAccessTo: localRedirect.deletingLastPathComponent()) // delete last path component if you have other things that the page will load in that directory, like images or css
                return
            }
        }
    }
    decisionHandler(.allow)
}

我把导航到google作为一种测试,但是把代码留在了那里,这样人们就可以很容易地看到重定向是如何工作的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61673209

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档