H5离线包技术的实际应用-webview秒开
一、背景在实际业务中,我们app中的webview使用的场景越来越多,加载速度成为了困扰用户的一个痛点,尤其是h5由jsp过渡到vue后,页面加载速度更慢了,经常是经过长时间的loading才能加载出来,虽然这和我们的整体架构有关,首页有4-7个webview fragment,在进入首页的时候会同时加载,各个页面都需要加载大量的图片以及数个请求。为此,提高加载速度成为了优化当中的一个方向。...
一、背景
在实际业务中,我们app中的webview使用的场景越来越多,加载速度成为了困扰用户的一个痛点,尤其是h5由jsp过渡到vue后,页面加载速度更慢了,经常是经过长时间的loading才能加载出来,虽然这和我们的整体架构有关,首页有4-7个webview fragment,在进入首页的时候会同时加载,各个页面都需要加载大量的图片以及数个请求。为此,提高加载速度成为了优化当中的一个方向。
二、技术探索
在查阅过相关资料后,技术方向大体分为了两个,一个是鹅厂的VasSonic,通过辅以x5内核对于webview的优化,加上页面直出,整体加载速度很夸张,在我看来基本逼近了webview的加载极限,但是其难以实现之处在于侵入性很强,需要整体结构向它靠拢,后端、h5、Android三方配合,对于像我们公司以业务为导向的团队来说,做起来还比较困难。另一个就是离线包,通常来说,加载一个h5页面最耗时的部分就在于页面资源的下载,如html、css、js文件,如果这些文件不需要下载,那么剩下的时间开销基本就是页面解析及渲染。我们Android在和h5沟通过以后,决定采取方案二。
三、技术实现
1.离线包的组成
离线包由h5提供,包里面的结构基本和线上一致,本身我们的h5网页就是放在cdn上,这次只不过是拿出来,打成压缩包,放在Android的apk包里
2.Android对离线包的解析
首先,离线包的zip包是放在assets文件夹下,在app启动时,解压zip包到相应的文件夹目录下,拿到这个本地路径
3.对线上地址的替换
webview在加载的时候,会调用loadurl方法,此时传进去的url还是线上的url,Android要做的最重要的一步就是重写webviewClient的shouldInterceptRequest方法,在里面拿到要加载的url,并且进行替换,替换成本地url。同样的道理,凡事线上资源都可以进行替换,如css、js、图片资源,还可以通过glide对图片资源进行缓存。核心代码如下
//=============================离线化对webviewclient的改造
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String urlOrigin) {
//拦截请求,把本地页面地址转换成线上页面地址
String url = UrlConfig.replaceUrlHost(urlOrigin);
String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url));
//如果是图片走缓存
if (("image/jpeg".equals(mimeType) || "image/png".equals(mimeType)))
return handleImageRequest(url, mimeType);
if (UrlConfig.USE_OFFLINE && !url.contains("http")) {
//构建WebResourceResponse,走重写后的方法。super会直接load传进来的urlOrigin
try {
URL localUri = new URL(url);
InputStream is = localUri.openConnection().getInputStream();
return new WebResourceResponse(
MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url))
, "UTF-8", is);
} catch (IOException e) {
//如果文件找不到,拦截方法会失效,还是走之前的url
if (e.getMessage().contains(".js")) {
//当前线程-Chrome_FileThread
webview.getHandler().post(new Runnable() {
@Override
public void run() {
onError.onErrorReceived();//处理白屏的情况,缺少js文件会走onError
C.OFFLINE_LOADFAIL = true;
}
});
}
e.printStackTrace();
}
}
return super.shouldInterceptRequest(view, url);
}
注释1:UrlConfig.replaceUrlHost方法里面是具体替换过程。举个例子:线上地址肯定是 ww.baidu.com/index.html这种,本地地址就是file:///storage/0/emulate/baidu/index.html,把index.html之前做字符串替换就可以。
四、最终效果
经过测试同学的性能测试,页面首次加载提升率平均50%,二次加载平均提升35%;由于网络请求也是Android代替h5请求,所以request请求提升超过80%,这些数据是正常网络状态下,而在弱网状态下更是有超过300%的提升
================================================================================================
如有问题,可加1510312433交流
更多推荐
所有评论(0)