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


項目地址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; } 
Aaron Swartz
Aaron Swartz

request的重寫定向,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; } 

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

- (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
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM