I'm working on an Android app with a webview pointing to a dynamic website by another team.
When i download a file (mostly dynamically redirected PDF and ZIP) all i get is a file in the downloads folder containing some HTML code with a message like "user not allowed to read the file", no matter how i implement the download, i tried:
all with the same results.
Navigating with normal browsers downloads work fine, both on desktop PC, android and iOS devices.
Why webview shouldn't have access to files?
May be a session issue? http port?
I really need some ideas...
Another tip: when downloading twice a file from the same link, the link will redirect to the same file but resulting in two different filenames...
EDIT: Instead of pointing the webView to the web-app, i tried to point to a common webpage with a link-redirect to download another file, well, simply it works.
Here are the webview.setDownloadListener - onDownloadStart()
parameters:
userAgent=Mozilla/5.0 (Linux; Android 4.4.2; Nexus 7 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36
contentDisposition=attachment;
filename=correct_filename.pdf,
url=http://www.xxx.xx/site/downloadfile.wplus?REDIRECTFILE=D-507497120&ID_COUNTOBJ=ce_5_home&TYPEOBJ=CExFILE&LN=2
mimeType=application/octet-stream
Here's some code
wv.getSettings().setSupportMultipleWindows(true);
wv.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
wv.getSettings().setAllowFileAccess(true);
wv.getSettings().setJavaScriptEnabled(true);
wv.getSettings().setBuiltInZoomControls(true);
wv.getSettings().setDisplayZoomControls(false);
wv.getSettings().setLoadWithOverviewMode(true);
wv.getSettings().setUseWideViewPort(true);
wv.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.setDescription("Download file...");
request.setTitle(URLUtil.guessFileName(url, contentDisposition, mimetype));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //Notify client once download is 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_LONG).show();
}
}
EDIT II
Here's the code i'm using when trying to download files "by hand":
onDownloadStart() is where i call downloadFileAsync():
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
String fileName;
try {
fileName = URLUtil.guessFileName(url, contentDisposition, mimeType);
downloadFileAsync(url, fileName);
}catch (Exception e){
}
}
and this is the AsyncTask:
private void downloadFileAsync(String url, String filename){
new AsyncTask<String, Void, String>() {
String SDCard;
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(String... params) {
try {
URL url = new URL(params[0]);
HttpURLConnection urlConnection = null;
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.connect();
int lengthOfFile = urlConnection.getContentLength();
//SDCard = Environment.getExternalStorageDirectory() + File.separator + "downloads";
SDCard = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+"";
int k = 0;
boolean file_exists;
String finalValue = params[1];
do {
if (k > 0) {
if (params[1].length() > 0) {
String s = params[1].substring(0, params[1].lastIndexOf("."));
String extension = params[1].replace(s, "");
finalValue = s + "(" + k + ")" + extension;
} else {
String fileName = params[0].substring(params[0].lastIndexOf('/') + 1);
String s = fileName.substring(0, fileName.lastIndexOf("."));
String extension = fileName.replace(s, "");
finalValue = s + "(" + k + ")" + extension;
}
}
File fileIn = new File(SDCard, finalValue);
file_exists = fileIn.exists();
k++;
} while (file_exists);
File file = new File(SDCard, finalValue);
FileOutputStream fileOutput = null;
fileOutput = new FileOutputStream(file, true);
InputStream inputStream = null;
inputStream = urlConnection.getInputStream();
byte[] buffer = new byte[1024];
int count;
long total = 0;
while ((count = inputStream.read(buffer)) != -1) {
total += count;
//publishProgress(""+(int)((total*100)/lengthOfFile));
fileOutput.write(buffer, 0, count);
}
fileOutput.flush();
fileOutput.close();
inputStream.close();
} catch (MalformedURLException e){
} catch (ProtocolException e){
} catch (FileNotFoundException e){
} catch (IOException e){
} catch (Exception e){
}
return params[1];
}
@Override
protected void onPostExecute(final String result) {
}
}.execute(url, filename);
}
taken from How to download a PDF from a dynamic URL in a webview
Thanx
Simply put, Android WebView allows apps to display web content, without having to open a web browser. Up to Android 6, WebView was a system service. Then, with Android 7.0, Google incorporated that functionality into the default Chrome Browser.
The first is by opening the list of system apps installed on your device, locating Android System WebView and enabling it. The second is by searching the app in the Google Play store and enabling it from there.
The WebView class is an extension of Android's View class that allows you to display web pages as a part of your activity layout. It does not include any features of a fully developed web browser, such as navigation controls or an address bar. All that WebView does, by default, is show a web page.
Go to the webpage where you want to download a file. Touch and hold what you want to download, then tap Download link or Download image. To see all the files you've downloaded to your device, open the Downloads app. Learn more about managing downloaded files.
Finally i decided to look for the DownloadHandler from the Android Stock Browser code. The only noticeable lack in my code was cookie (!!!).
Here's my final working version (DownloadManager method):
wv.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);
//------------------------COOKIE!!------------------------
String cookies = CookieManager.getInstance().getCookie(url);
request.addRequestHeader("cookie", cookies);
//------------------------COOKIE!!------------------------
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_LONG).show();
}
});
With this option I managed to download complete files, the download worked with other options but the documents appeared empty, especially when a session is being used.
Add below lines to AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Add DownloadListener to your WebView
Try this code
wv.setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(final String url, final String userAgent, String contentDisposition, String mimetype, long contentLength) {
//Checking runtime permission for devices above Marshmallow.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v(TAG, "Permission is granted");
downloadDialog(url, userAgent, contentDisposition, mimetype);
} else {
Log.v(TAG, "Permission is revoked");
//requesting permissions.
ActivityCompat.requestPermissions(PortalActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
} else {
//Code for devices below API 23 or Marshmallow
Log.v(TAG, "Permission is granted");
downloadDialog(url, userAgent, contentDisposition, mimetype);
}
}
});
//downloadDialog Method
public void downloadDialog(final String url, final String userAgent, String contentDisposition, String mimetype) {
//getting filename from url.
final String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
//alertdialog
AlertDialog.Builder builder = new AlertDialog.Builder(this);
//title of alertdialog
builder.setTitle(R.string.download_title);
//message of alertdialog
builder.setMessage(getString(R.string.download_file) + ' ' + filename);
//if Yes button clicks.
builder.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//DownloadManager.Request created with url.
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
//cookie
String cookie = CookieManager.getInstance().getCookie(url);
//Add cookie and User-Agent to request
request.addRequestHeader("Cookie", cookie);
request.addRequestHeader("User-Agent", userAgent);
//file scanned by MediaScannar
request.allowScanningByMediaScanner();
//Download is visible and its progress, after completion too.
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//DownloadManager created
DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
//Saving files in Download folder
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
//download enqued
downloadManager.enqueue(request);
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//cancel the dialog if Cancel clicks
dialog.cancel();
mWebView.goBack();
}
});
//alertdialog shows.
builder.show();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With