我有一个可从Web视图中导航的网站。其中一个页面生成一个ZIP文件,该文件通过BLOB URL下载。我发现webview不支持此功能,因此我尝试实现此解决方案:
Download Blob file from Website inside Android WebViewClient
但是,它对我不起作用。永远不会命中convertBase64StringToZipAndStoreIt中的断点。
更新:我发现我正在获取HTTP404。我尝试使用blobUrl和blobUrl.substring(5),结果两种方法都相同。不过,BLOB可以在Chrome中正常下载。
Webview设置:
private void launchWV() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
1);
setContentView(R.layout.activity_self_service_launcher);
mWebView = (WebView) findViewById(R.id.activity_launcher_webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(true);
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setSupportMultipleWindows(true);
webSettings.setAllowContentAccess(true);
webSettings.setAllowFileAccess(true);
webSettings.setAllowFileAccessFromFileURLs(true);
webSettings.setUserAgentString("Mozilla/5.0 (Android; X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.34 Safari/534.24" + getClientVersionInfo());
webSettings.setDomStorageEnabled(true);
webSettings.setLoadWithOverviewMode(true);
mWebView.setWebViewClient(new MyWebViewClient(this));
mWebView.setWebChromeClient(new MyWebChromeClient(this));
mWebView.addJavascriptInterface(new JavaScriptInterface(getApplicationContext()), "Android");
}
从shouldOverrideUrlLoading()调用的函数(仅关注BLOB URL的else条件):
private boolean handleRequest(WebView view, String url) {
String filename;
if (!checkInternetConnection()) {
ShowNetworkUnavailableDialog(false);
return true;
}
else {
if (url.contains("view/mys") || url.contains("view/myy") || url.contains("blob") || url.contains("view/mye")) {
if (url.contains("view/mys")) {
filename = getResources().getString(R.string.mys_file_name).concat(".pdf");
} else if (url.contains("view/myy")) {
filename = getResources().getString(R.string.form_file_name).concat(".pdf");
} else if (url.contains("blob")) {
filename = getResources().getString(R.string.mys_file_name).concat(".zip");
} else {
filename = getResources().getString(R.string.mye_file_name).concat(".pdf");
}
if (!url.contains("blob")) {
String cookies = CookieManager.getInstance().getCookie(url);
DownloadManager.Request downloadRequest = new DownloadManager.Request(Uri.parse(url));
downloadRequest.addRequestHeader("cookie", cookies);
downloadRequest.allowScanningByMediaScanner();
downloadRequest.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
downloadRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
try {
dm.enqueue(downloadRequest);
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(), getResources().getString(R.string.connection_unavailable), Toast.LENGTH_LONG).show();
return false;
}
} else {
String blobURL = JavaScriptInterface.getBase64StringFromBlobUrl(url);
mWebView.loadUrl(blobURL);
}
Toast.makeText(getApplicationContext(), getResources().getString(R.string.download_message), Toast.LENGTH_LONG).show();
return true;
} else if (!url.contains(getMetadata(getApplicationContext(), HOSTNAME))) {
//Navigate to external site outside of webview e.g. Help site
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
} else if(url.contains(getResources().getString(R.string.about_url))) {
mWebView.loadUrl(url);
return false;
} else {
if (savedInstanceState == null) {
mWebView.loadUrl(url);
}
return false;
}
}
}
JavaScriptInterface类:
public class JavaScriptInterface {
private Context context;
private NotificationManager nm;
public JavaScriptInterface(Context context) {
this.context = context;
}
@JavascriptInterface
public void getBase64FromBlobData(String base64Data) throws IOException {
convertBase64StringToZipAndStoreIt(base64Data);
}
public static String getBase64StringFromBlobUrl(String blobUrl){
if(blobUrl.startsWith("blob")){
return "javascript: var xhr = new XMLHttpRequest();" +
"xhr.open('GET', '" + blobUrl.substring(5) + "', true);" +
"xhr.setRequestHeader('Content-type','application/zip');" +
"xhr.responseType = 'blob';" +
"xhr.onload = function(e) {" +
" if (this.status == 200) {" +
" var blobZip = this.response;" +
" var reader = new FileReader();" +
" reader.readAsDataURL(blobZip);" +
" reader.onloadend = function() {" +
" base64data = reader.result;" +
" Android.getBase64FromBlobData(base64data);" +
" }" +
" }" +
"};" +
"xhr.send();";
}
return "javascript: console.log('It is not a Blob URL');";
}
private void convertBase64StringToZipAndStoreIt(String base64Zip) throws IOException {
final int notificationId = 1;
String currentDateTime = DateFormat.getDateTimeInstance().format(new Date());
final File dwldsPath = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS) + "/YourFileName_" + currentDateTime + "_.zip");
byte[] zipAsBytes = Base64.decode(base64Zip.replaceFirst("^data:application/zip;base64,", ""), 0);
FileOutputStream os;
os = new FileOutputStream(dwldsPath, false);
os.write(zipAsBytes);
os.flush();
if(dwldsPath.exists()) {
NotificationCompat.Builder b = new NotificationCompat.Builder(context, "MY_DL")
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("MY TITLE")
.setContentText("MY TEXT CONTENT");
nm = (NotificationManager) this.context.getSystemService(Context.NOTIFICATION_SERVICE);
if(nm != null) {
nm.notify(notificationId, b.build());
Handler h = new Handler();
long delayInMilliseconds = 5000;
h.postDelayed(new Runnable() {
public void run() {
nm.cancel(notificationId);
}
}, delayInMilliseconds);
}
}
}
}
我知道我不清楚的一件事是在类中对xhr.open的调用应该使用哪个URL。
我还尝试使用onDownloadStart获得相同的结果。
任何见识都将受到赞赏!