美文网首页good
iOS 提高WebView加载速度优化方案

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

作者: 马威明 | 来源:发表于2023-04-17 20:07 被阅读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使用缓存并及时更新方案总结

    相关文章

      网友评论

        本文标题:iOS 提高WebView加载速度优化方案

        本文链接:https://www.haomeiwen.com/subject/wodcjdtx.html