Android 离线加载落地
作者简介:Serpit,Android开发工程师,2023年加入37手游技术部,目前负责国内游戏发行 Android SDK 开发。
前言
在使用WebView时,会有一个老生常谈的话题------"WebView加载优化"。那WebView加载优化,一般有几个方向:
- WebView的预创建和复用
- WebView代理请求
- WebView的离线加载
这里简单科普一下这几个优化方向(大佬可以直接忽略~~)
预创建和复用
预创建和复用,见名知意,就是可以提前缓存一些WebView。这是因为,在WebView创建的时候,会需要一点时间,所以,为了节省这部分的时间,可以提前实例化WebView。这里可以使用缓存池来实现~
代理请求
代理请求,该方案是接管WebView的一些请求,帮助前端页面做请求,然后通过与前端的交互,将数据带回给前端页面。那,为什么要这么做呢?那也是"抢跑",提前在跳转/其他时机的时候,同时做一些网络请求,将业务数据处理好,等到前端页面加载好的时候,来客户端取即可。这样就节省了前端做请求的耗时了~
简单介绍完预创建和复用、WebView代理请求,接下来就介绍本文的离线加载了。
离线加载
离线加载是节省的哪一部分耗时呢?回答这个问题前,先了解下离线加载是个什么方案。
离线加载的原理是,拦截WebView的请求,转而在端内构造对应的响应来进行返回。所以,离线加载节省的是请求资源的耗时,快速页面的渲染。
如何落地?
落地这个离线加载,是离不开WebViewClient
中一个关键的API
java
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
这个API是我们完成资源拦截的关键,它的Request参数,带有当前WebView正要加载资源的URL,而返回值WebResourceResponse
则是返回给WebView,当前资源的响应。
下面就是伪代码
java
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
WebResourceResponse webResourceResponse = fetchResource(request); //根据请求匹配资源
if (webResourceResponse != null) {
return webResourceResponse;
}
return super.shouldInterceptRequest(view, request);
}
private WebResourceResponse fetchResource(WebResourceRequest webResourceRequest) {
String url = webResourceRequest.getUrl().toString();
Uri uri = Uri.parse(url);
File file = findFileLocal(uri); //省略匹配的逻辑...
return new WebResourceResponse(mime, "UTF-8", new FileInputStream(file));
}
有了这个强有力的API的,我们就可以轻松实现离线加载了。是不是很简单~
资源
因为离线加载除了加载逻辑以外,还有一个核心的点------资源!那资源管理这部分也是十分重要,下面将介绍资源管理部分需要注意的点和方案。由于我们的资源是前端资源,所以会有版本管理的需求,毕竟前端更新的时候本地的资源也需要更新,否则,加载出来的页面就会有问题。下面就介绍一下如何可以做到更新同步的。
更新注意的点有以下几个:
- 更新时机
- 更新策略
更新时机
更新时机,一般来说,在APP启动的时候会需要有一个检查的机制,检查当前的资源是否最新。然后防止用户在使用的过程中,前端有更新,也会在打开页面前做一次更新,确保用户的页面不受旧缓存影响。因此,更新的时机有两个,应用启动和打开页面。
更新策略
更新策略,也按应用启动和打开页面,有两个流程,下面用流程图的方式给大家介绍一下。
打开APP流程
在打开APP时,需要异步检查本地的离线包hash值是否与线上最新的版本一致,不一致则更新本地离线包,然后在更新成功后,则保存最新的离线包。当然,资源包目前只是做的整包更新,还可以在这个基础上优化做资源包的差分处理,做到增量资源包更新。这里先不展开,有兴趣的同学可以留言讨论~
打开页面更新流程
在打开页面前,也需要做一次检查,检查离线包是否最新,但这里有一个注意点和APP启动流程不太一样,因为更新离线资源是一个耗时的操作,所以当检查到本地不是最新时,需要把拦截WebView请求的逻辑给去除,让本次加载走线上的资源,同时等待下次资源最新可用的时候,才开启离线加载。
资源怎么来?
资源怎么来?很多同学会说,这不是废话吗?那当然从前端和后端资源服务接口来呀。这是肯定,没错的。但是,在调研初期,没有前端和后端同学的帮助时,又该如何验证可行性呢?这里安利一个Chrome的小插件Save All Resources
。这个插件可以把浏览器的请求资源拦截到本地文件夹中,是不是一个妥妥的调研神器~
万事具备,落地!
不知大家是否还记得,在上一篇WebView文章中提到的"WebHook"概念呢?没有看过的同学可以回头看下这个这是你们项目中WebView的样子吗?。在这里我们可以实现一个LocalH5WebHook
,然后针对一些开关和更新策略,对这个WebHook进行插拔,就可以灵活实现对离线加载功能的控制了。
java
public class LocalH5WebHook extends SimpleWebHook {
//... 省略其他代码
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
WebResourceResponse webResourceResponse = fetchResource(request);
if (webResourceResponse != null) {
return webResourceResponse;
}
return super.shouldInterceptRequest(view, request);
}
}
总结
上述介绍了一些的WebView优化思路还有落地离线加载的过程,希望可以对一些小伙伴有作用,也欢迎小伙伴们讨论和给些建议~