Am new to Java concepts. I am trying to download contents generated from JavaScript of my html file in android assets but the application crashes the moment I click on the download button. I suppose that I have to create a JavaScript interface to communicate with Java however I don’t know how to do that and would like to get help on that. How can I download the file generated by JavaScript in webview?
package com.fun.fun;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.app.DownloadManager;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.webkit.URLUtil;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private WebView web;
// application crashes if I download a file generated from script side of the following url;
String webUrl = "file:///android_asset/indexi.html";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
web = (WebView) findViewById(R.id.myweb);
web.loadUrl(webUrl);
WebSettings mywebsettings = web.getSettings();
mywebsettings.setJavaScriptEnabled(true);
web.setWebViewClient(new WebViewClient());
//improve webview performance
web.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
web.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
web.getSettings().setAppCacheEnabled(true);
web.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
mywebsettings.setDomStorageEnabled(true);
mywebsettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
mywebsettings.setUseWideViewPort(true);
mywebsettings.setSavePassword(true);
mywebsettings.setSaveFormData(true);
mywebsettings.setEnableSmoothTransition(true);
//External storage permission for saving file
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.M){
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED){
Log.d("permission","permission denied to WRITE_EXTERNAL_STORAGE - requesting it");
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissions,1);
}
}
//handle downloading
web.setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setMimeType(mimeType);
String cookies = CookieManager.getInstance().getCookie(url);
request.addRequestHeader("cookie",cookies);
request.addRequestHeader("User-Agent",userAgent);
request.setDescription("Downloading file....");
request.setTitle(URLUtil.guessFileName(url,contentDisposition,mimeType));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,URLUtil.guessFileName(url, contentDisposition, mimeType));
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
dm.enqueue(request);
Toast.makeText(getApplicationContext(),"Downloading File",Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onBackPressed() {
if(web.canGoBack()){
web.goBack();
}
else {
super.onBackPressed();
}
}
}
And my html file that I have loaded in webview is;
<html>
<div id="disp"></div>
<script>
function objectsToCSV(arr) {
const array = [Object.keys(arr[0])].concat(arr)
return array.map(row => {
return Object.values(row).map(value => {
return typeof value === 'string' ? JSON.stringify(value) : value }).toString()
}).join('n') }
var items = [
{ "name": "Item 1", "color": "Green", "size": "X-Large" },
{ "name": "Item 2", "color": "Green", "size": "X-Large" },
{ "name": "Item 3", "color": "Green", "size": "X-Large" }];
var csv = objectsToCSV(items);
document.getElementById("disp").innerHTML = csv;
function downloadCSV(csv) {
const blob = new Blob([csv], { type: 'text/csv' });
const anchor = document.createElement('a');
anchor.href = window.URL.createObjectURL(blob);
anchor.download = 'my_data.csv';
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
}
const downloadButton = document.createElement('button');
downloadButton.textContent = 'Download CSV';
downloadButton.addEventListener('click', () => {
downloadCSV(csv);
});
document.body.appendChild(downloadButton);
</script>
</html>
2
Answers
Hello to anyone facing the same problem of downloading their JavaScript generated file use JavaScript interface as shown below; Thanks to @blackapps suggestions.
In your HTML code;
In Mainactivity.java
Someone to improve on detecting the file type after decoding.
Have a great day!
You cannot use DownloadManager for what you want. You wil get something like:
Now with a little googling we found that all has been reported before and solved.
I just tried the suggestions and it worked for me using your indexi.html file:
Unable to download Blob file type in WebView on Android
Download Blob file from Website inside Android WebViewClient
Only had to change a few things to make it work for a html file loaded from assets.
Please edit the subject of your post to include loading html from assets and changing pdf to csv or txt.