43

I am trying to write an app to download PDFs from a URL, store them on SD, then open by Adobe PDF reader or other apps (which ever is able to open the PDF).

Until now, I had "successfully downloaded and stored it on SD card" (but every time when I try to open the PDF with a PDF reader, the reader crashes and says an unexpected error occurs), for example, http://maven.apache.org/maven-1.x/maven.pdf

Here is the code for my downloader:

//........code set ui stuff
//........code set ui stuff
     new DownloadFile().execute(fileUrl, fileName); 


private class DownloadFile extends AsyncTask<String, Void, Void>{

        @Override
        protected Void doInBackground(String... strings) {
            String fileUrl = strings[0];   // -> http://maven.apache.org/maven-1.x/maven.pdf
            String fileName = strings[1];  // -> maven.pdf
            String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
            File folder = new File(extStorageDirectory, "testthreepdf");
            folder.mkdir();

            File pdfFile = new File(folder, fileName);

            try{
                pdfFile.createNewFile();
            }catch (IOException e){
                e.printStackTrace();
            }
            FileDownloader.downloadFile(fileUrl, pdfFile);
            return null;
        }
    }



public class FileDownloader {
    private static final int  MEGABYTE = 1024 * 1024;

    public static void downloadFile(String fileUrl, File directory){
        try {

            URL url = new URL(fileUrl);
            HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.setDoOutput(true);
            urlConnection.connect();

            InputStream inputStream = urlConnection.getInputStream();
            FileOutputStream fileOutputStream = new FileOutputStream(directory);
            int totalSize = urlConnection.getContentLength();

            byte[] buffer = new byte[MEGABYTE];
            int bufferLength = 0;
            while((bufferLength = inputStream.read(buffer))>0 ){
                fileOutputStream.write(buffer, 0, bufferLength);
            }
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

In debug mode, I can see the app downloaded it and stored this PDF on /storage/sdcard/testpdf/maven.pdf. However, I guess the file may be corrupted somehow during downloading, so it doesn't open up properly...

Here is the code how I intend to open it with another reader app:

File pdfFile = new File(Environment.getExternalStorageDirectory() + "/testthreepdf/" + fileName);  // -> filename = maven.pdf
                    Uri path = Uri.fromFile(pdfFile);
                    Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
                    pdfIntent.setDataAndType(path, "application/pdf");
                    pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

                    try{
                        startActivity(pdfIntent);
                    }catch(ActivityNotFoundException e){
                        Toast.makeText(documentActivity, "No Application available to view PDF", Toast.LENGTH_SHORT).show();
                    }
Null
  • 1,950
  • 9
  • 30
  • 33
sefirosu
  • 2,558
  • 7
  • 44
  • 69

4 Answers4

88

Hi the problem is in FileDownloader class

 urlConnection.setRequestMethod("GET");
    urlConnection.setDoOutput(true);

You need to remove the above two lines and everything will work fine. Please mark the question as answered if it is working as expected.

Latest solution for the same problem is updated Android PDF Write / Read using Android 9 (API level 28)

Attaching the working code with screenshots.

enter image description here

enter image description here

MainActivity.java

package com.example.downloadread;

import java.io.File;
import java.io.IOException;

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public void download(View v)
    {
        new DownloadFile().execute("http://maven.apache.org/maven-1.x/maven.pdf", "maven.pdf"); 
    }

    public void view(View v)
    {
        File pdfFile = new File(Environment.getExternalStorageDirectory() + "/testthreepdf/" + "maven.pdf");  // -> filename = maven.pdf
        Uri path = Uri.fromFile(pdfFile);
        Intent pdfIntent = new Intent(Intent.ACTION_VIEW);
        pdfIntent.setDataAndType(path, "application/pdf");
        pdfIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        try{
            startActivity(pdfIntent);
        }catch(ActivityNotFoundException e){
            Toast.makeText(MainActivity.this, "No Application available to view PDF", Toast.LENGTH_SHORT).show();
        }
    }

    private class DownloadFile extends AsyncTask<String, Void, Void>{

        @Override
        protected Void doInBackground(String... strings) {
            String fileUrl = strings[0];   // -> http://maven.apache.org/maven-1.x/maven.pdf
            String fileName = strings[1];  // -> maven.pdf
            String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
            File folder = new File(extStorageDirectory, "testthreepdf");
            folder.mkdir();

            File pdfFile = new File(folder, fileName);

            try{
                pdfFile.createNewFile();
            }catch (IOException e){
                e.printStackTrace();
            }
            FileDownloader.downloadFile(fileUrl, pdfFile);
            return null;
        }
    }


}

FileDownloader.java

package com.example.downloadread;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class FileDownloader {
    private static final int  MEGABYTE = 1024 * 1024;

    public static void downloadFile(String fileUrl, File directory){
        try {

            URL url = new URL(fileUrl);
            HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
            //urlConnection.setRequestMethod("GET");
            //urlConnection.setDoOutput(true);
            urlConnection.connect();

            InputStream inputStream = urlConnection.getInputStream();
            FileOutputStream fileOutputStream = new FileOutputStream(directory);
            int totalSize = urlConnection.getContentLength();

            byte[] buffer = new byte[MEGABYTE];
            int bufferLength = 0;
            while((bufferLength = inputStream.read(buffer))>0 ){
                fileOutputStream.write(buffer, 0, bufferLength);
            }
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.downloadread"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="18" />
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.downloadread.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="15dp"
        android:text="download"
        android:onClick="download" />

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/button1"
        android:layout_marginTop="38dp"
        android:text="view"
        android:onClick="view" />

</RelativeLayout>
Zack Dawood
  • 2,230
  • 20
  • 18
  • 1
    HI Zack, by removing those two lines, it works, I can download and read on my mobile device. but somehow, each time i tried to read the DLed pdf on emulator, it crashes, any idea why? i use this adobe reader apk -> http://www.appsapk.com/adobe-reader/ did you read on emulator or your device? thx – sefirosu Jul 15 '14 at 08:55
  • 1
    and also, i wish to know why by removing those two lines, the app works? what is the story behind the scene? thx – sefirosu Jul 15 '14 at 08:59
  • 2
    My understanding is when downloading PDF from desktop application you need to specify GET / POST, however in Android decides how to download based on the response code. Hence that line is not required. Also the doOutput is not required as we are streaming and writing to the pdf file. Let me know if you need more details. Thanks for marking it as answered. Have a good day. – Zack Dawood Jul 15 '14 at 10:22
  • have you tried to load with adobe pdf reader within emulator? everytime i load pdf within emulator, it crashes and unexpected error – sefirosu Jul 15 '14 at 10:53
  • Hi use the default reader in Emulator, for adobe reader please use only the app in android app store. These appsapk.com/adobe-reader apk might be buggy. I have tested in actual devices with Adobe reader it is working. the screen shot which i have attached is from actual device. Please uninstall the adobe reader app and try again. The unexpected error you see in Adobe reader cannot be debugged because it happens in a apk where you dont have the source code. – Zack Dawood Jul 15 '14 at 11:33
  • Man You Saved Me ! Thanks. – Bassem Qoulta Jan 12 '17 at 23:32
  • @MohammedZackria-Zack Your Code is not work You not set Your code in any button listner how Your code work – Ashish Shahi Jun 24 '17 at 06:59
  • @MohammedZackria-Zack I am waste My Time In Your Code Nothing result found – Ashish Shahi Jun 24 '17 at 07:00
  • @AshishShahi the listener is set in activity_main.xml android:onClick="download" which calls the method download in the class MainActivity.java. Please debug and traverse the code to troubleshoot. This is 100% working code, i have tested again today. – Zack Dawood Jun 25 '17 at 15:51
  • @AshishShahi did you use all the code or used only some ? All the files needs to be same. Make sure you use the following files MainActivity.java FileDownloader.java AndroidManifest.xml activity_main.xml – Zack Dawood Jun 25 '17 at 15:53
  • 2
    @MohammedZackria-Zack Your Example is Good But some Problem When I am Open another Pdf Previous File Deleted Automatically . Please Say Me How can I Prevent File Delete Please Help Me – Ashish Shahi Jun 26 '17 at 04:47
  • @AshishShahi as per my code it opens only one pdf file which is hard coded. You need to open a new problem in Stackoverflow with code so we can suggest or troubleshoot. The code in the example opens only one pdf file which is http://maven.apache.org/maven-1.x/maven.pdf. The file is stored in the physical location, probably you are overwritting with the same name. – Zack Dawood Jun 27 '17 at 10:44
  • @MohammedZackria-Zack Your Tell Right But My Requirement is File Is downloaded if same File Exist then replace another wise create new file – Ashish Shahi Jun 27 '17 at 11:05
  • @AshishShahi Please open another problem with the your code and details. As per my code only one file will be downloaded. – Zack Dawood Jun 28 '17 at 11:15
  • Ok Thanks For Paying Attantion – Ashish Shahi Jun 28 '17 at 11:19
  • I just tried this code and I can't get it to work. Created a new project and copy pasted everything. I get the error that the PDF file can not be viewed. Do you have any ideas on why this is happening? I've tried to open it with three different pdf viewers and none of them can open the downloaded file. Thanks for any help! – nullforlife Jul 06 '17 at 15:46
  • @nullforlife check your logcat log file and see the error message. Or else debug the code and traverse. Let us know the error message. Which version of android you are using ? Are you using actual device or emulator ? – Zack Dawood Jul 06 '17 at 22:08
  • @MohammedZackria-Zack, I fixed it. I had "Exception 'open failed: EACCES (Permission denied)'" , seems that you need to request permission on API level > 23. Look into this question for more information: https://stackoverflow.com/questions/8854359/exception-open-failed-eacces-permission-denied-on-android I just added his code and ran it in onCreate (and accepted permissions) and your code worked fine. – nullforlife Jul 07 '17 at 07:16
  • @nullforlife Thank you for sharing the fix – Zack Dawood Jul 07 '17 at 14:26
  • @ZackDawood I run your code but it is not working, no errors nothing, If you want to see my code I have asked a question in SO. Here is the link. https://stackoverflow.com/questions/55816746/filedownloader-at-the-android-it-is-showing-no-errors-but-the-download-does-not – TheCoderGuy Apr 24 '19 at 08:40
  • 1
    @Spritzig I have updated the solution on your problem https://stackoverflow.com/questions/55816746/filedownloader-at-the-android-it-is-showing-no-errors-but-the-download-does-not/56313094#56313094 – Zack Dawood May 26 '19 at 11:32
10

This is the best method to download and view PDF file.You can just call it from anywhere as like

PDFTools.showPDFUrl(context, url);

here below put the code. It will works fine

 public class PDFTools {
    private static final String TAG = "PDFTools";
    private static final String GOOGLE_DRIVE_PDF_READER_PREFIX = "http://drive.google.com/viewer?url=";
    private static final String PDF_MIME_TYPE = "application/pdf";
    private static final String HTML_MIME_TYPE = "text/html";

   
    public static void showPDFUrl(final Context context, final String pdfUrl ) {
        if ( isPDFSupported( context ) ) {
            downloadAndOpenPDF(context, pdfUrl);
        } else {
            askToOpenPDFThroughGoogleDrive( context, pdfUrl );
        }
    }

   
    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
    public static void downloadAndOpenPDF(final Context context, final String pdfUrl) {
        // Get filename
        //final String filename = pdfUrl.substring( pdfUrl.lastIndexOf( "/" ) + 1 );
        String filename = "";
        try {
            filename = new GetFileInfo().execute(pdfUrl).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        // The place where the downloaded PDF file will be put
        final File tempFile = new File( context.getExternalFilesDir( Environment.DIRECTORY_DOWNLOADS ), filename );
        Log.e(TAG,"File Path:"+tempFile);
        if ( tempFile.exists() ) {
            // If we have downloaded the file before, just go ahead and show it.
            openPDF( context, Uri.fromFile( tempFile ) );
            return;
        }

        // Show progress dialog while downloading
        final ProgressDialog progress = ProgressDialog.show( context, context.getString( R.string.pdf_show_local_progress_title ), context.getString( R.string.pdf_show_local_progress_content ), true );

        // Create the download request
        DownloadManager.Request r = new DownloadManager.Request( Uri.parse( pdfUrl ) );
        r.setDestinationInExternalFilesDir( context, Environment.DIRECTORY_DOWNLOADS, filename );
        final DownloadManager dm = (DownloadManager) context.getSystemService( Context.DOWNLOAD_SERVICE );
        BroadcastReceiver onComplete = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if ( !progress.isShowing() ) {
                    return;
                }
                context.unregisterReceiver( this );

                progress.dismiss();
                long downloadId = intent.getLongExtra( DownloadManager.EXTRA_DOWNLOAD_ID, -1 );
                Cursor c = dm.query( new DownloadManager.Query().setFilterById( downloadId ) );

                if ( c.moveToFirst() ) {
                    int status = c.getInt( c.getColumnIndex( DownloadManager.COLUMN_STATUS ) );
                    if ( status == DownloadManager.STATUS_SUCCESSFUL ) {
                        openPDF( context, Uri.fromFile( tempFile ) );
                    }
                }
                c.close();
            }
        };
        context.registerReceiver( onComplete, new IntentFilter( DownloadManager.ACTION_DOWNLOAD_COMPLETE ) );

        // Enqueue the request
        dm.enqueue( r );
    }

    
    public static void askToOpenPDFThroughGoogleDrive( final Context context, final String pdfUrl ) {
        new AlertDialog.Builder( context )
                .setTitle( R.string.pdf_show_online_dialog_title )
                .setMessage( R.string.pdf_show_online_dialog_question )
                .setNegativeButton( R.string.pdf_show_online_dialog_button_no, null )
                .setPositiveButton( R.string.pdf_show_online_dialog_button_yes, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        openPDFThroughGoogleDrive(context, pdfUrl);
                    }
                })
                .show();
    }

    public static void openPDFThroughGoogleDrive(final Context context, final String pdfUrl) {
        Intent i = new Intent( Intent.ACTION_VIEW );
        i.setDataAndType(Uri.parse(GOOGLE_DRIVE_PDF_READER_PREFIX + pdfUrl ), HTML_MIME_TYPE );
        context.startActivity( i );
    }
    
    public static final void openPDF(Context context, Uri localUri ) {
        Intent i = new Intent( Intent.ACTION_VIEW );
        i.setDataAndType( localUri, PDF_MIME_TYPE );
        context.startActivity( i );
    }
    
    public static boolean isPDFSupported( Context context ) {
        Intent i = new Intent( Intent.ACTION_VIEW );
        final File tempFile = new File( context.getExternalFilesDir( Environment.DIRECTORY_DOWNLOADS ), "test.pdf" );
        i.setDataAndType( Uri.fromFile( tempFile ), PDF_MIME_TYPE );
        return context.getPackageManager().queryIntentActivities( i, PackageManager.MATCH_DEFAULT_ONLY ).size() > 0;
    }

    // get File name from url
    static class GetFileInfo extends AsyncTask<String, Integer, String>
    {
        protected String doInBackground(String... urls)
        {
            URL url;
            String filename = null;
            try {
                url = new URL(urls[0]);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.connect();
                conn.setInstanceFollowRedirects(false);
                if(conn.getHeaderField("Content-Disposition")!=null){
                    String depo = conn.getHeaderField("Content-Disposition");

                    String depoSplit[] = depo.split("filename=");
                    filename = depoSplit[1].replace("filename=", "").replace("\"", "").trim();
                }else{
                    filename = "download.pdf";
                }
            } catch (MalformedURLException e1) {
                e1.printStackTrace();
            } catch (IOException e) {
            }
            return filename;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            // use result as file name
        }
    }

}

try it. it will work, enjoy

Jijo
  • 510
  • 7
  • 13
  • 4
    this is bit long process – Anand Savjani May 09 '18 at 15:27
  • 1
    This worked for me after replacing openPDF method like openPDF(context, FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".my.package.name.provider", tempFile)); Its described here:https://stackoverflow.com/a/38858040/1492681 – ilker Feb 04 '19 at 11:35
  • 4
    Be wary though that the Google webservice `http://drive.google.com/viewer` was not officially launched for public consumption as an API and that they can take it down anytime without any public notice. – Abel Callejo Feb 07 '19 at 06:32
  • for an online step yes it's fine. But for offline one ? @jijo – gumuruh Mar 13 '22 at 20:16
5

Download source code from here (Open Pdf from url in Android Programmatically)

MainActivity.java

package com.deepshikha.openpdf;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;

public class MainActivity extends AppCompatActivity {
    WebView webview;
    ProgressBar progressbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webview = (WebView)findViewById(R.id.webview);
        progressbar = (ProgressBar) findViewById(R.id.progressbar);
        webview.getSettings().setJavaScriptEnabled(true);
        String filename ="http://www3.nd.edu/~cpoellab/teaching/cse40816/android_tutorial.pdf";
        webview.loadUrl("http://docs.google.com/gview?embedded=true&url=" + filename);

        webview.setWebViewClient(new WebViewClient() {

            public void onPageFinished(WebView view, String url) {
                // do your stuff here
                progressbar.setVisibility(View.GONE);
            }
        });

    }
}

Thanks!

Deepshikha Puri
  • 2,104
  • 22
  • 23
1
String imageurl = response.optString("PdfUrl");
                            DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
                            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(imageurl));

                            request.allowScanningByMediaScanner();
                            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //Notify client once download is completed!


                            dm.enqueue(request);