Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download file from base64 url in android webview

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>
like image 354
Elnoor Avatar asked Oct 05 '17 06:10

Elnoor


1 Answers

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();
    }
like image 165
Elnoor Avatar answered Oct 15 '22 23:10

Elnoor