Tuesday, March 19, 2013

Android - WebView download/open PDF generated by TCPDF url

Recently, I came across a request to put a mobile website into an app, so people won't need to navigate the browser to access the pages.

WebView is a very nice API to serve this purpose, and this doesn't need to invoke the original mobile website design and coding.

The first challenging thing is I need to successfully download the PDF files that are generated by TCPDF in run time. Since WebView does not handle this kind of request automatically like the typically desktop browsers do, such as chrome or firefox etc. I got to adding code to WebVeiw how to handle the PDF which is generated by TCPDF.

I found that there were not even a Q&A like stackoverflow mentioned WebView with TCPDF. Anyway, there were still some Q&A about WebView and PDF/file download. But, most of the examples and questions are about downloading a physical file on server which is not exactly the same as working with TCPDF. But those materials are still helpful to me, a newbie of Android, a lot to figure out a solution.

So, now I want to share how this can be achieved, even the code may be raw, but this works for me.


First, initialing the download in setDownloadListener in onCreate Activity, after WebView instant is created, like the following:

        WebView myWebView = (WebView) findViewById(R.id.webview);
        myWebView.setWebViewClient(new WebViewClient());            
     
        myWebView.setDownloadListener(new DownloadListener() {
            @Override
            public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {            
                //start download
                DownloadPDF downloadPDF = new DownloadPDF();
                downloadPDF.execute(url,userAgent,contentDisposition);
            }                    
        });
     
        WebSettings webSettings = myWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        myWebView.loadUrl("http://www.examlple.com");                  
 

And then, adding a private class DownloadPDF() which extends Asynctask like below:

private class DownloadPDF extends AsyncTask<String, Integer, String> {                      
        @Override
        protected String doInBackground(String... sUrl) {  
            try {
            URL url = new URL(sUrl[0]);            
         
                File myDir = new File(Environment.getExternalStoragePublicDirectory(
                        Environment.DIRECTORY_DOWNLOADS).toString()+"/myPDF");
             
                // create the directory if it does not exist
                if (!myDir.exists()) myDir.mkdirs();          

                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setDoOutput(true);        
                connection.connect();          

                //get filename from the contentDisposition
                String filename = null;
                Pattern p = Pattern.compile("\"([^\"]*)\"");
Matcher m = p.matcher(sUrl[2]);
                while (m.find()) {
                filename = m.group(1);
                }      

                File outputFile = new File(myDir, filename);

                InputStream input   = new BufferedInputStream(connection.getInputStream());
                OutputStream output = new FileOutputStream(outputFile);
                           
                byte data[] = new byte[1024];
                long total = 0;
                int count;
                while ((count = input.read(data)) != -1) {
                    total += count;                  
                    output.write(data, 0, count);
                }              
                connection.disconnect();
                output.flush();
                output.close();
                input.close();
             
                // displayPdf();  a function to open the PDF file automatically
           
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                 e.printStackTrace();
            }
            return null;
        }
    }

Lastly, remember to add permission in Mainifest.xml:


<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />.



Done. The next thing to do is "Open the PDF file automatically".




5 comments:

Fuensalida P said...

If you use login services in Android not working properly. We modified piece of code to pass the cookie to the native part.

http://stackoverflow.com/questions/27526518/managed-cookie-in-cordova-with-android

Unknown said...

Hey @early
I hope you can help me.

I have done exactly as you said.

If you want I can send you the .xml and main.java file too.

When I click on any hyperlink to .pdf it does nothing. I have a pdf viewer installed on my phone.
Can you please solve my issue?

Thanks.

early said...

Hi @Ultimate Papers,

I don't know if your way to open a PDF is exactly the same as mine.
You want to open a PDF by clicking a Hyperlink that points to a PDF file. my guess is something like href="your pdf file"

However, this doesn't work with my code.

My code is mainly for open a PHP file which is rendering PDF by TCPDF Library, then download to the client browser.

Hope this helps.

Ameen Click said...

Thanks... I was looking for this for sometime now...

Unknown said...

I am using streamsaver (https://github.com/jimmywarting/StreamSaver) to generate a download of a stream received by me which is not directly downloadable from the other website eg. of streamsaver generated url
http://localhost:4000/localhost:3000localhost:4000/286303/19%3A55%3A19%3A361.webm
such urls are downloadable in chrome PC or mobile (version 90) but fails in my webview code which is like yours and this webview code downloads files from external websites but fails get from this streamsaver url. and errors at this line inputStream = new BufferedInputStream(urlConnection.getInputStream());
Will be thankful for any ideas.