WKWebView 優(yōu)先加載本地資源包

公司新項(xiàng)目里面,主要是以原生作為框架,詳情頁面有web頁面負(fù)責(zé)展示笛园。iOS這邊是用WKWebView來加載web頁面,但是由于網(wǎng)絡(luò)環(huán)境和頁面復(fù)雜度的問題笨农,iOS 端和安卓 的web加載速度很慢褂乍。(客戶服務(wù)器域名的問題)
1、把所有web的資源包放到本地:問題依舊在
2桑涎、web頁面共有的資源包放到原生本地彬向,web頁面加載時(shí),先判斷本地是否有資源包攻冷,優(yōu)先加載本地資源包娃胆。
參考:https://segmentfault.com/a/1190000005732602
https://blog.csdn.net/u011154007/article/details/68068172
https://blog.csdn.net/hanhailong18/article/details/79394856
核心原理:
對(duì)H5請(qǐng)求進(jìn)行攔截,如果本地已經(jīng)有對(duì)應(yīng)的靜態(tài)資源文件等曼,則直接加載里烦,這樣就能達(dá)到“秒開”webview的效果。

對(duì)于iOS而言禁谦,這就需要用到NSURLProtocol這個(gè)神器了胁黑。接下來,分析下它到底是什么東西州泊,我們?cè)趺蠢盟_(dá)到上述效果丧蘸。

NSURLProtocol:它能夠讓你去重新定義蘋果的URL加載系統(tǒng)(URL Loading System)的行為,URL Loading System里有許多類用于處理URL請(qǐng)求遥皂,比如NSURL力喷,NSURLRequest刽漂,NSURLConnection和NSURLSession等。當(dāng)URL Loading System使用NSURLRequest去獲取資源的時(shí)候弟孟,它會(huì)創(chuàng)建一個(gè)NSURLProtocol子類的實(shí)例贝咙,你不應(yīng)該直接實(shí)例化一個(gè)NSURLProtocol,NSURLProtocol看起來像是一個(gè)協(xié)議拂募,但其實(shí)這是一個(gè) 類庭猩,而且必須使用該類的子類,并且需要被注冊(cè)没讲。

換句話說眯娱,NSURLProtocol能攔截所有當(dāng)前app下的網(wǎng)絡(luò)請(qǐng)求,并且能自定義地進(jìn)行處理爬凑。
直接上代碼

#import "NSURLProtocolCustom.h"
#import <CoreFoundation/CoreFoundation.h>
#import <MobileCoreServices/MobileCoreServices.h>
static NSString* const FilteredKey = @"FilteredKey";

@interface NSURLProtocolCustom()<NSURLConnectionDataDelegate>
@property(nonatomic, strong)NSURLConnection *coonection;
@end


@implementation NSURLProtocolCustom
//這個(gè)方法的作用是判斷當(dāng)前protocol是否要對(duì)這個(gè)request進(jìn)行處理(所有的網(wǎng)絡(luò)請(qǐng)求都會(huì)走到這里徙缴,所以我們只需要對(duì)我們產(chǎn)生的request進(jìn)行處理即可)。
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
    NSString *extension = request.URL.pathExtension;
    BOOL isSource = [@[@"png", @"jpeg", @"gif", @"jpg", @"js", @"css"] indexOfObjectPassingTest:^BOOL(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        return [extension compare:obj options:NSCaseInsensitiveSearch] == NSOrderedSame;
    }] != NSNotFound;
    return [NSURLProtocol propertyForKey:FilteredKey inRequest:request] == nil && isSource;
}
//可以對(duì)request進(jìn)行預(yù)處理嘁信,比如對(duì)header加一些東西什么的于样,我們這里沒什么要改的,所以直接返回request就好了潘靖。
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
    return request;
}
//我們這里需要做一件事穿剖,就是自己拼裝httpResponse,并且返回給url load system卦溢,然后到了webview那一層糊余,會(huì)收到response,對(duì)于webview而言单寂,加載本地和走網(wǎng)絡(luò)拿到的response是完全一樣的贬芥。所以上述代碼展示了如何拼裝一個(gè)httpResponse,當(dāng)組裝完成后宣决,需要調(diào)用self.client將數(shù)據(jù)傳出去蘸劈。
- (void)startLoading
{
    //fileName 獲取web頁面加載的資源包文件名(js  css等)
    NSString *fileName = [super.request.URL.absoluteString componentsSeparatedByString:@"/"].lastObject;

    //這里是獲取本地資源路徑 如:png,js等
    NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
    NSLog(@"fileName is %@ path=%@",fileName,path);
    if (!path) {
       //本地資源包沒有所需的文件,加載網(wǎng)絡(luò)請(qǐng)求
        NSMutableURLRequest *newrequest = [self.request mutableCopy];
        newrequest.allHTTPHeaderFields = self.request.allHTTPHeaderFields;
        [NSURLProtocol setProperty:@YES forKey:FilteredKey inRequest:newrequest];
        self.coonection = [NSURLConnection connectionWithRequest:newrequest delegate:self];
        return;
    }
    //根據(jù)路徑獲取MIMEType
    CFStringRef pathExtension = (__bridge_retained CFStringRef)[path pathExtension];
    CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, NULL);
    CFRelease(pathExtension);
    
    //The UTI can be converted to a mime type:
    NSString *mimeType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType);
    if (type != NULL)
        CFRelease(type);
    
    //加載本地資源
    NSData *data = [NSData dataWithContentsOfFile:path];
    [self sendResponseWithData:data mimeType:mimeType];
}

