28

I'm going to show a pdf in my application, and the pdf has to be bundled with the application.

What is a good way to do this?

I have read that it might be possible to do this by adding the pdf file to a res/raw folder and read it from there, but i get project errors when i put the pdf file there.

So i tried to put the pdf file in the asset folder of the project, and it gave no errors.

This is how i've tried to show the pdf:

File pdfFile = new File("res/raw/file.pdf");
Uri path = Uri.fromFile(pdfFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(path, "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

Any ideas or suggestions?

Thanks in advance

Ikky
  • 2,826
  • 14
  • 47
  • 68

6 Answers6

33

You cannot open the pdf file directly from the assets folder.You first have to write the file to sd card from assets folder and then read it from sd card.The code is as follows:-

     @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    File fileBrochure = new File(Environment.getExternalStorageDirectory() + "/" + "abc.pdf");
    if (!fileBrochure.exists())
    {
         CopyAssetsbrochure();
    } 

    /** PDF reader code */
    File file = new File(Environment.getExternalStorageDirectory() + "/" + "abc.pdf");      

    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.fromFile(file),"application/pdf");
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    try 
    {
        getApplicationContext().startActivity(intent);
    } 
    catch (ActivityNotFoundException e) 
    {
         Toast.makeText(SecondActivity.this, "NO Pdf Viewer", Toast.LENGTH_SHORT).show();
    }
}

//method to write the PDFs file to sd card
    private void CopyAssetsbrochure() {
        AssetManager assetManager = getAssets();
        String[] files = null;
        try 
        {
            files = assetManager.list("");
        } 
        catch (IOException e)
        {
            Log.e("tag", e.getMessage());
        }
        for(int i=0; i<files.length; i++)
        {
            String fStr = files[i];
            if(fStr.equalsIgnoreCase("abc.pdf"))
            {
                InputStream in = null;
                OutputStream out = null;
                try 
                {
                  in = assetManager.open(files[i]);
                  out = new FileOutputStream(Environment.getExternalStorageDirectory() + "/" + files[i]);
                  copyFile(in, out);
                  in.close();
                  in = null;
                  out.flush();
                  out.close();
                  out = null;
                  break;
                } 
                catch(Exception e)
                {
                    Log.e("tag", e.getMessage());
                } 
            }
        }
    }

 private void copyFile(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        int read;
        while((read = in.read(buffer)) != -1){
          out.write(buffer, 0, read);
        }
    }

Thats all..Enjoy!! and please dont forget to give +1.Thanks

varun
  • 3
  • 3
Deepak Sharma
  • 4,999
  • 5
  • 51
  • 61
  • 8
    As Lint in new version recommands.. Do not hardcode `/sdcard/`; use `Environment.getExternalStorageDirectory().getPath()` instead – Marcel Bro Mar 12 '13 at 23:38
  • 1
    Environment.getExternalStorageDirectory().getPath() + "/" to make this example work – max4ever Apr 18 '14 at 11:03
  • how to delete the pdf after the user read it? i tried using startActivityForResult but no luck – max4ever Apr 18 '14 at 11:21
25

You would be able to show it from raw/ or assets/ if your application actually implemented a PDF reader. Since you want it to be displayed in a separate application (such as Adobe Reader), I suggest doing the following:

  1. Store the PDF file in the assets/ directory.
  2. When the user wants to view it, copy it somewhere public. Look into openFileOutput or getExternalFilesDir.
  3. Launch the Intent just like you are doing now, except use getAbsolutePath() on the newly created file for the intent's data.

Be aware that a user might not have a PDF reading application. In this case, it is useful to catch the ActivityNotFoundException and show an appropriate message.

Felix
  • 88,392
  • 43
  • 149
  • 167
  • 5
    You can use the PackageManager's [queryIntentActivities](http://developer.android.com/reference/android/content/pm/PackageManager.html#queryIntentActivities(android.content.Intent,%20int)) method to check if any activity can respond to a given Intent. See [here](http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/scan/ScanIntent.java#) for an example – David Snabel-Caunt Jun 27 '11 at 10:31
  • @David I knew I was forgetting something! Thanks for adding that. – Felix Jun 27 '11 at 10:48
  • :) I have a feeling your answer is the best solution unless external applications can access package resources. – David Snabel-Caunt Jun 27 '11 at 11:01
