欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android h5预加载js和css提升打开速度

程序员文章站 2023-12-24 22:09:03
...

使用webpack加vue开发单页面程序时,不可避免的会生成大量的css和js文件,常规的优化方案是:

  • 拆分第三方库,改为cdn
  • vue模块改为懒加载
  • 服务器启用gzip减少文件体积

这些操作可以明显提升50%效果,但是在APP中,还是无法达到秒开,所以我们还需要着手对APP进行优化,优化的思路如下:

  1. 保存第三方js/css到文件夹(Assets目录)
  2. 预加载本地js/css文件进行缓存
  3. 当访问h5页面时,拦截js/css文件的访问请求,替换缓存中的本地文件

1.保存第三方js、css文件

首先,将项目中用到的第三方文件保存在Assets目录中
android h5预加载js和css提升打开速度

2.预加载本地js/css文件进行缓存

在初始化APP时候,下载h5页面的所有html,然后用正则匹配出所有的本地css和js文件,并且将这些文件存在缓存目录中。

private void cacheWebviewJs() {
        HttpClient httpClient = HttpClient.getInstance();
        httpClient.getHttpRequestGet("http://www.xxx.com/", new HttpRequestBack() {
            @Override
            public void back(String s) {
                List<String> strs = new ArrayList<String>();
                Pattern p = Pattern.compile("href=([css,js][^\\s]*)");
                Matcher m = p.matcher(s);
                while (m.find()) {
                    strs.add(m.group(1));
                }
                for (int i = 0; i < strs.size(); i++) {
                    String domain = "http://www.xxx.com/";
                    String path = domain + strs.get(i);
                    String[] filenameArr = path.split("/");
                    String filename = filenameArr[filenameArr.length - 1];
                    String savePath = Environment.getExternalStorageDirectory() + "/xxxapp/data/"; + filename;
                    File cacheFile = new File(savePath);
                    if(!cacheFile.exists()){
                        Log.i("====cacheWebviewJs====", savePath);
                        SaveDataUtils.writeUrToStrealm(cacheFile,path);
                    }
                }
            }
      

3.拦截js、css请求,并且替换为本地文件

这里进行区分,第三方库的js、css文件,和本地的文件,要分别替换。
这么做目的是防止将来第三方库js文件重名,导致h5无法正确执行。

webView.setWebViewClient(new WebViewClient() {
			//只处理21版本以上的安卓程序,以下版本的不是这个方法
            @TargetApi(Build.VERSION_CODES.LOLLIPOP)
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
                Uri uri = request.getUrl();
                String path = uri.getPath();
                if (path.contains(".js") || path.contains(".css")) {
                    String[] arr = path.split("/");
                    String jsFileName = arr[arr.length - 1];
                    String[] arrEnd = jsFileName.split("\\.");
                    if (arr.length != 0) {
                        if (arrEnd.length != 0) {
                            //第三方库文件列表
                            String[] fileArr = {"axios.min.js", "nutui.min.css","nutui.min.js","vconsole.min.js","vue.js","vue-router.js","vuex.js"};
                            String file_type = "application/x-javascript";
                            if(jsFileName.contains(".css")){
                                file_type = "text/css";
                            }
                            for(int i =0;i<fileArr.length;i++){
                                if (jsFileName.equals(fileArr[i])) {
                                    try {
                                        return new WebResourceResponse(file_type,"utf-8",getBaseContext().getAssets().open("h5cache" + "/" + fileArr[i]));
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }

                            //读取其他临时js缓存
                            try {
                                String savePath = Environment.getExternalStorageDirectory() + "/xxxapp/data/"; + jsFileName;
                                File cacheFile = new File(savePath);
                                if(cacheFile.exists()){
                                    return SaveDataUtils.getWebResource(file_type,"utf-8", cacheFile);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
                return super.shouldInterceptRequest(view, request);
            }
});

其他用到的第三方库

1、HttpClient 用来获取js和css文件,自己实现即可

2、SaveUtils存储和读取缓存文件数据流

public class SaveDataUtils {

    /**
     * 得到WebResourceResponse对象
     * @return
     */
    public static WebResourceResponse getWebResource(File uFile, String url) {

        try {
            URL uri = new URL(url);
            URLConnection connection = uri.openConnection();
            String contentType = connection.getContentType();
            String mimeType = "";
            String encoding = "";
            if (contentType != null && !"".equals(contentType)) {
                if (contentType.indexOf(";") != -1) {
                    String[] args = contentType.split(";");
                    mimeType = args[0];
                    String[] args2 = args[1].trim().split("=");
                    if (args.length == 2 && args2[0].trim().toLowerCase().equals("charset")) {
                        encoding = args2[1].trim();
                    } else {

                        encoding = "utf-8";
                    }
                } else {
                    mimeType = contentType;
                    encoding = "utf-8";
                }
            }

            FileInputStream fileInputStream = new FileInputStream(uFile);
            SaveDataUtils.readBlock(fileInputStream);

            return new WebResourceResponse(mimeType, encoding, fileInputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static WebResourceResponse getWebResource(String mimeType,String encoding,File uFile) {

        try {
            FileInputStream fileInputStream = new FileInputStream(uFile);
            return new WebResourceResponse(mimeType, encoding, fileInputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 把js,css保存在本地
     * @param uFile 本地存储的文件名File路径
     * @param url 将要下载的js,css文件
     */
    public static void writeUrToStrealm(File uFile, String url) {
        try {
            URL uri = new URL(url);
            URLConnection connection = uri.openConnection();
            InputStream uristream = connection.getInputStream();
            //String cache = connection.getHeaderField("Ddbuild-Cache");
            String contentType = connection.getContentType();
            //textml; charset=utf-8
            String mimeType = "";
            String encoding = "";
            if (contentType != null && !"".equals(contentType)) {
                if (contentType.indexOf(";") != -1) {
                    String[] args = contentType.split(";");
                    mimeType = args[0];
                    String[] args2 = args[1].trim().split("=");
                    if (args.length == 2 && args2[0].trim().toLowerCase().equals("charset")) {
                        encoding = args2[1].trim();
                    } else {

                        encoding = "utf-8";
                    }
                } else {
                    mimeType = contentType;
                    encoding = "utf-8";
                }
            }

            //todo:缓存uristream
            FileOutputStream output = new FileOutputStream(uFile);
            int read_len;
            byte[] buffer = new byte[1024];
            while ((read_len = uristream.read(buffer)) > 0) {
                output.write(buffer, 0, read_len);
            }
            output.close();
            uristream.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 写入JS相关文件
     * by黄海杰 at:2015-10-29 16:14:01
     * @param output
     * @param str
     */
    public static void writeBlock(OutputStream output, String str) {
        try {
            byte[] buffer = str.getBytes("utf-8");
            int len = buffer.length;
            byte[] len_buffer = toByteArray(len, 4);
            output.write(len_buffer);
            output.write(buffer);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 读取JS相关文件
     * @param input
     * @return
     */
    public static String readBlock(InputStream input) {
        try {
            byte[] len_buffer = new byte[4];
            input.read(len_buffer);
            int len = toInt(len_buffer);
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            int read_len = 0;
            byte[] buffer = new byte[len];
            while ((read_len = input.read(buffer)) > 0) {
                len -= read_len;
                output.write(buffer, 0, read_len);
                if (len <= 0) {
                    break;
                }
            }
            buffer = output.toByteArray();
            output.close();
            return new String(buffer,"utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * int转byte
     * by黄海杰 at:2015-10-29 16:15:06
     * @param iSource
     * @param iArrayLen
     * @return
     */
    public static byte[] toByteArray(int iSource, int iArrayLen) {
        byte[] bLocalArr = new byte[iArrayLen];
        for (int i = 0; (i < 4) && (i < iArrayLen); i++) {
            bLocalArr[i] = (byte) (iSource >> 8 * i & 0xFF);
        }
        return bLocalArr;
    }

    /**
     * byte转int
     * by黄海杰 at:2015-10-29 16:14:37
     * @param bRefArr
     * @return
     */
    // 将byte数组bRefArr转为一个整数,字节数组的低位是整型的低字节位
    public static int toInt(byte[] bRefArr) {
        int iOutcome = 0;
        byte bLoop;

        for (int i = 0; i < bRefArr.length; i++) {
            bLoop = bRefArr[i];
            iOutcome += (bLoop & 0xFF) << (8 * i);
        }
        return iOutcome;
    }
}

IOS的处理方法应该也类似,可参考:
http://www.cocoachina.com/articles/89994

h5cache第三方库下载地址:
链接: https://pan.baidu.com/s/17JdNHQIPDcmDSuUsp6PxWg 提取码: dkmn

上一篇:

下一篇: