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

項目地址github:<a >HybirdWKWebVIew</a>

HybridNSURLProtocol

一個基于WKWebView的hybirde的容器。能攔截所有WKWKWebView的的css,js,png等網(wǎng)絡(luò)請求的demo
NSURLProtocol 子類,就可以對 app 內(nèi)所有的網(wǎng)絡(luò)請求進行:

[NSURLProtocol registerClass:[HybridNSURLProtocol class]]

可是在 WKWebView 中的請求卻完全不遵從這一規(guī)則,只是象征性+ (BOOL) canInitWithRequest:(NSURLRequest *)request 方法,之后的整個請求流程似乎就與 NSURLProtocol 完全無關(guān)了。

使我WKWebView 的一度認為請求不遵守NSURLProtocol協(xié)議,所以不走 NSURLProtocol。這個也是很苦擾我的問題。導致我們hybird的容器1.0也是是用UIWebVIew實現(xiàn)的。

但在蘋果放在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文件需要頻繁調(diào)用一個函數(shù),可以用static inline來聲明。在SDWebImage讀取內(nèi)存的緩存也用到這個聲明。
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 ))
{
//看看是否已經(jīng)處理過了,防止無限循環(huán)
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 ))
{
//看看是否已經(jīng)處理過了,防止無限循環(huán)
if ([NSURLProtocol propertyForKey:KHybridNSURLProtocolHKey inRequest:request])
return NO;
return YES;
}
return NO;
}

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

- (void)startLoading
{
NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
//給我們處理過的請求設(shè)置一個標識符, 防止無限循環(huán),
[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 >HybirdWKWebVIew</a>,對您有幫助,歡迎star。

有問題反饋

在使用中有任何問題,歡迎反饋給我,可以用以下聯(lián)系方式跟我交流

  • github:<a >LiuShuoyu</a>

接受啟發(fā)的作者的github

github:<a >Yeatse CC</a>
蘋果開發(fā)者文檔:<a >apple</a>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 對于目前UIWebView的離線緩存方式主要有如下幾種: 1.HTML5 , Manifest 最開始我的想法是使...
    lucifrom_long閱讀 3,293評論 2 7
  • 公司最近有個需求,去除h5頁面的廣告,最后實現(xiàn)的方式是后臺去過濾,移動端這里只需要攔截里面的一個css地址重定向就...
    態(tài)度哥閱讀 8,596評論 19 34
  • WKWebView 是蘋果在 WWDC 2014 上推出的新一代 webView 組件,用以替代 UIKit 中笨...
    Aiana閱讀 4,799評論 1 8
  • 對于運營人員來說,現(xiàn)在的工作越分越細。在經(jīng)過行業(yè)大牛和運營高手們的不斷完善和總結(jié)后,如今的運營工作籠統(tǒng)的可分為三大...
    諸葛io閱讀 4,982評論 1 11
  • 搞錯了,身體需要原料 人體的修復能力是不是非常的神奇?可以說是無所不能,人體內(nèi)的一切損傷都能通過修復而治愈,而且速...
    璀璨星空888閱讀 671評論 0 1

友情鏈接更多精彩內(nèi)容