Ios 使用WKWebView拦截请求

Ios 使用WKWebView拦截请求,ios,objective-c,Ios,Objective C,现在我使用的是UIWebView和NSURLProtocol的canInitWithRequest:,我可以截获所有请求并按我的要求处理 在新的WKWebView中没有这种方法,我也没有找到类似的方法 有人解决了这个问题吗?我只是盲目地猜测,因为我只带了我的windows电脑。通过阅读苹果开发人员文档,我收集到了一些信息,这些信息可能会引出一些关于如何解决这个问题的想法 基于 将委托属性设置为符合WKUIDelegate协议的对象,以跟踪web内容的加载 另外,我发现我们可以使用 弱变量navi

现在我使用的是
UIWebView
NSURLProtocol的
canInitWithRequest:
,我可以截获所有请求并按我的要求处理

在新的
WKWebView
中没有这种方法,我也没有找到类似的方法


有人解决了这个问题吗?

我只是盲目地猜测,因为我只带了我的windows电脑。通过阅读苹果开发人员文档,我收集到了一些信息,这些信息可能会引出一些关于如何解决这个问题的想法

基于

将委托属性设置为符合WKUIDelegate协议的对象,以跟踪web内容的加载

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

弱变量navigationDelegate:WKNavigationDelegate?{get set}

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

然后,在我们创建并设置自定义之后,我们将覆盖一些方法来截取我们可能要查找的内容。我发现这个部分有点有趣,因为它们接收到一个as参数。此外,你可能想浏览一下,看看是否有什么东西可以帮助我们实现我们的目标


顺便说一句,为了解决这个问题,我只是给出了一些想法,这些想法可能是100%错误的,因为我自己没有尝试过。

在iOS 11中,WKWebView提出了一个名为WKURLSchemeHandler的自定义方案处理程序,您可以使用它来拦截自定义事件。 有关更多信息,请查看此项目。

通过为
WKNavigationDelegate实现
decidePolicyFor:navigationAction:
方法,您可以在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 navigationAction.request.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)

}

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

  • 设置本地代理,使用WKNavigationDelegate

    -[ViewController webView:decidePolicyForNavigationAction:decisionHandler:]
    
    加载新请求并转发到本地服务器,在本地服务器端您可以执行一些操作(例如缓存)

  • 私有api。使用WKBrowsingContextController和自定义URL协议

    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"];
    }
    
  • 使用KVO获取系统http/https处理程序。(ios 11,*)

    所有这三种可能需要处理CORS和post正文的方法,都会覆盖更改浏览器的选项请求( ),您可以自定义http头来替换要剥离的帖子正文的http正文


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

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


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

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

  • 下载我们想要离线或在线呈现的网站的html以拦截请求
  • 将html放在用户的文档目录中,或将其放在存档中。但是我们应该知道html文件的路径
  • 将我们网站的所有js、cs、woff和字体与我们的基本html放在同一级别。我们需要在加载web视图时授予权限
  • 然后,我们必须向WKWebView注册我们自己的自定义处理程序方案。当wkwebview看到模式“myhandler webview”时,它将为您提供控制权,您将获得对“func webview(u”webview:wkwebview,start urlSchemeTask:WKURLSchemeTask)”委托实现的回调。您可以在这个委托中使用url,如第6点所述
  • 将文件方案转换为自定义方案(myhandler webview),然后使用WKWebView加载它
  • 实现以下WKURLSchemeHandler协议的方法,并处理WKURLSchemeTask的didReceiveResponse、didReceiveData和didFinish委托方法
  • 如果这个解释还不够,请告诉我

    目标c下面提到的例子


    我发现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”(
    location.href
    via javascript)和我的新方案,并由此引发了新的问题

    • 第一个问题是我的应用程序主要使用javascript, 而且
      document.cookie
      已停止工作。我正在使用Cordova 框架,所以我开发了一个插件来设置和获取cookie 替换document.cookie(我必须这样做,因为很明显,我 还需要设置http头(cookie)

    • 第二个问题是,我有很多“交叉起源”的问题
            let configuration = WKWebViewConfiguration();
              configuration.setURLSchemeHandler(self, forURLScheme: "myhandler-webview");
              webView = WKWebView(frame: view.bounds, configuration: configuration);
      
          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))
      
          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")
          }
      
      
      [conf setURLSchemeHandler:[CustomSchemeHandler new] forURLScheme:@"mynewscheme"];
      [conf setURLSchemeHandler:[CustomSchemeHandler new] forURLScheme:@"mynewschemesecure"];