以前写过一篇文章是关于基于NSURLProtocol作的DNS解析,其中对NSURLProtocol也有了简单的介绍,咱们都知道他能够拦截全部基于URL Loading System 中的请求,可是对于WKWebview里面所发出的请求即便他是http/https 也无能为力,先来简单的了解下WKWebView.javascript
iOS8之后,苹果推出了新框架Webkit,提供了替换UIWebView的组件WKWebView。各类UIWebView的问题没有了,速度更快了,占用内存少了,一句话,WKWebView是App内部加载网页的最佳选择!咱们作开发最关系的是内存问题,基本上网上全部的资料都在说WKWebview的内存占用会更少,可是到底少了多少我这边作了下测试,一样是加载163的首页
java
因为WKWebview是基于webkit内核来作的,因此咱们在使用的时候须要导入一个这样的东西。git
#import <WebKit/WebKit.h>复制代码
经过这个咱们能够猜到WKWebview中全部的请求以及一些逻辑确定走的都是webkit里面的东西,因此他对于网页的加载之之类的操做也不会走系统本省的URL Loading System,这么说来他的请求不能被NSURLProtocol拦截也是理所固然的了。不过WKWebview是否真的和NSURLProtocol一点关系都没有还须要去研究,幸亏webkit是开源的,github上很容易找到源码(大小大概是1G多点的zip,花了我将近一天时间来看)。拉下代码直接搜索NSURLProtocol,看看有没有有关的信息
github
+ [NSURLProtocol canInitWithRequest:]复制代码
这样的字样,再经过网上查一些资料也证明了个人猜测,其实WKWebview在一开始时候是会调用到NSURLProtocol中的入口方法canInitWithRequest的,可是就没有而后了,也就是说WKWebview是和NSURLProtocol有必定关联,只是在NSURLProtocol的入口处返回NO因此致使NSURLProtocol不接管WKWebview的请求。咱们点进webkit源码中的CustomProtocol能够看到,总体的结构咱们都差很少,可是我注意到每一个CustomProtocol的入口函数都有这样一个判断:
web
[WKBrowsingContextController registerSchemeForCustomProtocol:testScheme];复制代码
方法实现为框架
+ (void)registerSchemeForCustomProtocol:(NSString *)scheme
{
WebProcessPool::registerGlobalURLSchemeAsHavingCustomProtocolHandlers(scheme);
}复制代码
void WebProcessPool::registerGlobalURLSchemeAsHavingCustomProtocolHandlers(const String& urlScheme)
{
if (!urlScheme)
return;
globalURLSchemesWithCustomProtocolHandlers().add(urlScheme);
for (auto* processPool : allProcessPools())
processPool->registerSchemeForCustomProtocol(urlScheme);
}复制代码
经过方法名字能够看出这个就是那个向webkit注册CustomScheme的方法,只要咱们在注册完咱们本身的CustomProtocol以后在调用该方法应该就能够了。经过他的源码也进一步印证了个人猜测(他也是这么写的)
函数
找到了方法就要去实施,不过由于registerSchemeForCustomProtocol是WKBrowsingContextController的类方法,因此只能用WKBrowsingContextController去调用,可是在webkit的头文件发现WKBrowsingContextController并无开放出来,因此咱们采用NSClassFromString和NSSelectorFromString方法来拿到类和对应的方法,总体代码以下源码分析
//注册本身的protocol
[NSURLProtocol registerClass:[CustomProtocol class]];
//建立WKWebview
WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc] init];
WKWebView * wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) configuration:config];
[wkWebView loadRequest:webViewReq];
[self.view addSubview:wkWebView];
//注册scheme
Class cls = NSClassFromString(@"WKBrowsingContextController");
SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");
if ([cls respondsToSelector:sel]) {
// 经过http和https的请求,同理可经过其余的Scheme 可是要知足ULR Loading System
[cls performSelector:sel withObject:@"http"];
[cls performSelector:sel withObject:@"https"];
}复制代码
实现效果。我将网页中全部的图片替换成了柴犬图片
性能
#####值得注意
由于WKBrowsingContextController和registerSchemeForCustomProtocol应该是私有的因此使用时候须要对字符串作下处理,用加密的方式或者其余就能够了,实测能够过审核的。个人文章简书和掘金同步更新测试