4

I have a website that is navigated from within a webview. One of the pages generates a ZIP file that is downloaded via a BLOB URL. I discovered that this is not supported by webview, so I have tried implementing this solution:

Download Blob file from Website inside Android WebViewClient

However, it is not working for me. Breakpoints in convertBase64StringToZipAndStoreIt are never hit.

UPDATE: I've found that I'm getting an HTTP 404. I've tried using blobUrl and blobUrl.substring(5) and the result is the same either way. The BLOBs are downloading fine in Chrome, though.

Webview setup:

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");
}

Function called from shouldOverrideUrlLoading() (only the else condition for BLOB URLs is of concern):

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 class:

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);
        }
    }
}

}

One thing I know I am unclear on is what URL should be going into the call to xhr.open in the class.

I also tried using onDownloadStart with the same result.

Any insight is greatly appreciated!

E. Neal
  • 41
  • 1
  • 4

0 Answers0