美文网首页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