good

iOS 提高WebView加载速度优化方案

2023-04-17  本文已影响0人  马威明

背景

开发中 WebView是很常用的技术方案 相比native 也有着很明显的一些优点 如:
1、实现安卓 iOS的复用
2、不用发版 动态更新页面
3、节约native开发资源
......
但同时 也存在一些缺点 比较明显的就是 加载速度比较慢 用户体验不如native
所以 提高WebView的加载速度 提升用户体验是避不开的问题

WebView加载速度优化方案

一、WebView加载过程

想要优化WebView加载速度 首先需要了解下网页加载过程:
初始化webview -> 建立连接 -> 请求页面 -> 下载数据 -> 解析HTML -> 请求 js/css 资源 -> dom 渲染 -> 解析 JS 执行 -> JS 请求数据 -> 解析渲染 -> 下载渲染图片

二、WebView优化方案

1、提前初始化WebView
当App打开时,默认是并不初始化浏览器内核的;只有当创建WebView实例的时候,才会创建WebView的基础框架。
所以与浏览器不同,App中打开WebView的第一步并不是建立连接,而是启动浏览器内核。
提前初始化WebView可以节省这部分时间
提前初始化WebView分为两种情况
① 刚启动 还没打开过WebView
可以初始化一个全局单例WebView 在APP刚启动时就初始化 打开具体页面是都复用这同一个WebView
这种方式存在的一个缺点就是如果用户不打开WebView 会造成资源的浪费
② 每次打开WebView时 如果之前没有打开过 把当前WebView存到内存中 下次打开 直接取出来使用

根据url取出WebView
③ 对于确定性比较高的常用网页 可以在启动时直接保存到内存 用户打开时就可以直接显示
根据url预加载WebView
2、预存HTML到本地
APP启动时预存HTML到本地 打开WebView准备加载HTML文件时 WKURLSchemeHandler 拦截请求资源判断资源是否和本地资源一致(一致则返回本地资源文件,不一致则请求网络资源)
这种预存方式不能处理Http、Https等常规scheme 本地资源不存在时 请求网络资源时 可能需要主动转换成http/https
- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask {
    self.holdUrlSchemeTasks[urlSchemeTask.description] = @(YES);
    /// 优先加载本地资源,本地没有加载网络资源化
    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文件、图片资源压缩处理
这个需要H5同学帮助
H5的css、js文件压缩方案
4、js、css、image等资源进行离线缓存
WKWebView是有缓存策略模式的 通常情况下 我们是关闭缓存的 不然可能会出现数据不能及时更新的问题
如果开启了本地缓存配置 建议H5链接增加一个类似于版本号的标识 如果内容有更新 则版本号+1 WKWebView的缓存是通过urlString来判断是否需要重新加载 版本号变化 会认为是新的网页 则会重新加载
WKWebView默认缓存策略

参考

支付宝移动端动态化方案实践
Web离线技术
WKURLSchemeHandler协议优化HTML加载速度
iOS WebView的性能、体验优化
移动 H5 首屏秒开优化方案探讨
iOS html5使用缓存并及时更新方案总结

上一篇下一篇

猜你喜欢

热点阅读