iOS 提高WebView加載速度優(yōu)化方案

背景

開發(fā)中 WebView是很常用的技術(shù)方案 相比native 也有著很明顯的一些優(yōu)點(diǎn) 如:
1、實(shí)現(xiàn)安卓 iOS的復(fù)用
2、不用發(fā)版 動態(tài)更新頁面
3、節(jié)約native開發(fā)資源
......
但同時(shí) 也存在一些缺點(diǎn) 比較明顯的就是 加載速度比較慢 用戶體驗(yàn)不如native
所以 提高WebView的加載速度 提升用戶體驗(yàn)是避不開的問題

WebView加載速度優(yōu)化方案

一、WebView加載過程

想要優(yōu)化WebView加載速度 首先需要了解下網(wǎng)頁加載過程:
初始化webview -> 建立連接 -> 請求頁面 -> 下載數(shù)據(jù) -> 解析HTML -> 請求 js/css 資源 -> dom 渲染 -> 解析 JS 執(zhí)行 -> JS 請求數(shù)據(jù) -> 解析渲染 -> 下載渲染圖片

二、WebView優(yōu)化方案

1、提前初始化WebView
當(dāng)App打開時(shí),默認(rèn)是并不初始化瀏覽器內(nèi)核的;只有當(dāng)創(chuàng)建WebView實(shí)例的時(shí)候,才會創(chuàng)建WebView的基礎(chǔ)框架。
所以與瀏覽器不同,App中打開WebView的第一步并不是建立連接,而是啟動瀏覽器內(nèi)核。
提前初始化WebView可以節(jié)省這部分時(shí)間
提前初始化WebView分為兩種情況
① 剛啟動 還沒打開過WebView
可以初始化一個(gè)全局單例WebView 在APP剛啟動時(shí)就初始化 打開具體頁面是都復(fù)用這同一個(gè)WebView
這種方式存在的一個(gè)缺點(diǎn)就是如果用戶不打開WebView 會造成資源的浪費(fèi)
② 每次打開WebView時(shí) 如果之前沒有打開過 把當(dāng)前WebView存到內(nèi)存中 下次打開 直接取出來使用

根據(jù)url取出WebView

③ 對于確定性比較高的常用網(wǎng)頁 可以在啟動時(shí)直接保存到內(nèi)存 用戶打開時(shí)就可以直接顯示
根據(jù)url預(yù)加載WebView

2、預(yù)存HTML到本地
APP啟動時(shí)預(yù)存HTML到本地 打開WebView準(zhǔn)備加載HTML文件時(shí) WKURLSchemeHandler 攔截請求資源判斷資源是否和本地資源一致(一致則返回本地資源文件,不一致則請求網(wǎng)絡(luò)資源)
這種預(yù)存方式不能處理Http、Https等常規(guī)scheme 本地資源不存在時(shí) 請求網(wǎng)絡(luò)資源時(shí) 可能需要主動轉(zhuǎn)換成http/https

- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask {
    self.holdUrlSchemeTasks[urlSchemeTask.description] = @(YES);
    /// 優(yōu)先加載本地資源,本地沒有加載網(wǎng)絡(luò)資源化
    NSString *urlString = urlSchemeTask.request.URL.absoluteString;
    NSString *fileName = [urlString lastPathComponent];
    NSString *markStrig = [NSString stringWithFormat:@"%@/",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject];
    NSRange range = [urlString rangeOfString:markStrig];
    if (range.location != NSNotFound) {
        fileName = [urlString substringFromIndex:range.location];
    }
    NSString *mainBundlePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    NSString *htmlPath = [mainBundlePath stringByAppendingFormat:@"/"];
    NSString *filePath = [htmlPath stringByAppendingFormat:@"%@",fileName];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    /// 判斷文件是否存在
    if ([fileManager fileExistsAtPath:filePath]) {
        NSData *data = [NSData dataWithContentsOfFile:filePath];
        NSURLResponse *response = [[NSURLResponse alloc] initWithURL:urlSchemeTask.request.URL MIMEType:@"text/html" expectedContentLength:data.length textEncodingName:nil];
        [urlSchemeTask didReceiveResponse:response];
        [urlSchemeTask didReceiveData:data];
        [urlSchemeTask didFinish];
    } else {
        NSString *schemeUrl = urlSchemeTask.request.URL.absoluteString;
        if ([schemeUrl hasPrefix:@"qekj"]) {
            schemeUrl = [schemeUrl stringByReplacingOccurrencesOfString:@"qekj" withString:@"http"];
        }
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:schemeUrl]];
        NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSNumber *number = self.holdUrlSchemeTasks[urlSchemeTask.description];
                BOOL flag = number.boolValue;
                if (flag == NO) {
                    return;
                }
                if (response) {
                    [urlSchemeTask didReceiveResponse:response];
                } else {
                    NSURLResponse *response = [[NSURLResponse alloc] initWithURL:urlSchemeTask.request.URL MIMEType:@"未知類型" expectedContentLength:data.length textEncodingName:nil];
                    [urlSchemeTask didReceiveResponse:response];
                }
                [urlSchemeTask didReceiveData:data];
                if (error) {
                    [urlSchemeTask didFailWithError:error];
                } else {
                    [urlSchemeTask didFinish];
                }
            });
        }];
        [dataTask resume];
    }
}

處理自定義請求的方案

scheme替換

3、H5的css、js文件、圖片資源壓縮處理
這個(gè)需要H5同學(xué)幫助
H5的css、js文件壓縮方案
4、js、css、image等資源進(jìn)行離線緩存
WKWebView是有緩存策略模式的 通常情況下 我們是關(guān)閉緩存的 不然可能會出現(xiàn)數(shù)據(jù)不能及時(shí)更新的問題
如果開啟了本地緩存配置 建議H5鏈接增加一個(gè)類似于版本號的標(biāo)識 如果內(nèi)容有更新 則版本號+1 WKWebView的緩存是通過urlString來判斷是否需要重新加載 版本號變化 會認(rèn)為是新的網(wǎng)頁 則會重新加載
WKWebView默認(rèn)緩存策略

參考

支付寶移動端動態(tài)化方案實(shí)踐
Web離線技術(shù)
WKURLSchemeHandler協(xié)議優(yōu)化HTML加載速度
iOS WebView的性能、體驗(yàn)優(yōu)化
移動 H5 首屏秒開優(yōu)化方案探討
iOS html5使用緩存并及時(shí)更新方案總結(jié)

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

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

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