前言
三种形式:Native页面、RN页面和h5页面,相当比前两种形式,h5有跨平台、开发成本低、迭代速度快优势,同时也有加速速度慢,性能不够理想的问题。为弥补h5的短板,最快最有效的是提升h5加载速度。
根据前端同事的调研,以下为h5页面加载过程耗时分析:
其中静态资源下载过程时间是最长的,而且根据h5的复杂程度还可能会更长,如果能提前把这些资源缓存好,并拦截WebView加载资源的过程,这将大大提交h5的打开速度。幸运的是Android的webview可以直接拦截下载资源。
public class DuWebViewClient extends WebViewClient {
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return super.shouldInterceptRequest(view, url);
}
}
客户端方案
对于客户端来说,资源缓存主要包括两部分: h5资源下载,WebView资源拦截 在具体实现时还需要解决解决几个问题
- 提前缓存的资源哪里来?
- 在远端创建一个配置文件,配置好需要提前缓存的资源url
- 请求需要预加载的资源配置列表接口
- 清空待下载的任务队列,防止重复和冗余请求
- 在缓存中检查本地是否存在
- 存在直接略过
- 不存在放入下载队列
- 下载资源策略
- 根据配置将资源分为几个优先级 priority
- 特高 0: 不论前后台,不论网络情况立即下载
- 高 1: 前台wifi条件下,或者后台不论网络环境下
- 中 2: 后台,不论网络环境
- 低 3: 后台wifi条件下
- 在进入不同条件时,从待下载列队中取出下载任务进行下载
- 下载完成后进资源进行校验
- 检查规则暂定采用返回头里面的md5进行校验
- 资源存储到缓存,防止
- 缓存采用LRUDiskCache,大小暂定50M,这样可以
- 将下载的资源本身,及请求的Respone的header部分进行存储
- 以资源的url作为惟一key进行保存,此时要保证当资源有修改时url也一定会修改
- WebView拦截资源
- 重写WebViewClient的shouldInterceptRequest方法
- 根据url查找本地是否存在缓存
- 有缓存就取出缓存与header
- header添加字段du_cached: [缓存时间戳],预留
- 埋点统计
- 针对首次打开WebView页面的进行统计
- 页面加载完毕后上传Apm
下载流程:
拦截流程
代码设计
代码框架设计
遵循高内聚,低偶合的原则,sdk对外主要暴露四个类,FastHybridApi与FastHybridConfig配置初始化,IFastHybridProxy用来代理WebView资源加载过程,而FastHybridResourceResponse单独封装利于我们转化成自己需要的对象。所以对于外外部使用来说,仅需要三步
- 根据需求初始化
FastHybridApi.init(context, FastHybridConfig(
appId = "du",
isDebug = DuConfig.DEBUG,
configUrl = if (DuConfig.DEBUG) TEST_CONFIG_URL else RELEASE_CONFIG_URL ,
miniCheckTime = if (DuConfig.DEBUG) 0L else FhConstants.DEFAULT_MINE_CHECK_TIME
))
- 创建IFastHybridProxy, 其中setOnLoadCallBack是为了统计页面加载完成的时间
boolean isH5resourceLoad = ConfigCenterHelper.isEnable("h5resourceLoad", false);
fastHybridProxy = FastHybridApi.INSTANCE.createProxy(loadUrl, isH5resourceLoad);
fastHybridProxy.setOnLoadCallBack((url, timeSpent, isCacheOpen, isCacheResource,
isFirstLoad, cachedResources) ->{
if (isCacheResource && isFirstLoad){
FhLogger.INSTANCE.d("onLoad upload to apm...");
Map<String, String> map = new HashMap<>();
map.put("url", url);
map.put("cost", String.valueOf(timeSpent));
ApmBiClient.monitorMap("other",
isCacheOpen && isH5resourceLoad ? "h5_resource_load" : "h5_resource_load_2",
map, 1f);
}
} );
- 代理WebView的加载过程
private DuWebViewClient webViewClient = new DuWebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (fastHybridProxy != null) {
fastHybridProxy.onPageStarted(url);
}
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
onPageLoadFinish(view, url);
if (fastHybridProxy != null){
fastHybridProxy.onPageFinish(url);
}
}
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
FastHybridResourceResponse resourceResponse = fastHybridProxy != null ?
fastHybridProxy.shouldInterceptRequest(request) : null;
return resourceResponse != null ? resourceResponse.toWebResource()
: super.shouldInterceptRequest(webview, request);
}
@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
FastHybridResourceResponse response = fastHybridProxy != null ?
fastHybridProxy.shouldInterceptRequest(url) : null;
return response != null ? response.toWebResource() : null;
}
};
|