美文网首页iOS程序犭袁iOS精英班JS 与 iOS
iOS WKWebView (NSURLProtocol)拦截j

iOS WKWebView (NSURLProtocol)拦截j

作者: 刘小弟 | 来源:发表于2017-01-19 16:11 被阅读4867次

    项目地址github:<a href="https://github.com/LiuShuoyu/HybirdWKWebVIew/">HybirdWKWebVIew</a>

    HybridNSURLProtocol

    一个基于WKWebView的hybirde的容器。能拦截所有WKWKWebView的的css,js,png等网络请求的demo
    NSURLProtocol 子类,就可以对 app 内所有的网络请求进行:

    [NSURLProtocol registerClass:[HybridNSURLProtocol class]]
    
    

    可是在 WKWebView 中的请求却完全不遵从这一规则,只是象征性+ (BOOL) canInitWithRequest:(NSURLRequest *)request 方法,之后的整个请求流程似乎就与 NSURLProtocol 完全无关了。

    使我WKWebView 的一度认为请求不遵守NSURLProtocol协议,所以不走 NSURLProtocol。这个也是很苦扰我的问题。导致我们hybird的容器1.0也是是用UIWebVIew实现的。

    但在苹果放在gittub的CustomHTTPProtocol,明显感觉到WKWebview的也是遵守NSURLProtocol,要不也不会走+ (BOOL)canInitWithRequest:(NSURLRequest *)request;后来一个每天看博客和gittub的习惯帮助了我,找到一个大神的不久前开源库。

    使用了WKBrowsingContextController和registerSchemeForCustomProtocol。 通过反射的方式拿到了私有的 class/selector。通过kvc取到browsingContextController。通过把注册把 http 和 https 请求交给 NSURLProtocol 处理。

    [NSURLProtocol wk_registerScheme:@"http"];
    [NSURLProtocol wk_registerScheme:@"https"];
    

    下面直接上源代码吧

    //FOUNDATION_STATIC_INLINE 属于属于runtime范畴,你的.m文件需要频繁调用一个函数,可以用static inline来声明。在SDWebImage读取内存的缓存也用到这个声明。
    FOUNDATION_STATIC_INLINE Class ContextControllerClass() {
    static Class cls;
    if (!cls) {
    cls = [[[WKWebView new] valueForKey:@"browsingContextController"] class];
    }
    return cls;
    }
    
    FOUNDATION_STATIC_INLINE SEL RegisterSchemeSelector() {
    return NSSelectorFromString(@"registerSchemeForCustomProtocol:");
    }
    
    FOUNDATION_STATIC_INLINE SEL UnregisterSchemeSelector() {
    return NSSelectorFromString(@"unregisterSchemeForCustomProtocol:");
    }
    
    @implementation NSURLProtocol (WebKitSupport)
    
    + (void)wk_registerScheme:(NSString *)scheme {
    Class cls = ContextControllerClass();
    SEL sel = RegisterSchemeSelector();
    if ([(id)cls respondsToSelector:sel]) {
    // 放弃编辑器警告
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [(id)cls performSelector:sel withObject:scheme];
    #pragma clang diagnostic pop
    }
    }
    
    + (void)wk_unregisterScheme:(NSString *)scheme {
    Class cls = ContextControllerClass();
    SEL sel = UnregisterSchemeSelector();
    if ([(id)cls respondsToSelector:sel]) {
    // 放弃编辑器警告
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [(id)cls performSelector:sel withObject:scheme];
    #pragma clang diagnostic pop
    }
    }
    
    

    注册后,客户端所有请求走+ (BOOL)canInitWithRequest:(NSURLRequest *)request。下面是打印的请求的log

    + (BOOL)canInitWithRequest:(NSURLRequest *)request
    {
    NSLog(@"request.URL.absoluteString = %@",request.URL.absoluteString);
    NSString *scheme = [[request URL] scheme];
    if ( ([scheme caseInsensitiveCompare:@"http"]  == NSOrderedSame ||
    [scheme caseInsensitiveCompare:@"https"] == NSOrderedSame ))
    {
    //看看是否已经处理过了,防止无限循环
    if ([NSURLProtocol propertyForKey:KHybridNSURLProtocolHKey inRequest:request])
    return NO;
    return YES;
    }
    return NO;
    }
    
    
    WechatIMG1.png WechatIMG2.jpeg

    项目地址:

    github:<a href="https://github.com/LiuShuoyu/HybirdWKWebVIew/">HybirdWKWebVIew</a>,对您有帮助,欢迎star。

    有问题反馈

    在使用中有任何问题,欢迎反馈给我,可以用以下联系方式跟我交流

    • github:<a href="https://github.com/LiuShuoyu/">LiuShuoyu</a>

    接受启发的作者的github

    github:<a href="https://github.com/yeatse/">Yeatse CC</a>
    苹果开发者文档:<a href="https://developer.apple.com/library/content/samplecode/CustomHTTPProtocol/Introduction/Intro.html/">apple</a>

    相关文章

      网友评论

      • MTDeveloper:为什么只能拦截到一次js/css文件?有缓存就拦截不到了,清缓存后 才行,怎么才能每次加载就能拦截到
      • 小苏羿:该方案有严重问题,会造成js的post请求body参数被清空,js页面无法通过post请求传递参数的问题。。。。我还真的遇到了 请问有没解决方案呢?
      • 拔山河:该方案有严重问题,会造成js的post请求body参数被清空,js页面无法通过post请求传递参数的问题。问题定位参照文章《【腾讯Bugly干货分享】WKWebView 那些坑》https://blog.csdn.net/tencent_bugly/article/details/54668721/。自定义URL schemes拦截才是完美解决方案。具体参照文章:《WKWebView采用HybridNSURLProtocol协议拦截图片等资源预加载》https://blog.csdn.net/jia12216/article/details/82219836
        小松松先生:谢谢分享!
      • rockyMJ:替换js,css成功后,但是h5页面发送的网络请求后台收不到,是因为拦截了吗?
        rockyMJ:@拔山河 谢谢
        拔山河:js的post请求body参数被清空,js页面无法通过post请求传递参数的问题。问题定位参照文章《【腾讯Bugly干货分享】WKWebView 那些坑》https://blog.csdn.net/tencent_bugly/article/details/54668721/。
      • 消失的BUG:望回复 求解
      • 消失的BUG:我遇到的问题是。h5加载完成以后 h5之后里面的请求 被修改了 导致后台 拿不到数据
        消失的BUG:没解决呢,这是wk的坑,要么使用get请求,要么h5需要发送的post请求让你来发
        rockyMJ:里面的http请求的body是nil.不知道为什么
        rockyMJ:哥们,我的也是 解决了吗?
      • CRAZYBADAM:给力,解决了
      • MTDeveloper:在你说的那个方法里拦截不到js和css呀
        MTDeveloper:是怎么回事?
      • c96787cb33a7:之前用了这个方法一直没问题,今天发现换了一个链接WK一直在加载
      • benlue:请受小弟一拜, 解决了我的大问题
      • 逸小苼:加载https网页,注册了拦截test协议拦截该网页内的自定义协议资源,test://demo.js,拦截不到app这个协议呀,求教
        刘小弟:@逸小苼 我们后期用协议, js调native的,native来实现网络请求。
        逸小苼:@宋大北 改用UIWebView了,WKWebView拦截的POST请求会丢失参数。
        d62c9a9ca0ed:大佬,我们最近也碰到了这个问题,请问你最后是怎么解决的?
      • 无声落叶:您好,我用canInitWithRequest方法做了某个页面简单的拦截,通过日志发现好像有"间歇性"问题(可能是自身原因)。多次重新打包、debug发现,只有第一次打包的时候canInitWithRequest才能截取到页面所需的css、js、png等资源文件。
        无声落叶:@刘小弟 谢谢,我知道怎么处理了。
        刘小弟:@无声落叶 WK内部缓存机制,只有第一次才加载css、js、png等资源文件。
      • 5ec1da87f063:意思是 WKWebView 是支持 NSURLProtocol的?
      • d0b60a301eeb:硕总监就是厉害呀
      • 木目心:
        这种方式会导致Webview中发送的POST形式的请求body为空,这个怎么解决呢?
        贵州一哥:@刘小弟 我用原生请求都不行
        刘小弟:@猪猪行天下 body为空, 目前请求可用Native的代发,来解决body的问题。 不过后期代码会比较聚合
        猪猪行天下:问下你解决body为空的问题了吗?
      • c96787cb33a7:你好,我的项目有用了这个方法将请求的图片换成本地的图片,但是有些网页能够显示本地的图片,有些就不能够显示,请问有什么原因吗?
        刘小弟:@luy丶z 加我微信哈。沟通方便些476804765
        c96787cb33a7:@刘小弟 有的
        刘小弟:@luy丶z 你好, 你看下是截到URL是否是图片URL。 你把你所有图片的URL的打印出来看看。
      • 刘小弟:项目中Hybird容器升级到WKWebView各种坑 http://www.jianshu.com/p/cbe38ba06e2e
      • 汉秋:达平哥,遇见你了啊
        刘小弟:@汉秋 哈哈,有缘呦。你怎么知道是我。
      • 2677e3feb221:请问下楼主,这种方式做wkwebview的拦截,审核不会有影响吗?
        刘小弟:@xiaohei_spring 可以的哈
      • 7f8d025fa7db:66666 终于找到咯。是我想要Demo
        2677e3feb221:请问下楼主,这种方式做wkwebview的拦截,审核不会有影响吗?
        刘小弟:@蜂小蜜 谢谢。

      本文标题:iOS WKWebView (NSURLProtocol)拦截j

      本文链接:https://www.haomeiwen.com/subject/rzuibttx.html