最近接到个奇葩需求,缓存webview,我想着webview不是自带缓存么,奈何手上这个设备由于网络等各种限制问题,导致webview不能直接加载H5中的资源。也就是说原生缓存机制啥的用不了。
思路:
1.H5本身是html文件,可以想办法保存在本地。
2.H5内的图片可以通过Glide来处理。设置WebViewClient,通过shouldInterceptRequest 拦截所有的资源请求,将图片交给Glide。
开搞: 这里有个问题H5本身怎么保存,估计要写很多代码吧,对于我这个懒人来说太麻烦,html本身就是文件,能不能用glide来处理尼。
查资料发现Glide Decode:
里面有File,那么是不是完全可以把h5一个链接当作file使用glide加载了。上代码
1.先处理Glide加载图片部分,新建一个专门处理各种资源的工具类
public class GlideUtil {
public static byte[] syncLoad(String url, String type) {
GlideUrl glideUrl = buildUrl(url);
byte[] bt = null;
switch (type) {
case "gif":
FutureTarget<byte[]> targetGif = Glide.with(App.instance)
.as(byte[].class)
.load(glideUrl)
.decode(GifDrawable.class).submit();
try {
bt = targetGif.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case "img":
FutureTarget<Bitmap> targetImg = Glide.with(App.instance)
.asBitmap().load(glideUrl).submit();
try {
Bitmap bitmap = targetImg.get();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
bt = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
break;
case "html":
FutureTarget<File> targetHtml = Glide.with(App.instance)
.asFile()
.load(glideUrl)
.submit();
try {
File file = targetHtml.get();
FileInputStream fis = new FileInputStream(file);
//新的 byte 数组输出流,缓冲区容量1024byte
ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
//缓存
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
//改变为byte[]
bt = bos.toByteArray();
//
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
break;
}
return bt;
}
public static GlideUrl buildUrl(String url){
GlideUrl cookie = new GlideUrl(url, new LazyHeaders.Builder()
.addHeader("Cookie", "2")
.build());
return cookie;
}
}
这里为什么要返回byte[],往下看
2.webview 设置 WebViewClient,重写 shouldInterceptRequest
web.webViewClient = object : WebViewClient(){
override fun shouldInterceptRequest(
view: WebView?,
request: WebResourceRequest?
): WebResourceResponse? {
var url = request?.url.toString()
if(url.endsWith(".png") || url.endsWith(".jpg")){
val bytes = GlideUtil.syncLoad(url, "img")
if (bytes != null) {
return WebResourceResponse(
"image/*",
"utf-8",
ByteArrayInputStream(bytes)
)
}
}
if(url.endsWith(".html")){
val bytes = GlideUtil.syncLoad(url, "html")
if (bytes != null) {
return WebResourceResponse(
"text/html",
"utf-8",
ByteArrayInputStream(bytes)
)
}
}
return super.shouldInterceptRequest(view, request)
}
}
测试搞起来
1.第一次联网加载后,去缓存目录查看:
这里面应该包含了图片及html源文件吧。
2.杀进程,断网后,再次打开app,完美还原!!!
3.为了验证H5资源是使用了Glide缓存,将上图中的文件拷出,尝试一下重名名
这些不就是H5所有的东西了嘛。
有的人要说有些H5里有视频,我想只要把视频当作file来处理,同样是可行的吧。待验证.......
附上 Glide 4.+ 设置缓存路径,便于后期维护本地资源
class App :Application() {
companion object{
lateinit var instance:Application
}
override fun onCreate() {
super.onCreate()
instance = this
initGlide()
}
fun initGlide(){
val builder = GlideBuilder()
//设置内存缓存大小为20mb
val memoryCacheSize = 1024 * 1024 * 200 // 200M
//设置内存缓存大小
builder.setMemoryCache(LruResourceCache(memoryCacheSize.toLong()))
//设置硬盘缓存大小为1G
val diskCacheSize = 1024 * 1024 * 1000 // 1G
// builder.setDiskCache(InternalCacheDiskCacheFactory(this, "Glide_Cache", diskCacheSize.toLong()))
builder.setDiskCache(DiskLruCacheFactory(cacheDir.path + "/Glide_Cache_Folder", diskCacheSize.toLong()))
Glide.init(this, builder)
}
}
笔记
通过 oss请求码获取视频第一帧画面
https://xxxxxxxxxx.mp4?x-oss-process=video/snapshot,t_1000,f_jpg,w_750