iOS 讓 WKWebView 支援 NSURLProtocol

來源:互聯網
上載者:User

標籤:是你   rip   私人api   origin   UI   註冊   handler   gem   結構   

 

iOS8以後,蘋果推出了新架構Webkit,提供了替換UIWebView的組件WKWebView。各種UIWebView的問題沒有了,速度更快了,佔用記憶體少了,一句話,WKWebView是App內部載入網頁的最佳選擇!我們做開發最關係的是記憶體問題,基本上網上所有的資料都在說WKWebview的記憶體佔用會更少,但是到底少了多少我這邊做了下測試,同樣是載入163的首頁

 使用UIWebView的記憶體  使用WKWebview的記憶體

從看出記憶體大概能最佳化百分之八十左右,而且從網頁的滑動上也確實有所改善。這麼明顯的效能提升但是蘋果並沒有完全放棄UIWebView也一定有他的道理,就拿本文要講的NSURLProtocol攔截請求來說,WKWebview的相容並不UIWebView好,還需要開發人員做一些操作。

WebKit源碼分析

由於WKWebview是基於webkit核心來做的,所以我們在使用的時候需要匯入一個這樣的東西。
#import <WebKit/WebKit.h>
通過這個我們可以猜到WKWebview中所有的請求以及一些邏輯肯定走的都是webkit裡面的東西,所以他對於網頁的載入之之類的操作也不會走系統本省的URL Loading System,這麼說來他的請求不能被NSURLProtocol攔截也是理所當然的了。不過WKWebview是否真的和NSURLProtocol一點關係都沒有還需要去研究,幸好webkit是開源的,github上很容易找到源碼(大小大概是1G多點的zip,花了我將近一天時間來看)。拉下代碼直接搜尋NSURLProtocol,看看有沒有有關的資訊

 搜尋結果
看來的確是有和NSURLProtocol有關係,後面通過斷點的調用棧中也找到了
+ [NSURLProtocol canInitWithRequest:]
這樣的字樣,再通過網上查一些資料也證實了我的猜想,其實WKWebview在一開始時候是會調用到NSURLProtocol中的入口方法canInitWithRequest的,但是就沒有然後了,也就是說WKWebview是和NSURLProtocol有一定關聯,只是在NSURLProtocol的入口處返回NO所以導致NSURLProtocol不接管WKWebview的請求。我們點進webkit源碼中的CustomProtocol可以看到,整體的結構我們都差不多,但是我注意到每個CustomProtocol的入口函數都有這樣一個判斷:
 入口函數1
 入口函數2
(粉色的可以暫時認定為是它內部的一個custom字串)通過這個可以猜想,WKWebview並不是不走NSURLProtocol,而是需要滿足他的一個規則,他才會在入口函數這裡返回YES來給你允許存取,這個規則便是你所請求的URL的Scheme要和它內部配置的CustomScheme相同。不過這裡有一個疑問,蘋果在使用webkit時候為什麼會把http/https這樣福士化的scheme過濾掉,看來他是不建議開發人員來使用NSURLProtocol。接下來我們來看這個CustomScheme,既然蘋果內部規定好的那麼一定能通過某種方式來註冊一個自己的scheme,實在不行就hook嘛。通過翻他的源碼發現最終都指向一句代碼
[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之後在調用該方法應該就可以了。通過他的源碼也進一步印證了我的猜想(他也是這麼寫的)


 webkit源碼具體實施

找到了方法就要去實施,不過因為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"];    }

 

值得注意
  • 關於私人API

因為WKBrowsingContextController和registerSchemeForCustomProtocol應該是私人的所以使用時候需要對字串做下處理,用加密的方式或者其他就可以了,實測可以過審核的。

 

第三方的庫

GitHub:NSURLProtocol-WebKitSupport

 

iOS 讓 WKWebView 支援 NSURLProtocol

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.