iOS学习开发iOS开发技术收集 -- 完整应用及开发技巧篇iOS开发技术收集 -- 理论知识及学习资料篇

WKWebView 加载速度优化

2019-06-06  本文已影响2人  忆辰念家

因为H5的存在可以快速发布,不受审核影响的特点。目前存在很多公司,对于一些尝试性的功能,会优先采用H5来实现。甚至有些公司为了节省用人成本,直接在原生APP的壳子里完全嵌入H5页面。但是H5的体验比起原生来还是差了挺多的,那么怎么优化就成为一个需要解决的问题了。

首先,要先研究一下为啥H5的体检比较差,只有知道问题所在,才能更好的解决问题。H5页面给人直观上的感觉的就是加载的速度太慢,常常存在一段时间的空白情况。

那么为啥会存在这样的情况的,我们可以了解一下,H5的加载过程干了些啥东西。

初始化 webview -> 请求页面 -> 下载数据 -> 解析HTML -> 请求 js/css 资源 -> dom 渲染 -> 解析 JS 执行 -> JS 请求数据 -> 解析渲染 -> 下载渲染图片

哇塞,好大一堆事情,辛苦了。那么那些方面我们可以进行优化呢,这里就得看看为了解决这个问题而掉光头发的老前辈们的想法了。

方法很多,本文就介绍的方法就是要怎么减少网络请求从而提升H5的加载速度。

存在原生开发经验的同志都知道 WebView 加载H5的方式存在两种,一种是加载HTMLString,而另外一种就是加载url地址喽。本文就从这两方面来解读。

加载HTMLString

先奉上代码再做解释。

let htmlContent = "<p>我们都知道有些食物能治病,但如果吃不对,它们也能致病。有些食物,对于我们一般人来说,有着滋补的功效,但是对于高血压患者,它们最好别碰!<span >高血压的“三大杀手”</span></p><h1>1、韭 菜</h1><p>韭菜也具有发散性,有温肾助阳的功效。而大多数高血压患者属于阴虚体质,燥热、阳火过盛,多吃韭菜不但不利于血压控制,反而会加重病情。</p><p>2、猪 肝</span></p><p>猪肝中胆固醇含量很高,患有高血压、冠心病、肥胖症及血脂高的人忌食猪肝。</p><p><span >3、鸡 汤</span></p><p>鸡汤的营养价值很高,而多喝鸡汤又会使胆固醇和血压增高。因此,鸡汤不能盲目地作为病人的营养品,特别是患有高血压的人,不宜喝鸡汤。否则只会进一步加重病情,对身体有害无益。</p><p><br></p><blockquote> <span >除了上面三种美食,下面这些东西高血压患者也要少碰。</span></blockquote><p><span >1、味 精</span></p><p>研究表明,味精的主要成分是谷氨酸钠,如果平时钠的含量已经达到阈值,再多吃味精,显然会增高钠的摄入量,从而不利于高血压的控制。</p><p><span >2、“隐 形 盐”</span></p><p>酱油、黄酱、腐乳等调味脂高的人忌食猪肝。</p><p><span >3、鸡 汤</span></p><p>鸡汤的营养价值很高,而多喝鸡汤又会使胆固醇和血压增高。因此,鸡汤不能盲目地作为病人的营养品,特别是患有高血压的人,不宜喝鸡汤。否则只会进一步加重病情,对身体有害无益。</p><p><br></p><blockquote> <span >除了上面三种美食,下面这些东西高血压患者也要少碰。</span></blockquote><p><span >1、味 精</span></p><p>研究表明,味精的主要成分是谷氨酸钠,如果平时钠的含量已经达到阈值,再多吃味精,显然会增高钠的摄入量,从而不利于高血压的控制。</p><p><span >2、“隐 形 盐”</span></p><p>酱油、黄酱、腐乳等调味\\345\\223品含盐量高;腊肉、奶酪、火腿、榨菜也都含盐;话梅、薯片、椒盐花生等零食均是含盐食物。买食品时看下食品包装上的营养成分表,“NRV%”超过30%就要少买少吃。</p><p><br></p><p><span >3、浓 茶</span></p><p>高血压病患者忌饮浓茶,尤其是忌饮浓烈红茶。因为红茶中所含的茶碱最高,可以引起大脑兴奋、不安、失眠、心悸等不适,从而使血压上升。</p><p><span >4、饮 酒</span></p><p>研究表明,饮酒在一般情况下会让血压升高4到8毫米汞柱。大量、长期饮酒,更易诱发动脉硬化,加重高血压。因此,高血压患者应戒酒。</p><p>5、吸 烟</span></p><p>香烟中的尼古丁,能刺激心脏和血管,使血压升高,加速动脉粥样硬化的形成。高血压被称为“安静的杀手”,患病后可能没有症状,而大多数患者可能只有到体检的那天才知道自己得了高血压。</p><blockquote> <span >帮你“稳住”血压</span></blockquote><p><span >1、定期监测血压</span></p><p>家庭自测血压正常值应小于135/85毫米汞柱,非同一天测量、3次超标需及时就医。</p><p><br></p><p><span >2、清淡饮食</span></p><p>饮食上不要大鱼大肉,注意清淡一些,每天盐摄入量控制在6克以下,吃油量在25~30克之间。猪肉等红肉、高盐的腌制食品应限量,甜食和糖果尽量不吃。</p><p><span >3、控制体重</span></p><p>体质指数【BMI=体重(千克)÷身高的平方(米的平方)】尽可能保持在19~24之间。</p><p><span >4、补点钾</span></p><p>适当吃些钾含量较高的食物有助于降低血压,还能降低高血压患者发生中风的风险。建议多吃香蕉、桃子、西瓜、红薯、菠菜、芹菜、土豆等。</p><p><span >5、增加镁、钙的摄入</span></p><p>镁有助于血管扩张,补充镁的最安全方法是通过含镁丰富的食物来补充。富含镁的食物有各种干豆、鲜豆、香菇、菠菜、桂圆、豆芽等。钙不足也可使血压升高,钙增加会使血压下降。富含钙的食物有奶类、豆类等。</p><p><span >6、吃点醋</span></p><p>醋是通过抑制血管紧张素转换酶生成而直接抑制血压升高的。醋还具有利尿作用和有利于身体对钙的吸收,这些作用对降低血压有一定帮助。</p><p><span >7、抽空多走走</span></p><p>慢走5分钟、散步5分钟交替进行,可软化血管。建议利用零散时间锻炼,如出门少开车,多步行一会;养成晚饭后溜达一圈的习惯。</p><p><br></p><blockquote> <span >喝喝茶调血压</span></blockquote><p><span >葛 根 茶</span></p><p>葛根具有改善脑部血液循环之效,对因高血压引起的头痛、眩晕、耳鸣及腰酸腿痛等症状有较好的缓解功效。经常饮用葛根茶对治疗高血压具有明显的疗效。</p><p>做法:将葛根洗净切成薄片,每天30克,加水煮沸后当茶饮用。</p><p><span >莲子心茶</span></p><p>莲子心其味清苦,可以祛五脏之火,具有极好的降压去脂的功效。</p><p>做法:取莲子心12克,开水冲泡代茶饮,每天早晚各1次。</p><p><span >高血压是个终身性疾病,需要终身用药控制。但是除合理用药外,健康的生活方式必不可少。合理膳食、适量运动、戒烟限酒及心理健康,才是人类健康的四大基石。</span></p>"

