iOS WKWebView (NSURLProtocol)攔截js、css,圖片資源

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

HybridNSURLProtocol

一個基於WKWebView的hybirde的容器。能攔截全部WKWKWebView的的css,js,png等網絡請求的demo
NSURLProtocol 子類,就能夠對 app 內全部的網絡請求進行:html

[NSURLProtocol registerClass:[HybridNSURLProtocol class]]

但是在 WKWebView 中的請求卻徹底不聽從這一規則,只是象徵性+ (BOOL) canInitWithRequest:(NSURLRequest *)request 方法,以後的整個請求流程彷佛就與 NSURLProtocol 徹底無關了。git

使我WKWebView 的一度認爲請求不遵照NSURLProtocol協議,因此不走 NSURLProtocol。這個也是很苦擾個人問題。致使咱們hybird的容器1.0也是是用UIWebVIew實現的。github

但在蘋果放在gittub的CustomHTTPProtocol,明顯感受到WKWebview的也是遵照NSURLProtocol,要不也不會走+ (BOOL)canInitWithRequest:(NSURLRequest *)request;後來一個天天看博客和gittub的習慣幫助了我,找到一個大神的不久前開源庫。json

使用了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。下面是打印的請求的logsession

+ (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; } 
Aaron Swartz
Aaron Swartz

request的重寫定向,request的重寫定向,替換百度知道的logapp

+ (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; } 

這裏最好加上緩存判斷,加載本地離線文件, 這個直接簡單的例子。編輯器

- (void)startLoading { NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy]; //給咱們處理過的請求設置一個標識符, 防止無限循環, [NSURLProtocol setProperty:@YES forKey:KHybridNSURLProtocolHKey inRequest:mutableReqeust]; //這裏最好加上緩存判斷,加載本地離線文件, 這個直接簡單的例子。 if ([mutableReqeust.URL.absoluteString isEqualToString:sourIconUrl]) { NSData* data = UIImagePNGRepresentation([UIImage imageNamed:@"medlinker"]); NSURLResponse* response = [[NSURLResponse alloc] initWithURL:self.request.URL MIMEType:@"image/png" expectedContentLength:data.length textEncodingName:nil]; [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed]; [self.client URLProtocol:self didLoadData:data]; [self.client URLProtocolDidFinishLoading:self]; } else { NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; self.task = [session dataTaskWithRequest:self.request]; [self.task resume]; } } 

下面是代碼效果圖


 
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>

做者:劉小弟 連接:https://www.jianshu.com/p/4fc13d4d5607 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。
相關文章
相關標籤/搜索