Android—在WebView中下载Blob协议文件
2020-05-13 本文已影响0人
东方未曦
之前有个需求是要下载Blob协议的gif,让我苦恼了好久。平时下载http协议的文件时直接获取输入流即可,但是Java无法获得Blob协议的文件流,无法直接处理。不过JavaScript处理Blob协议非常方便,可以考虑通过前端将该文件转化为Base64的字符串。
那么下载Blob协议文件时,可以先将链接传给前端,前端通过JS处理后得到Base64的文件流,再将文件流通过Android的JavaScript方法传给客户端。
按这个逻辑,JS处理文件流这块需要前端开发,不过有意思的是,这部分功能我们可以直接在客户端写。如下方的getBase64StringFromBlobUrl()
方法,将JS代码拼成String,调用WebView.loadUrl(...)
加载这段JS代码即可,那么所有的流程都能在客户端实现。
public class DownloadBlobFileJSInterface {
private Context mContext;
private DownloadGifSuccessListener mDownloadGifSuccessListener;
public DownloadBlobFileJSInterface(Context context) {
this.mContext = context;
}
public void setDownloadGifSuccessListener(DownloadGifSuccessListener listener) {
mDownloadGifSuccessListener = listener;
}
@JavascriptInterface
public void getBase64FromBlobData(String base64Data) {
convertToGifAndProcess(base64Data);
}
public static String getBase64StringFromBlobUrl(String blobUrl) {
if (blobUrl.startsWith("blob")) {
return "javascript: var xhr = new XMLHttpRequest();" +
"xhr.open('GET', '" + blobUrl + "', true);" +
"xhr.setRequestHeader('Content-type','image/gif');" +
"xhr.responseType = 'blob';" +
"xhr.onload = function(e) {" +
" if (this.status == 200) {" +
" var blobFile = this.response;" +
" var reader = new FileReader();" +
" reader.readAsDataURL(blobFile);" +
" reader.onloadend = function() {" +
" base64data = reader.result;" +
" Android.getBase64FromBlobData(base64data);" +
" }" +
" }" +
"};" +
"xhr.send();";
}
return "javascript: console.log('It is not a Blob URL');";
}
private void convertToGifAndProcess(String base64) {
String currentDateTime = DateFormat.getDateTimeInstance().format(new Date());
File gifFile = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS) + "/Test_" + currentDateTime + "_.gif");
saveGifToPath(base64, gifFile);
Toast.makeText(mContext, R.string.save_image_success, Toast.LENGTH_SHORT).show();
if (mDownloadGifSuccessListener != null) {
mDownloadGifSuccessListener.downloadGifSuccess(gifFile.getAbsolutePath());
}
}
private void saveGifToPath(String base64, File gifFilePath) {
try {
byte[] fileBytes = Base64.decode(base64.replaceFirst(
"data:image/gif;base64,", ""), 0);
FileOutputStream os = new FileOutputStream(gifFilePath, false);
os.write(fileBytes);
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public interface DownloadGifSuccessListener {
void downloadGifSuccess(String absolutePath);
}
}
随后新建WebView,并为WebView添加JavascriptInterface,最后通过loadUrl()
方法执行JS代码即可。
// 1. 新建WebView
mWebView = new WebView(this);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAppCachePath(getApplicationContext().getCacheDir().getAbsolutePath());
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
webSettings.setDatabaseEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setUseWideViewPort(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setPluginState(WebSettings.PluginState.ON);
// 2. 添加JavascriptInterface
mDownloadBlobFileJSInterface = new DownloadBlobFileJSInterface(this);
mWebView.addJavascriptInterface(mDownloadBlobFileJSInterface, "Android");
// 3. 执行JS代码
mWebView.loadUrl(DownloadBlobFileJSInterface.getBase64StringFromBlobUrl(url));