3

I've used the following format to open raw resources from within my own application. I haven't tested whether another application can open your raw resource.

Uri path = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.myPdfName);
Shailendra Madda
  • 20,649
  • 15
  • 100
  • 138
David Snabel-Caunt
  • 57,804
  • 13
  • 114
  • 132
  • 1
    hmm, i have adobe reader installed on my device, but i get a ActivitynotFoundException. Any ideas? – Ikky Jun 27 '11 at 10:47
  • Either the URI or the mime type (or both) can't be matched, unfortunately I don't know how the Reader application matches. You might have to try with and without specifying the mime type, and try opening something from the SD card as it may be that it won't open from your raw resources at all. – David Snabel-Caunt Jun 27 '11 at 10:56
1

You pdf intent seems good but you should try this to get the Uri of file in the raw folder :

Uri path = Uri.parse("android.resource://<you package>/raw/<you file.pdf>");

(Source)

Alex K
  • 8,269
  • 9
  • 39
  • 57
Snicolas
  • 37,840
  • 15
  • 114
  • 173
0

I had various problems with the answers, so I pulled together something that works.

LAYOUT

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >


    <ImageView
        android:id="@+id/image_pdf"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/btn_okay"
        android:layout_margin="5dp"/>

    <Button
        android:id="@+id/btn_okay"
        android:layout_width="80dp"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="10dp"
        android:text="@string/ok"/>

</RelativeLayout>

CODE

/**
 * Render a page of a PDF into ImageView
 * @param targetView
 * @throws IOException
 */
private void openPDF(ImageView targetView) throws IOException {

    //open file in assets

    ParcelFileDescriptor fileDescriptor;

    String FILENAME = "your.pdf";

    // Create file object to read and write on
    File file = new File(getActivity().getCacheDir(), FILENAME);
    if (!file.exists()) {
        AssetManager assetManager = getActivity().getAssets();
        FileUtils.copyAsset(assetManager, FILENAME, file.getAbsolutePath());
    }

    fileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);

    PdfRenderer pdfRenderer = new PdfRenderer(fileDescriptor);

    //Display page 0
    PdfRenderer.Page rendererPage = pdfRenderer.openPage(0);
    int rendererPageWidth = rendererPage.getWidth();
    int rendererPageHeight = rendererPage.getHeight();
    Bitmap bitmap = Bitmap.createBitmap(
            rendererPageWidth,
            rendererPageHeight,
            Bitmap.Config.ARGB_8888);
    rendererPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);

    targetView.setImageBitmap(bitmap);
    rendererPage.close();
    pdfRenderer.close();
}


public static boolean copyAsset(AssetManager assetManager, String fromAssetPath, String toPath) {
    InputStream in = null;
    OutputStream out = null;
    try {
        in = assetManager.open(fromAssetPath);
        new File(toPath).createNewFile();
        out = new FileOutputStream(toPath);
        copyFile(in, out);
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
        return true;
    } catch(Exception e) {
        e.printStackTrace();
        return false;
    }
}

public static void copyFile(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024];
    int read;
    while((read = in.read(buffer)) != -1){
        out.write(buffer, 0, read);
    }
}
Someone Somewhere
  • 23,475
  • 11
  • 118
  • 166
-3

my apps needs to open a pdf file content in the raw data on external app ... im write:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button button = (Button) findViewById(R.id.OpenPdfButton);
    button.setOnClickListener(new View.OnClickListener() {
        InputStream is = getResources().openRawResource(R.raw.filepdf);

        @Override
        public void onClick(View v) {
           startpdf();
         }
           private void startpdf() {
            // TODO Auto-generated method stub

            File file = new File("R.id.filepdf");

            if (file.exists()) {
                Uri path = Uri.fromFile(file);
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setDataAndType(path, "application/pdf");
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

                try {
                    startActivity(intent);
                } 
                catch (ActivityNotFoundException e) {

                }
            }
        }


    });
}
}