//加载远程css 依赖网络速度
let string = "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0,user-scalable=no\"><meta content=\"yes\" name=\"apple-mobile-web-app-capable\"><meta content=\"yes\" name=\"apple-touch-fullscreen\"><meta name=\"format-detection\" content=\"telephone=no\"><link href=\"https://app.h5.ihaozhuo.com/lib/css/newscss.css\" rel=\"stylesheet\"></head><body>\(htmlContent)</body></html>"
self.webView.loadHTMLString(string, baseURL: nil)

//加载本地css
let link:String = Bundle.main.url(forResource: "newscss", withExtension: "css")!.absoluteString
let baseUrl = URL.init(fileURLWithPath: "file:///assets/")
let string = "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0,user-scalable=no\"><meta content=\"yes\" name=\"apple-mobile-web-app-capable\"><meta content=\"yes\" name=\"apple-touch-fullscreen\"><meta name=\"format-detection\" content=\"telephone=no\"><link href=\"" + link + "\" rel=\"stylesheet\"></head><body>\(htmlContent)</body></html>"
self.webView.loadHTMLString(string, baseURL: baseUrl)

代码挺简单的,看文章的小伙伴应该都能理解,其中主要区别就是这两句话,

//资源为网络路径
<link href=\"https://app.h5.ihaozhuo.com/lib/css/newscss.css\" rel=\"stylesheet\">
//资源为本地路径
<link href=\"" + link + "\" rel=\"stylesheet\">

可能有些小伙伴,加载本地资源不成功,其中需要两个点要注意:
1、就是需要设置baseURL。
2、baseUrl 可以写的我代码中完全一样,另外.css文件需要和webview在同级目录。

加载url地址