- (void)stopLoading
{
    [self.coonection cancel];
    NSLog(@"stopLoading, something went wrong!");
}

- (void)sendResponseWithData:(NSData *)data mimeType:(nullable NSString *)mimeType
{
    NSMutableDictionary *header = [[NSMutableDictionary alloc]initWithCapacity:2];
    NSString *contentType = [mimeType stringByAppendingString:@";charset=UTF-8"];
    header[@"Content-Type"] = contentType;
    header[@"Content-Length"] = [NSString stringWithFormat:@"%lu",(unsigned long) data.length];
    NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc]initWithURL:self.request.URL statusCode:200 HTTPVersion:@"1.1" headerFields:header];
    // 這里需要用到MIMEType
    //NSURLResponse *response = [[NSURLResponse alloc] initWithURL:super.request.URL MIMEType:mimeType expectedContentLength:-1 textEncodingName:nil];
    
    //硬編碼 開始嵌入本地資源到web中
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
    [[self client] URLProtocol:self didLoadData:data];
    [[self client] URLProtocolDidFinishLoading:self];
}
#pragma 代理
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    [self.client URLProtocol:self didLoadData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
    [self.client URLProtocolDidFinishLoading:self];
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    [self.client URLProtocol:self didFailWithError:error];
}

@end

目前尊沸,關(guān)于攔截并加載本地資源包的代碼操作就沒有了威沫,剩下還有一步,就是在加載web頁面之前洼专,對(duì)自定義的NSURLProtocol 進(jìn)行注冊(cè)棒掠,使上面的代碼實(shí)現(xiàn)對(duì)資源的攔截

-(void)setNSURLProtocolCustom{
    //注冊(cè)
    [NSURLProtocol registerClass:[NSURLProtocolCustom class]];
    //實(shí)現(xiàn)攔截功能,這個(gè)是核心
    Class cls = NSClassFromString(@"WKBrowsingContextController");
    SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");
    if ([(id)cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [(id)cls performSelector:sel withObject:@"http"];
        [(id)cls performSelector:sel withObject:@"https"];
#pragma clang diagnostic pop
    }
}

結(jié)語:之前單純加載web頁面的時(shí)候屁商,加載時(shí)間基本都是在兩秒以上句柠,現(xiàn)在基本控制在兩秒以內(nèi)了 。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棒假,一起剝皮案震驚了整個(gè)濱河市溯职,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帽哑,老刑警劉巖谜酒,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異妻枕,居然都是意外死亡僻族,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門屡谐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來述么,“玉大人,你說我怎么就攤上這事愕掏《让兀” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵饵撑,是天一觀的道長剑梳。 經(jīng)常有香客問我,道長滑潘,這世上最難降的妖魔是什么垢乙? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮语卤,結(jié)果婚禮上追逮,老公的妹妹穿的比我還像新娘。我一直安慰自己粹舵,他們只是感情好钮孵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著齐婴,像睡著了一般油猫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柠偶,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天情妖,我揣著相機(jī)與錄音,去河邊找鬼诱担。 笑死毡证,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蔫仙。 我是一名探鬼主播料睛,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了恤煞?” 一聲冷哼從身側(cè)響起屎勘,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎居扒,沒想到半個(gè)月后概漱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡喜喂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年瓤摧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玉吁。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡照弥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出进副,到底是詐尸還是另有隱情这揣,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布敢会,位于F島的核電站曾沈,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鸥昏。R本人自食惡果不足惜塞俱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吏垮。 院中可真熱鬧障涯,春花似錦、人聲如沸膳汪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽遗嗽。三九已至粘我,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間痹换,已是汗流浹背征字。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留娇豫,地道東北人匙姜。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像冯痢,于是被迫代替她去往敵國和親氮昧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子框杜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)袖肥,斷路器咪辱,智...
    卡卡羅2017閱讀 134,661評(píng)論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,167評(píng)論 25 707
  • 今天起了個(gè)大早,趕了個(gè)晚集昭伸。等了半小時(shí)梧乘,都不見206的蹤影。索性走路到幼兒園庐杨,趕9:20的趟…蟲子說,背著書包夹供,他...
    溦歷閱讀 182評(píng)論 0 0
  • 【0615我在悅讀】凡楚 2018年第93次打卡灵份, 書名:書都不會(huì)讀,你還想成功 作者:二志成哮洽、鄭會(huì)一 篇目:p1...
    凡楚_929d閱讀 123評(píng)論 0 0
  • 怎樣達(dá)到雙贏填渠? 做到兩點(diǎn)一是做好自己,使自己成為獨(dú)立鸟辅、有安全感氛什、有原則的人。二是避免被競爭想法和攀比思想左右匪凉。 另...
    徐慧棣閱讀 187評(píng)論 0 0