如何打开存储在res/raw或assets文件夹中的PDF文件?

28

我要在我的应用程序中展示一个PDF文件,这个文件必须与应用程序一起打包。

有什么好的方法可以做到这一点吗?

我已经阅读过可能通过将PDF文件添加到res/raw文件夹并从那里读取来实现此目的,但是当我把PDF文件放在那里时,我得到了项目错误。

因此,我尝试将PDF文件放在项目的asset文件夹中,这没有出现任何错误。

这是我尝试展示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);

有什么想法或建议吗?

谢谢提前。

6个回答

33

你不能直接从资产文件夹中打开PDF文件。你首先需要将文件从资产文件夹写入SD卡,然后再从SD卡中读取它。代码如下:

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

就这些了...享受吧!请不要忘记点赞+1。谢谢。


8
在新版本中,Lint建议不要硬编码/sdcard/,而是使用Environment.getExternalStorageDirectory().getPath() - Marcel Bro
1
Environment.getExternalStorageDirectory().getPath() + "/" 为使此示例工作。 - max4ever
如何在用户阅读完PDF后删除它?我尝试使用startActivityForResult但没有成功。 - max4ever

25
如果您的应用程序实际上实现了PDF阅读器,您可以从raw/assets/中显示它。由于您希望它在单独的应用程序(如Adobe Reader)中显示,我建议您执行以下操作:
  1. 将PDF文件存储在assets/目录中。
  2. 当用户想要查看它时,将其复制到某个公共位置。可以查看openFileOutputgetExternalFilesDir
  3. 像现在一样启动Intent,除了使用新创建的文件的getAbsolutePath()作为意图的数据外,不要做其他修改。
请注意,用户可能没有PDF阅读应用程序。在这种情况下,捕获ActivityNotFoundException并显示适当的消息是有用的。

5
你可以使用PackageManager的queryIntentActivities方法来检查是否有任何活动可以响应给定的Intent。请参阅此处的示例:http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/scan/ScanIntent.java# - David Snabel-Caunt
@David 我知道自己忘了点什么!谢谢你加上了那个。 - Felix
我觉得你的答案是最佳解决方案,除非外部应用程序可以访问包资源。 - David Snabel-Caunt

3

我曾使用以下格式从自己的应用程序中打开原始资源。我没有测试过其他应用程序是否可以打开您的原始资源。

Uri path = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.myPdfName);

1
嗯,我在设备上安装了Adobe Reader,但是出现了ActivitynotFoundException异常。有什么想法吗? - Ikky
很遗憾,URI或MIME类型(或两者都)无法匹配,我不知道Reader应用程序如何进行匹配。您可能需要尝试指定或不指定MIME类型,并尝试从SD卡中打开某些内容,因为它可能根本无法从原始资源中打开。 - David Snabel-Caunt

1

你的PDF意图看起来不错,但是你应该尝试这个方法来获取raw文件夹中文件的Uri:

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

(来源)


0

我在答案方面遇到了各种问题,所以我整理了一些可行的东西。

布局

<?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>

代码

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

-3

我的应用程序需要在外部应用程序中打开原始数据中的PDF文件内容...我写道:

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) {

                }
            }
        }


    });
}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接