上面的那种加载H5的方法很简单粗暴,只需要替换网络连接为本地连接就好啦,但是我们项目实战中通过加载url地址的方式其实更常见些。这时候我们改怎么处理呢?修改资源为本地路径就别想啦,想破脑袋、查遍资料发现了这个好东西 WKURLSchemeHandler。不过这个东西在 iOS 11之后才有支持,不过iOS系统的更新占比完全不用担心的,直接搞起来。

先看看代码怎么写:

let configuration = WKWebViewConfiguration.init();
//这里是个注意点 yjkCustomScheme 这个玩意儿就是和H5约定的规则哦,H5加载的资源用这个作为协议就好啦
configuration.setURLSchemeHandler(CustomURLSchemeHandler.init(), forURLScheme: "yjkCustomScheme")
webView = WKWebView.init(frame: CGRect.init(x: 0, y: 0, width: view.frame.width, height: view.frame.height), configuration: configuration)
webView.scrollView.decelerationRate = UIScrollView.DecelerationRate.normal
webView.navigationDelegate = self
self.view.addSubview(webView)
        
//***加载H5的地址就应该使用这个规则来加载,不然直接加载https的地址是无法进行拦截的
webView.load(URLRequest.init(url: URL.init(string: "yjkCustomScheme://app.h5.ihaozhuo.com/native/yjkdemo/index.html?v=6")!))

处理代理的完整代码:

//拦截类
class CustomURLSchemeHandler: NSObject {
    
}

extension CustomURLSchemeHandler:WKURLSchemeHandler{
    
    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        
        //文件名
        let fileName = urlSchemeTask.request.url?.lastPathComponent
        //文件扩展名(文件类型)
        let pathExtension = urlSchemeTask.request.url?.pathExtension
        
        //获取本地资源
        let fileURL = Bundle.main.url(forResource: fileName?.components(separatedBy: ".").first, withExtension: pathExtension)
        
        //本地存在文件
        if fileURL != nil{
            //获取本地资源异常
            do {
                //返回本地数据
                let data:NSData = try Data.init(contentsOf: fileURL!) as NSData
                let pathExtension = fileURL!.pathExtension
                let mime = mimeType(forPathExtension: pathExtension)
                
                let response:URLResponse = URLResponse.init(url: urlSchemeTask.request.url!, mimeType: mime, expectedContentLength: data.length, textEncodingName: nil)
                urlSchemeTask.didReceive(response)
                urlSchemeTask.didReceive(data as Data)
                urlSchemeTask.didFinish()
            }catch {
                //本地资源获取异常
                requestWebViewData(urlSchemeTask: urlSchemeTask)
            }
        }else{
            //无本地资源
            requestWebViewData(urlSchemeTask: urlSchemeTask)
        }
    }
    
    func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
        
    }
    
    /// 代替H5发出网络请求
    ///
    /// - Parameter urlSchemeTask:
    private func requestWebViewData(urlSchemeTask: WKURLSchemeTask){
        let schemeUrl:String = urlSchemeTask.request.url?.absoluteString ?? ""  //***这个搞过来好像都是小写的
        //换成原始的请求地址
        let replacedStr = schemeUrl.replacingOccurrences(of: "yjkcustomscheme", with: "https")
        //发出请求结果返回
        let request = URLRequest.init(url: URL.init(string: replacedStr)!)
        let config = URLSessionConfiguration.default
        let session = URLSession.init(configuration: config)
        let dataTask = session.dataTask(with: request) { (data:Data?, response:URLResponse?, error:Error?) in
            if error != nil{
                urlSchemeTask.didFailWithError(error!)
            }else{
                urlSchemeTask.didReceive(response!)
                urlSchemeTask.didReceive(data!)
                urlSchemeTask.didFinish()
            }
        }
        dataTask.resume()
    }
    
    /// 获取文件类型
    ///
    /// - Parameter pathExtension:
    /// - Returns:
    private func mimeType(forPathExtension pathExtension: String) -> String {
        if
            let id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(),
            let contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue()
        {
            return contentType as String
        }
        
        return "application/octet-stream"
    }
}

所有代码都在上面了,不多哔哔了。主要思想就是拦截掉H5发出去的请求,返回给他本地数据,从而减少H5网络请求的时长。

最后要说的就是这几点:
1、目前影响H5体验的主要因素就是网络请求的速度,在5G高速发展的今天,H5势必会成为将来发展的大趋势。
2、通过实测加载HTMLString比加载url的速度确实要快很多。因此,能通过后台返回Html标签的,尽量就使用Html标签。
3、本文只是介绍一个思路,要想完整应用的项目中,还是要做一些列的工作的。比如肯定是需要一个版本管理的机制的。

参考文章:
iOS WKWebView 加载本地HTML、CSS、JS文件
iOS app秒开H5优化总结
移动端本地 H5 秒开方案探索与实现

上一篇下一篇

猜你喜欢

热点阅读