一、背景

在实际业务中,我们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交流

Logo

前往低代码交流专区

更多推荐