以前寫過一篇文章是關於基於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應該是私有的因此使用時候須要對字符串作下處理,用加密的方式或者其餘就能夠了,實測能夠過審覈的。個人文章簡書和掘金同步更新測試