11

I am writing a webview app in which i can download files from (html tag) urls to device. I can download files like png/jpg/pdf etc, but when url is a base64 string value i don't know how to download it. Can someone help me to achieve that?

For example, when the below html link clicked file abc.png can be downloaded easily

<a href="http://web.com/abc.png" download >Download</a>

But when url is base64 like below, webview can't download the "file":

<a href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA..." download>Download</a>
Elnoor
  • 3,401
  • 4
  • 24
  • 39
  • @DimaKozhevin no, it is not same question. I don't want to load image to webview, i want to convert base64 to file and save it to device – Elnoor Oct 06 '17 at 03:27

3 Answers3

20

I could manage to save base64 encoded data as a file. So, the basic short answer to my question was decoding encoded data to bytes and writing it to a file like this:

String base64EncodedString = encodedDataUrl.substring(encodedDataUrl.indexOf(",") + 1);
byte[] decodedBytes = Base64.decode(base64EncodedString, Base64.DEFAULT);
OutputStream os = new FileOutputStream(file);
os.write(decodedBytes);
os.close();

Just for reference for others who may come up with the same question I am adding my final code below. Inside onCreate() method i am handling file downloads like this:

webView.setDownloadListener(new DownloadListener() {
    @Override
    public void onDownloadStart(String url, String userAgent,
                                String contentDisposition, String mimeType,
                                long contentLength) {

        if (url.startsWith("data:")) {  //when url is base64 encoded data
            String path = createAndSaveFileFromBase64Url(url);
            return;
        }

        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(getResources().getString(R.string.msg_downloading));
        String filename = URLUtil.guessFileName(url, contentDisposition, mimeType);
        request.setTitle(filename);
        request.allowScanningByMediaScanner();
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
        DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        dm.enqueue(request);
        Toast.makeText(getApplicationContext(), R.string.msg_downloading, Toast.LENGTH_LONG).show();
    }
});

And createAndSaveFileFromBase64Url() method which deals with base64 encoded data looks like this:

public String createAndSaveFileFromBase64Url(String url) {
        File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        String filetype = url.substring(url.indexOf("/") + 1, url.indexOf(";"));
        String filename = System.currentTimeMillis() + "." + filetype;
        File file = new File(path, filename);
        try {
            if(!path.exists())
                path.mkdirs();
            if(!file.exists())
                file.createNewFile();

            String base64EncodedString = url.substring(url.indexOf(",") + 1);
            byte[] decodedBytes = Base64.decode(base64EncodedString, Base64.DEFAULT);
            OutputStream os = new FileOutputStream(file);
            os.write(decodedBytes);
            os.close();

            //Tell the media scanner about the new file so that it is immediately available to the user.
            MediaScannerConnection.scanFile(this,
                    new String[]{file.toString()}, null,
                    new MediaScannerConnection.OnScanCompletedListener() {
                        public void onScanCompleted(String path, Uri uri) {
                            Log.i("ExternalStorage", "Scanned " + path + ":");
                            Log.i("ExternalStorage", "-> uri=" + uri);
                        }
                    });

            //Set notification after download complete and add "click to view" action to that
            String mimetype = url.substring(url.indexOf(":") + 1, url.indexOf("/"));
            Intent intent = new Intent();
            intent.setAction(android.content.Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(file), (mimetype + "/*"));
            PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);

            Notification notification = new NotificationCompat.Builder(this)
                                                        .setSmallIcon(R.mipmap.ic_launcher)
                                                        .setContentText(getString(R.string.msg_file_downloaded))
                                                        .setContentTitle(filename)
                                                        .setContentIntent(pIntent)
                                                        .build();

            notification.flags |= Notification.FLAG_AUTO_CANCEL;
            int notificationId = 85851;
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.notify(notificationId, notification);
        } catch (IOException e) {
            Log.w("ExternalStorage", "Error writing " + file, e);
            Toast.makeText(getApplicationContext(), R.string.error_downloading, Toast.LENGTH_LONG).show();
        }

        return file.toString();
    }
Elnoor
  • 3,401
  • 4
  • 24
  • 39
  • 1
    Your code gives me the following error, can you help me with this?: `android.os.FileUriExposedException: file:///storage/emulated/0/Download/1548198938835.png exposed beyond app through Intent.getData() at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799) at android.net.Uri.checkFileUriExposed(Uri.java:2346) at android.content.Intent.prepareToLeaveProcess(Intent.java:8965) at android.content.Intent.prepareToLeaveProcess(Intent.java:8926) at android.app.PendingIntent.getActivity(PendingIntent.java:340)` – Lenin Meza Jan 22 '19 at 23:23
  • 2
    @LeninMeza this maybe helpful https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed – Elnoor Jan 22 '19 at 23:36
0

If you are using Java 1.8, you can try with

     import java.util.Base64;

     public class DecodeBase64 {

     public static void main(String []args){
        String encodedUrl = "aHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNDY1NzkyMzcvZG93bmxvYWQtZmlsZS1mcm9tLWJhc2U2NC11cmwtaW4tYW5kcm9pZC13ZWJ2aWV3LzQ2NTc5MzE0";
        byte[] decodedBytes = Base64.getUrlDecoder().decode(encodedUrl);
        String result = new String(decodedBytes);
        System.out.println(result);
     }
}

output should be:

https://stackoverflow.com/questions/46579237/download-file-from-base64-url-in-android-webview/46579314

0

First of all you need to convert this base64 string to bitmap image format than try to download that.

you can convert your string like this.

public static Bitmap decodeBase64(String input)
{
    byte[] decodedByte = Base64.decode(input, Base64.DEFAULT); 


    return BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length);
}

it will return bitmap of your base64.

Tejas Pandya
  • 3,987
  • 1
  • 26
  • 51
  • Ok, after i created bitmap, what i should do with that ? – Elnoor Oct 05 '17 at 06:43
  • you can set this bitmap in any hidden imageview .like this imageview.setImageBitmap(bitmap); after that . you can download that easily . as you downloaded before – Tejas Pandya Oct 05 '17 at 06:47
  • Sorry, i still didn't get that. For other files there is an html tag like: download and basically clicking on it will download it – Elnoor Oct 05 '17 at 06:52
  • As you mentioned in your question you can download file from html tag . now whats the matter? – Tejas Pandya Oct 05 '17 at 06:56
  • If url contains file path/name i can download it, but if the url is base64 i can't. it is that simple – Elnoor Oct 05 '17 at 06:58
  • After following processes i mentioned you need to visit this.. 'https://stackoverflow.com/questions/38820673/saving-an-image-from-imageview-into-internal-storage' – Tejas Pandya Oct 05 '17 at 07:08