使用WKWebView拦截请求

时间:2016-10-19 13:58:57

标签: ios objective-c

现在我正在使用canInitWithRequest:NSURLProtocol WKWebView我可以拦截所有请求并按照我想要的方式使用它。

在新的enum MyEnum { FIRST { @Override void foo() { //Do something } }, SECOND { @Override void foo() { //Do something else } }; abstract void foo(); } 这个方法中没有,我没有找到类似的东西。

有人解决了这个问题吗?

7 个答案:

答案 0 :(得分:1)

iOS 11中的

WKWebView提出了名为 WKURLSchemeHandler 的自定义方案处理程序,您可以使用它来拦截自定义事件。 有关更多信息,请查看此项目。 https://github.com/BKRApps/KRWebView

答案 1 :(得分:1)

您可以通过为decidePolicyFor: navigationAction:实现WKNavigationDelegate方法,在iOS 8.0以后的WKWebView上拦截请求。

 func webView(_ webView: WKWebView, decidePolicyFor 
       navigationAction: WKNavigationAction, 
       decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {

    //link to intercept www.example.com

    // navigation types: linkActivated, formSubmitted, 
    //                   backForward, reload, formResubmitted, other

    if navigationAction.navigationType == .linkActivated {
        if webView.url!.absoluteString == "http://www.example.com" {
            //do stuff

            //this tells the webview to cancel the request
            decisionHandler(.cancel)
            return
        }
    }

    //this tells the webview to allow the request
    decisionHandler(.allow)

}

答案 2 :(得分:1)

有很多方法可以实现拦截器请求。

  1. 设置本地代理,使用WKNavigationDelegate

    -[ViewController webView:decidePolicyForNavigationAction:decisionHandler:]
    

    加载新请求并转发到本地服务器,您可以在本地服务器端执行某些操作(例如缓存)。

  2. 私有api。使用WKBrowsingContextController和自定义URLProtocol

    Class cls = NSClassFromString(@"WKBrowsingContextController");
    SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");
    if ([(id)cls respondsToSelector:sel]) {
        // 把 http 和 https 请求交给 NSURLProtocol 处理
        [(id)cls performSelector:sel withObject:@"http"];
        [(id)cls performSelector:sel withObject:@"https"];
    }
    
  3. 使用KVO获取系统http / https处理程序。(ios 11,*)

    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    URLSchemeHandler *schemeHandler = [[URLSchemeHandler alloc] init];
    [configuration setURLSchemeHandler:schemeHandler forURLScheme:@"test"];
    NSMutableDictionary *handlers = [configuration valueForKey:@"_urlSchemeHandlers"];
    handlers[@"http"] = schemeHandler;
    handlers[@"https"] = schemeHandler;
    

    您可能需要用所有三种方式处理CORS和要剥离的正文,您覆盖更改浏览器的选项请求( Preflighted_requests),您可以自定义http标头以替换http正文以删除帖子正文。

答案 3 :(得分:1)

我知道我来晚了,但是我能够解决这个问题。我可以使用以下技巧来拦截每个请求,甚至您的http / https呼叫。我还可以跟踪从html到服务器的调用。我还可以使用它来呈现带有脱机内容的html。

  1. 下载我们要离线或在线呈现的网站的html,以拦截请求。
  2. 将html放置在用户的文档目录中,或将其放置在存档中。但是我们应该知道html文件的路径。
  3. 将您网站的所有js,cs,woff,字体都放置在与基本html相同的级别。加载网络视图时需要获得许可。
  4. 然后,我们必须向WKWebView注册我们自己的自定义处理程序方案。当wkwebview看到模式“ myhandler-webview”时,它将为您提供控制,并且您将获得回调到'func webView(_ webView:WKWebView,start urlSchemeTask:WKURLSchemeTask)'委托实现。您可以像在第6点中提到的那样在此委托中使用url。
      let configuration = WKWebViewConfiguration();
        configuration.setURLSchemeHandler(self, forURLScheme: "myhandler-webview");
        webView = WKWebView(frame: view.bounds, configuration: configuration);
  1. 将文件方案转换为自定义方案(myhandler-webview),然后使用WKWebView加载
    let htmlPath = Bundle.main.path(forResource: "index", ofType: "html")
    var htmlURL = URL(fileURLWithPath: htmlPath!, isDirectory: false)                    
    htmlURL = self.changeURLScheme(newScheme: "myhandler-webview", forURL: htmlURL)
    self.webView.load(URLRequest(url: htmlURL))
  1. 实施以下WKURLSchemeHandler协议方法并处理didReceiveResponse,didReceiveData,didFinish WKURLSchemeTask的委托方法。
    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        print("Function: \(#function), line: \(#line)")
        print("==> \(urlSchemeTask.request.url?.absoluteString ?? "")\n")

    // You can find the url pattern by using urlSchemeTask.request.url. and create NSData from your local resource and send the data using 3 delegate method like done below.
    // You can also call server api from this native code and return the data to the task.
    // You can also cache the data coming from server and use it during offline access of this html.
    // When you are returning html the the mime type should be 'text/html'. When you are trying to return Json data then we should change the mime type to 'application/json'.
    // For returning json data you need to return NSHTTPURLResponse which has base classs of NSURLResponse with status code 200. 

    // Handle WKURLSchemeTask delegate methods
        let url = changeURLScheme(newScheme: "file", forURL: urlSchemeTask.request.url!)

        do {
            let data = try Data(contentsOf: url)

            urlSchemeTask.didReceive(URLResponse(url: urlSchemeTask.request.url!, mimeType: "text/html", expectedContentLength: data.count, textEncodingName: nil))
            urlSchemeTask.didReceive(data)
            urlSchemeTask.didFinish()
        } catch {
            print("Unexpected error when get data from URL: \(url)")
        }
    }

    func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
        print("Function: \(#function), line: \(#line)")
        print("==> \(urlSchemeTask.request.url?.absoluteString ?? "")\n")
    }

让我知道这个解释是否还不够。

下面提到的客观c示例

intercepting request with wkwebview

答案 4 :(得分:1)

我发现这个问题在 5 年后仍然会引起好奇心,所以我描述了我是如何解决它的以及我面临的一些主要问题。 正如在此回答的许多人一样,我已经实施了 WKURLSchemeHandler 并使用了新方案。

首先,wkwebview 启动的 URL 不能是 HTTP(或 HTTPS),而是您的新方案之一。

示例

mynewscheme://your-server-application.com

在您的 WKWebViewConfiguration conf 中,我设置了处理程序:

[conf setURLSchemeHandler:[CustomSchemeHandler new] forURLScheme:@"mynewscheme"];
[conf setURLSchemeHandler:[CustomSchemeHandler new] forURLScheme:@"mynewschemesecure"];

CustomSchemeHandler 中,我实现了 webView:startURLSchemeTask:webView:stopURLSchemeTask:

在我的情况下,我检查请求是否针对我刚刚保存在本地的文件,否则我使用 http(或 https)更改实际协议(“mynewscheme 或“mynewschemesecure”),然后我自己提出请求。

此时我解决了“拦截问题”。

以这种新方式,我们在我的新方案中获得了 webview“位置”(location.href,通过 javascript),随之而来的是新的问题。

  • 第一个问题是我的应用程序主要使用 javascript, 并且 document.cookie 已停止工作。我正在使用科尔多瓦 框架,所以我开发了一个插件来设置和获取 cookie 替换 document.cookie(我必须这样做,因为,显然,我 也有 http 标头 set-cookie)。

  • 第二个问题是我有很多“跨域”问题,然后 我更改了相对网址中的所有网址(或使用新方案)

  • 第三个问题是浏览器自动处理服务器80端口 和 443,省略它们,但现在已经停止(可能是因为“不 http 位置”)。在我的服务器代码中,我必须处理这个问题。

写下这几行我承认这似乎是一个容易解决的问题,但我确保找到解决方法,如何解决它并与无限量的代码集成一直很困难。解决方案的每一步都对应着一个新问题。

答案 5 :(得分:0)

我盲目地猜测,因为我只有我的Windows电脑。通过阅读Apple Developer文档,我收集的信息可能会带来一些关于如何解决问题的想法。

基于WKWebView

  

将delegate属性设置为符合WKUIDelegate协议的对象,以跟踪Web内容的加载。

另外,我发现我们可以使用

设置navigationDelegate

weak var navigationDelegate: WKNavigationDelegate? { get set }

  

WKNavigationDelegate协议的方法可帮助您实现在Web视图接受,加载和完成导航请求的过程中触发的自定义行为。

然后在我们创建并设置自定义WKNavigationDelegate之后,我们将覆盖一些方法来拦截我们可能正在寻找的东西。我找到了一些感兴趣的Responding to Server Actions部分,因为他们收到WKNavigation作为参数。此外,您可能希望浏览WKNavigationActionWKNavigationResponse,看看是否有某些内容可能有助于我们实现目标。

顺便说一下,我只想提出一些想法,以便我们可以解决这个问题,这些想法可能100%错误,因为我自己没有尝试过。

答案 6 :(得分:0)

一个人可以使用WKURLSchemeHandler来拦截要加载到WKWebView中的每个请求, 唯一的缺点是您无法注册用于拦截的http或https方案,

解决方案是 用自定义方案网址(例如xyz://)替换您的http / https方案网址 例如https://google.com可以像xyz://google.com一样加载 现在,您将在WKURLSchemeHandler中获得一个回调,然后再次将其替换回https并以编程方式加载数据并调用urlSchemeTask.didReceive(response)

这样,每个https请求都会到达您的处理程序。