这个版本有个需求就是优化webview的加载速度,争取做到h5秒开。于是各种找解决方案:
1、美团WebView性能、体验分析与优化
https://tech.meituan.com/WebViewPerf.html
我使用的方法也是参考美团的一点,并没有美团优化的全面
2、腾讯开源框架VasSonic
https://segmentfault.com/a/1190000010711024
QQ使用h5秒开方案,下载尝鲜了下,确实快了很多。但是使用成本太大了,需要后台和前端配合使用,于是就放弃了。
因为我们app图片展示较多,根据app特性我们最后总结的一个简单可行的优化方案是:拦截替换webview中加载的资源文件,替换成事先下载好在本地的文件。这样就不需要去网上加载资源文件了。
好了,上代码:
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
Uri uri = Uri.parse(url);
if (interceptRequest(uri) != null){
return interceptRequest(uri);
}
return super.shouldInterceptRequest(view, url);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
if (interceptRequest(uri) != null){
return interceptRequest(uri);
}
return super.shouldInterceptRequest(view, request);
}
在需要连网加载资源的地方做拦截,判断本地是否有已经下载好的文件,如果有就加载本地文件,否则就网络加载。
/**
* 拦截url 判断本地是否有缓存资源文件
* @param uri
* @return
*/
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private WebResourceResponse interceptRequest(Uri uri){
WebResourceResponse resourceResponse = null;
for (int i = 0; i < mKeyList.size(); i++) {
//判断是否要加载本地资源
if (mKeyList.get(i).contains(uri.getAuthority())) {
try {
//加载资源类型
String mimeType = "";
if (uri.getPath().contains(".js")) {
mimeType = "text/javascript";
} else {
mimeType = MimeTypeMapUtils.getMimeTypeFromUrl(uri.toString());
}
String path = FilePath.OfflineCache + uri.getAuthority() + uri.getPath();
if (!TextUtils.isEmpty(mimeType)) {
resourceResponse = new WebResourceResponse(mimeType, "", 200, "ok", header, new FileInputStream(path));
return resourceResponse;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
return resourceResponse;
}
mKeyList是事先缓存在本地key
private List<String> mKeyList;
MOfflineCacheBean cacheBean = SPUtils.get(Cosmeapp.mCosmeapp, SPUtils.S_K_OFFLINE, MOfflineCacheBean.class);
mKeyList = cacheBean.getOfflineList();
MimeTypeMapUtils资源类型判断
public class MimeTypeMapUtils {
public static String getFileExtensionFromUrl(String url) {
url = url.toLowerCase();
if (!TextUtils.isEmpty(url)) {
int fragment = url.lastIndexOf('#');
if (fragment > 0) {
url = url.substring(0, fragment);
}
int query = url.lastIndexOf('?');
if (query > 0) {
url = url.substring(0, query);
}
int filenamePos = url.lastIndexOf('/');
String filename =
0 <= filenamePos ? url.substring(filenamePos + 1) : url;
// if the filename contains special characters, we don't
// consider it valid for our matching purposes:
if (!filename.isEmpty()) {
int dotPos = filename.lastIndexOf('.');
if (0 <= dotPos) {
return filename.substring(dotPos + 1);
}
}
}
return "";
}
public static String getMimeTypeFromUrl(String url) {
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(getFileExtensionFromUrl(url));
}
public static String getMimeTypeFromExtension(String extension) {
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
}
这里要说一下这个替换方法:
resourceResponse = new WebResourceResponse(mimeType, "", 200, "ok", header, new FileInputStream(path));
构造方法,见名知意原则。
WebResourceResponse(String mimeType, String encoding, int statusCode, String reasonPhrase, Map<String, String> responseHeaders, InputStream data)
第一就是这个reasonPhrase最好用英文字母,我之前用的汉字,他们解析不出来。
第二就是responseHeaders
header.put("Access-Control-Allow-Origin", "*");
header.put("Access-Control-Allow-Headers", "Content-Type");
好了,在我们这种图片比较多的app中,使用这种优化,webview打开速度提升还是挺大的,肉眼可见啊。