android h5预加载js和css提升打开速度
程序员文章站
2023-12-24 22:09:03
...
使用webpack加vue开发单页面程序时,不可避免的会生成大量的css和js文件,常规的优化方案是:
- 拆分第三方库,改为cdn
- vue模块改为懒加载
- 服务器启用gzip减少文件体积
这些操作可以明显提升50%效果,但是在APP中,还是无法达到秒开,所以我们还需要着手对APP进行优化,优化的思路如下:
- 保存第三方js/css到文件夹(Assets目录)
- 预加载本地js/css文件进行缓存
- 当访问h5页面时,拦截js/css文件的访问请求,替换缓存中的本地文件
1.保存第三方js、css文件
首先,将项目中用到的第三方文件保存在Assets目录中
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