【问题标题】:Read a pdf file from assets folder从 assets 文件夹中读取 pdf 文件
【发布时间】:2013-06-09 18:00:35
【问题描述】:
public void DOCS(View btnDocs)
{   
    File fileBrochure = new File("android.resource://com.project.datastructure/assets/abc.pdf");
    if (!fileBrochure.exists())
    {
         CopyAssetsbrochure();
    } 

    /** PDF reader code */
    File file = new File("android.resource://com.project.datastructure/assets/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(Stack_dr.this, "NO Pdf Viewer", Toast.LENGTH_SHORT).show();
    }
}
private void CopyAssetsbrochure() {
    AssetManager assetManager = getAssets();
    String[] files = null;
    try 
    {
        files = assetManager.list("");
    } 
    catch (IOException e){}
    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("/sdcard/" + files[i]);
              copyFile(in, out);
              in.close();
              in = null;
              out.flush();
              out.close();
              out = null;
              break;
            } 
            catch(Exception e){}
        }
    }
}

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

我正在尝试从我的应用程序文件夹中的 assets 文件夹中读取一个 pdf 文件。当我单击我的 DOCS 按钮时,一切正常,弹出一个窗口让我选择一个打开 pdf 的应用程序,即“abc.pdf”,但在选择一个选项后,我收到一条错误消息“文件路径无效”。我认为它们与我在代码中指定的路径存在一些问题。 请帮忙

【问题讨论】:

  • 您检查过复制的 pdf 文件是否真的存在于您的 SD 卡中吗?顺便说一句,您应该使用 Environment.getExternalStorageDirectory() 指定路径而不是“/sdcard/”
  • pdf 存在于我的资产文件夹中,将与应用程序一起提供

标签: java android pdf android-intent android-assets


【解决方案1】:

试试这个

public class SampleActivity extends Activity
    {

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

        }

        private void CopyReadAssets()
        {
            AssetManager assetManager = getAssets();

            InputStream in = null;
            OutputStream out = null;
            File file = new File(getFilesDir(), "abc.pdf");
            try
            {
                in = assetManager.open("abc.pdf");
                out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);

                copyFile(in, out);
                in.close();
                in = null;
                out.flush();
                out.close();
                out = null;
            } catch (Exception e)
            {
                Log.e("tag", e.getMessage());
            }

            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(
                    Uri.parse("file://" + getFilesDir() + "/abc.pdf"),
                    "application/pdf");

            startActivity(intent);
        }

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

    }

确保包含

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

在清单中

【讨论】:

  • 所以我们必须写入外部存储?没有副本可以直接打开吗?
  • @sunil 嗨,我正在尝试相同的代码,但出现错误 Activity not found。你能帮我看看为什么会这样
  • @poojagupta 未发现您在 Menifest 文件中未提及的活动,请检查清单文件
  • @sunil 我已经提到过,但 Intent intent = new Intent(Intent.ACTION_VIEW); 仍然出错intent.setDataAndType( Uri.parse("file://" + getFilesDir() + "/abc.pdf"), "application/pdf");开始活动(意图);
  • 在 Google 最近加强了 SD 卡的安全性之后,这仍然有效吗?
【解决方案2】:

比如sunsil,但在外部目录的情况下。

import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Environment;
import android.os.Bundle;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;


public class MainActivity extends Activity {

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

        copyReadAssets();
    }


    private void copyReadAssets()
    {
        AssetManager assetManager = getAssets();

        InputStream in = null;
        OutputStream out = null;

        String strDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+ File.separator + "Pdfs";
        File fileDir = new File(strDir);
        fileDir.mkdirs();   // crear la ruta si no existe
        File file = new File(fileDir, "example2.pdf");



        try
        {

            in = assetManager.open("example.pdf");  //leer el archivo de assets
            out = new BufferedOutputStream(new FileOutputStream(file)); //crear el archivo


            copyFile(in, out);
            in.close();
            in = null;
            out.flush();
            out.close();
            out = null;
        } catch (Exception e)
        {
            Log.e("tag", e.getMessage());
        }

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.parse("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + File.separator + "Pdfs" + "/example2.pdf"), "application/pdf");
        startActivity(intent);
    }

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

像这样更改部分代码:

out = new BufferedOutputStream(new FileOutputStream(file));

前面的例子是针对Pdfs的,如果是例子.txt

FileOutputStream fos = new FileOutputStream(file);

【讨论】:

    【解决方案3】:

    如果您想打开本地存储在 assets 文件夹中的 .pdf 文件而不使用 Intent 来启动外部应用程序,我建议使用 Android 类 PdfRenderer。发现文档here

    This 是一个对我有用的好例子。

    但是,当我下载此示例时,它无法运行。我不得不对其进行一些更改以使用其他答案here 中提到的 copyReadAssets() 函数,然后引用该文件(在复制后)我使用:

    File file = new File("/data/data/" + getContext().getPackageName() + "/files/mypdf.pdf");
    

    最后我还修改了 onAttach(),因为它使用了已弃用的 onAttach() 和 closeRenderer() 形式,因为它会在关闭为空的对象时抛出错误。

    所以我完整的 PdfRendererBasicFragment.java 文件如下所示:

    package com.example.android.pdfrendererbasic;
    
    import android.app.Activity;
    import android.app.Fragment;
    import android.content.Context;
    import android.content.res.AssetManager;
    import android.graphics.Bitmap;
    import android.graphics.pdf.PdfRenderer;
    import android.os.Bundle;
    import android.os.ParcelFileDescriptor;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.Toast;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    /**
     * This fragment has a big {@ImageView} that shows PDF pages, and 2 {@link android.widget.Button}s to move between
     * pages. We use a {@link android.graphics.pdf.PdfRenderer} to render PDF pages as {@link android.graphics.Bitmap}s.
     */
    public class PdfRendererBasicFragment extends Fragment implements View.OnClickListener {
    
        /**
         * Key string for saving the state of current page index.
         */
        private static final String STATE_CURRENT_PAGE_INDEX = "current_page_index";
    
        /**
         * File descriptor of the PDF.
         */
        private ParcelFileDescriptor mFileDescriptor;
    
        /**
         * {@link android.graphics.pdf.PdfRenderer} to render the PDF.
         */
        private PdfRenderer mPdfRenderer;
    
        /**
         * Page that is currently shown on the screen.
         */
        private PdfRenderer.Page mCurrentPage;
    
        /**
         * {@link android.widget.ImageView} that shows a PDF page as a {@link android.graphics.Bitmap}
         */
        private ImageView mImageView;
    
        /**
         * {@link android.widget.Button} to move to the previous page.
         */
        private Button mButtonPrevious;
    
        /**
         * {@link android.widget.Button} to move to the next page.
         */
        private Button mButtonNext;
    
        public PdfRendererBasicFragment() {
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false);
        }
    
        @Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            // Retain view references.
            mImageView = (ImageView) view.findViewById(R.id.image);
            mButtonPrevious = (Button) view.findViewById(R.id.previous);
            mButtonNext = (Button) view.findViewById(R.id.next);
            // Bind events.
            mButtonPrevious.setOnClickListener(this);
            mButtonNext.setOnClickListener(this);
            // Show the first page by default.
            int index = 0;
            // If there is a savedInstanceState (screen orientations, etc.), we restore the page index.
            if (null != savedInstanceState) {
                index = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, 0);
            }
            showPage(index);
        }
    
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            try {
                openRenderer(context);
            } catch (IOException e) {
                e.printStackTrace();
                Toast.makeText(context, "Error! " + e.getMessage(), Toast.LENGTH_SHORT).show();
                getActivity().finish();
            }
        }
    
        @Override
        public void onDetach() {
            try {
                closeRenderer();
            } catch (IOException e) {
                e.printStackTrace();
            }
            super.onDetach();
        }
    
        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            if (null != mCurrentPage) {
                outState.putInt(STATE_CURRENT_PAGE_INDEX, mCurrentPage.getIndex());
            }
        }
    
        /**
         * Sets up a {@link android.graphics.pdf.PdfRenderer} and related resources.
         */
        private void openRenderer(Context context) throws IOException {
            // Copy the pdf to a usable location
            CopyReadAssets();
    
            File file = new File("/data/data/" + context.getPackageName() + "/files/sample.pdf");
            mPdfRenderer = new PdfRenderer(ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
        }
    
        /**
         * Closes the {@link android.graphics.pdf.PdfRenderer} and related resources.
         *
         * @throws java.io.IOException When the PDF file cannot be closed.
         */
        private void closeRenderer() throws IOException {
            if (mCurrentPage != null) {
                mCurrentPage.close();
            }
    
            if (mPdfRenderer != null) {
                mPdfRenderer.close();
            }
    
            if (mFileDescriptor != null) {
                mFileDescriptor.close();
            }
        }
    
        /**
         * Shows the specified page of PDF to the screen.
         *
         * @param index The page index.
         */
        private void showPage(int index) {
            if (mPdfRenderer.getPageCount() <= index) {
                return;
            }
            // Make sure to close the current page before opening another one.
            if (null != mCurrentPage) {
                mCurrentPage.close();
            }
            // Use `openPage` to open a specific page in PDF.
            mCurrentPage = mPdfRenderer.openPage(index);
            // Important: the destination bitmap must be ARGB (not RGB).
            Bitmap bitmap = Bitmap.createBitmap(mCurrentPage.getWidth(), mCurrentPage.getHeight(),
                    Bitmap.Config.ARGB_8888);
            // Here, we render the page onto the Bitmap.
            // To render a portion of the page, use the second and third parameter. Pass nulls to get
            // the default result.
            // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
            mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
            // We are ready to show the Bitmap to user.
            mImageView.setImageBitmap(bitmap);
            updateUi();
        }
    
        /**
         * Updates the state of 2 control buttons in response to the current page index.
         */
        private void updateUi() {
            int index = mCurrentPage.getIndex();
            int pageCount = mPdfRenderer.getPageCount();
            mButtonPrevious.setEnabled(0 != index);
            mButtonNext.setEnabled(index + 1 < pageCount);
            getActivity().setTitle(getString(R.string.app_name_with_index, index + 1, pageCount));
        }
    
        /**
         * Gets the number of pages in the PDF. This method is marked as public for testing.
         *
         * @return The number of pages.
         */
        public int getPageCount() {
            return mPdfRenderer.getPageCount();
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.previous: {
                    // Move to the previous page
                    showPage(mCurrentPage.getIndex() - 1);
                    break;
                }
                case R.id.next: {
                    // Move to the next page
                    showPage(mCurrentPage.getIndex() + 1);
                    break;
                }
            }
        }
    
        private void CopyReadAssets()
        {
            AssetManager assetManager = getActivity().getAssets();
    
            InputStream in = null;
            OutputStream out = null;
            File file = new File(getActivity().getFilesDir(), "sample.pdf");
    
            if(!file.exists()) {
                try {
                    in = assetManager.open("sample.pdf");
                    out = getActivity().openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);
    
                    copyFile(in, out);
                    in.close();
                    in = null;
                    out.flush();
                    out.close();
                    out = null;
                } catch (Exception e) {
                    Log.e("tag", e.getMessage());
                }
            }
            else {
                Log.d("test", "file already exists");
            }
        }
    
        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);
            }
        }
    
    }
    

    【讨论】:

      【解决方案4】:

      虽然已经回答了这个问题,但我想分享我的解决方案,因为我认为它更容易包含在内。

      用法:

      new OpenLocalPDF(context, 'nameOfPDFStoredInAssets').execute()
      

      这里是OpenLocalPDF 类:

      public class OpenLocalPDF {
      
          private static String TAG = OpenLocalPDF.class.getSimpleName();
      
          private WeakReference<Context> contextWeakReference;
          private String fileName;
      
          public OpenLocalPDF(Context context, String fileName) {
              this.contextWeakReference = new WeakReference<>(context);
              this.fileName = fileName.endsWith("pdf") ? fileName : fileName + ".pdf";
          }
      
          public void execute() {
      
              Context context = contextWeakReference.get();
              if (context != null) {
                  new CopyFileAsyncTask().execute();
              }
      
          }
      
      
          private class CopyFileAsyncTask extends AsyncTask<Void, Void, File> {
      
      
              final String appDirectoryName = BuildConfig.APPLICATION_ID;
              final File fileRoot = new File(Environment.getExternalStoragePublicDirectory(
                      Environment.DIRECTORY_DOCUMENTS), appDirectoryName);
      
              @Override
              protected File doInBackground(Void... params) {
      
                  Context context = contextWeakReference.get();
      
                  AssetManager assetManager = context.getAssets();
      
                  File file = new File(fileRoot, fileName);
      
                  InputStream in = null;
                  OutputStream out = null;
                  try {
      
                      file.mkdirs();
      
                      if (file.exists()) {
                          file.delete();
                      }
      
                      file.createNewFile();
      
      
                      in = assetManager.open(fileName);
                      Log.d(TAG, "In");
      
                      out = new FileOutputStream(file);
                      Log.d(TAG, "Out");
      
                      Log.d(TAG, "Copy file");
                      copyFile(in, out);
      
                      Log.d(TAG, "Close");
                      in.close();
      
                      out.flush();
                      out.close();
      
                      return file;
                  } catch (Exception e)
                  {
                      Log.e(TAG, e.getMessage());
                  }
      
                  return null;
              }
      
              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);
                  }
              }
      
              @Override
              protected void onPostExecute(File file) {
                  super.onPostExecute(file);
      
                  Context context = contextWeakReference.get();
      
      
                  Intent intent = new Intent(Intent.ACTION_VIEW);
                  intent.setDataAndType(
                          Uri.fromFile(file),
                          "application/pdf");
      
                  context.startActivity(intent);
      
              }
          }
      }
      

      Manifest.xml中添加此权限

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

      【讨论】:

      • 亲爱的@RunLoop,这不是一个特别有建设性的评论。我在生产中使用它,所以我知道它在我的设置中有效。如果您想详细说明它对您不起作用的原因,那么也许我会花时间帮助您。
      【解决方案5】:

      试试这个:

      public String getAssetsPdfPath(Context context) {
      String filePath = context.getFilesDir() + File.separator + "myFile.pdf";
      File destinationFile = new File(filePath);
      
      try {
      FileOutputStream outputStream = new FileOutputStream(destinationFile);
      InputStream inputStream = context.getAssets().open("myFile.pdf");
      byte[] buffer = new byte[1024];
      int length = 0;
      while ((length = inputStream.read(buffer)) != -1) {
      outputStream.write(buffer, 0, length);
      }
      outputStream.close();
      inputStream.close();
      } catch (IOException e) {
      Log.e(context.getClass().getSimpleName(), "Error.");
      }
      
      return destinationFile.getPath();
      }
      

      【讨论】:

        【解决方案6】:

        此代码适用于每个 android 版本:

        活动:

        import android.app.Activity;
        import android.content.Intent;
        import android.content.pm.PackageManager;
        import android.content.res.AssetManager;
        import android.net.Uri;
        import android.os.Environment;
        import android.os.Bundle;
        import android.support.v4.app.ActivityCompat;
        import android.support.v4.content.ContextCompat;
        import android.support.v4.content.FileProvider;
        import android.util.Log;
        import android.widget.Toast;
        
        import java.io.BufferedOutputStream;
        import java.io.File;
        import java.io.FileOutputStream;
        import java.io.IOException;
        import java.io.InputStream;
        import java.io.OutputStream;
        
        import unimedbh.UnimedBH.R;
        
        
        public class MainActivity extends Activity {
        
            private static final int MY_PERMISSION_REQUEST_STORAGE = 1;
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        
                if (ContextCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        
                   ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSION_REQUEST_STORAGE); 
        
                } else {
                    copyReadAssets("YOUR_PDF_NAME.pdf");
                }
            }
        
        
            private void copyReadAssets(String fileName) {
                String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyFiles";
                File dir = new File(dirPath);
        
                if (!dir.exists()) {
                    dir.mkdirs();
                }
        
                AssetManager assetManager = getAssets();
                InputStream in = null;
                OutputStream out = null;
        
                try {
                    in = assetManager.open(fileName);
                    File outFile = new File(dirPath, fileName);
                    out = new FileOutputStream(outFile);
                    copyFile(in, out);
        
                    Intent intent = new Intent(Intent.ACTION_VIEW, FileProvider.getUriForFile(this, "com.package.name.fileprovider", outFile));
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_ACTIVITY_NO_HISTORY);
        
                    startActivity(intent);
                } catch (IOException e) {
                    e.printStackTrace();
                    Toast.makeText(this, "Error!", Toast.LENGTH_SHORT).show();
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
        
                    if (out != null) {
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        
            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);
                }
            }
        }
        

        Manifest.xml:

        <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.package.name.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths" />
        </provider>
        

        file_paths.xml:

        <paths>
            <files-path name="app_directory" path="directory/"/>
        </paths>
        

        在 API 16-28 中测试,适用于所有 API!

        【讨论】:

          【解决方案7】:

          您可以这样做(经过测试并使用 API 27)

          第 1 步

          在您的应用程序 gradle 中添加以下依赖项:

          implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'
          

          第 2 步

          添加以下 XML 代码:

          <com.github.barteksc.pdfviewer.PDFView
                   android:id="@+id/pdfv"
                   android:layout_width="match_parent"
                   android:layout_height="match_parent"> 
          </com.github.barteksc.pdfviewer.PDFView>
          

          第 3 步

          在您的 java 文件中添加以下代码:

          public class MainActivity extends AppCompatActivity {
          
              PDFView pdfView;
          
              @Override
              protected void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
                  setContentView(R.layout.activity_main);
                  pdfView=findViewById(R.id.pdfv);
                  pdfView.fromAsset("filename.pdf").load();
              }
          }
          

          这些更改将在您创建活动时加载 PDF 文件。

          【讨论】:

          • @ViddyutKhanvilkar 它只是没有加载任何东西,但这是我的一些错误。我现在正在使用另一种方法来处理 pdf
          • @Felipe Santiago。你采取了什么方法?
          • 我可以在服务器中使用这种方法制作在线 pdf 吗?
          • @DavidKariuki 如果我记得,我做了类似的事情stackoverflow.com/a/14578661/4407308
          • barteksc 库在 apk 中占用了这么多空间。
          【解决方案8】:

          我取得了成功,使用来自cYrixmorten 的答案,使用 OpenLocalPDF 类。

          但是,Android 18 不支持 Environment.DIRECTORY_DOCUMENTS。为了支持 Android 18 - 28,我必须进行以下更改。

          在“CopyFileAsyncTask”中,更改fileRoot声明:

          final File fileRoot = new File(Environment.getExternalStoragePublicDirectory(
                  Environment.DIRECTORY_DOCUMENTS), appDirectoryName);
          

          到这里:

          final File fileRoot = new File(Environment.getExternalStorageDirectory() + "/YourAppName");
          

          在“onPostExecute”中,改变这个:

          Intent intent = new Intent(Intent.ACTION_VIEW);
          intent.setDataAndType(
                  Uri.fromFile(file),
                  "application/pdf");
          context.startActivity(intent);
          

          到这里:

          Intent intent = new Intent(Intent.ACTION_VIEW);
          intent.setDataAndType(FileProvider.getUriForFile(context, "com.example.yourappname.provider", file), "application/pdf");
          intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
          context.startActivity(intent);
          

          最后,设置您的清单以支持FileProvider,如本文所述。

          【讨论】:

            【解决方案9】:

            这对我有用。

            第 1 步: 在 MainActivity.java 中

            public class SampleActivity extends Activity  {
            
             @Override
             protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
            
                //call this method by passing file name in params.
                readFromAssets("User guide.pdf");
             }
            
            public static void readFromAssets(String fileName) {
                AssetManager assetManager = getAssets();
                InputStream in = null;
                OutputStream out = null;
                File file = new File(mContext.getFilesDir(), fileName);
                try {
                    in = assetManager.open(fileName);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        out = mContext.openFileOutput(file.getName(), Context.MODE_PRIVATE);
                    } else {
                        out = mContext.openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);
                    }
                    copyFile(in, out);
                    in.close();
                    in = null;
                    out.flush();
                    out.close();
                    out = null;
                } catch (Exception e) {
                    Log.e("tag", e.getMessage());
                }
                Uri pdfFileURI;
                Intent intent = new Intent(Intent.ACTION_VIEW);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    pdfFileURI = FileProvider.getUriForFile(mContext,
                            BuildConfig.APPLICATION_ID + ".provider", file);
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                } else {
                    pdfFileURI = Uri.parse("file://" + mContext.getFilesDir() + "/" + fileName);
                }
                intent.setDataAndType(pdfFileURI, "application/pdf");
                mContext.startActivity(intent);
             }
            
               private 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);
                 }
               }
            }
            

            第 2 步:res-&gt;xml-&gt;provider_paths.xml 中创建 provider_paths.xml。见here

            <?xml version="1.0" encoding="utf-8"?>
            <paths>
              <external-path
                name="external"
                path="." />
              <root-path
                name="root"
                path="." />
            </paths>
            

            第 3 步:在 AndroidManifest.xml 中

            <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
            
            <application
                android:icon="@mipmap/ic_launcher"
                android:label="@string/app_name"
                android:theme="@style/AppThemeMaterial">
            
              <!-- INSIDE APPLICATION TAG -->
            
              <provider
                    android:name="androidx.core.content.FileProvider"
                    android:authorities="${applicationId}.provider"
                    android:exported="false"
                    android:grantUriPermissions="true">
                    <meta-data
                        android:name="android.support.FILE_PROVIDER_PATHS"
                        android:resource="@xml/provider_paths"/>
              </provider>
            </application>     
            

            【讨论】:

              【解决方案10】:

              尝试通过资产文件夹中的意图(在我的情况下为 PDF)打开文件时,没有开箱即用的答案。所以这是我的解决方案,结合了 2 个出色的答案,我相信它会对某人有所帮助。必须为 api >= 24。

              一旦您遵循此link 并添加您自己的GenericFileProvider 并在Application 标记内的清单中声明它并创建provider_paths.xml,只需使用以下类并将其命名为:

              OpenLocalPDF(this, "YOUR_PDF_NAME_IN_ASSETS_FOLDER.pdf").execute()

              OpenLocalPdf.kt:(也感谢 OP https://stackoverflow.com/a/41212708/1133011

              import android.content.Context
              import android.content.Intent
              import android.content.res.AssetManager
              import android.os.AsyncTask
              import android.util.Log
              import androidx.core.content.FileProvider
              import java.io.File
              import java.io.FileOutputStream
              import java.io.InputStream
              import java.io.OutputStream
              import java.lang.ref.WeakReference
              
              class OpenLocalPDF(context: Context?, fileName: String?) {
                  private val contextWeakReference: WeakReference<Context?>?
                  private val fileName: String?
                  fun execute() {
                      val context: Context = contextWeakReference!!.get()!!
                      if (context != null) {
                          CopyFileAsyncTask().execute()
                      }
                  }
              
                  private inner class CopyFileAsyncTask :
                      AsyncTask<Void?, Void?, File?>() {
                      val appDirectoryName: String? = co.za.umbiflow.BuildConfig.APPLICATION_ID
                      val fileRoot: File? = File(
                          android.os.Environment.getExternalStoragePublicDirectory(
                              android.os.Environment.DIRECTORY_DOCUMENTS
                          ), appDirectoryName
                      )
              
                      override fun doInBackground(vararg params: Void?): File? {
                          val context: Context = contextWeakReference!!.get()!!
                          val assetManager: AssetManager = context.getAssets()
                          val file = File(fileRoot, fileName)
                          var `in`: InputStream? = null
                          var out: OutputStream? = null
                          try {
                              file.mkdirs()
                              if (file.exists()) {
                                  file.delete()
                              }
                              file.createNewFile()
                              `in` = assetManager.open(fileName)
                              out = FileOutputStream(file)
                              copyFile(`in`, out)
                              `in`.close()
                              out.flush()
                              out.close()
                              return file
                          } catch (e: Exception) {
                              Log.e(TAG, e.message)
                          }
                          return null
                      }
              
                      private fun copyFile(`in`: InputStream, out: OutputStream) {
                          val buffer = ByteArray(1024)
                          var read: Int
                          while (`in`.read(buffer).also { read = it } != -1) {
                              out.write(buffer, 0, read)
                          }
                      }
              
                      override fun onPostExecute(file: File?) {
                          super.onPostExecute(file)
                          val context: Context = contextWeakReference!!.get()!!
              
                          var pdfUri =
                              FileProvider.getUriForFile(
                                  context,
                                  context.packageName + ".provider",
                                  file!!
                              )
              
                          val intent = Intent()
                          intent.action = Intent.ACTION_VIEW
                          intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                          intent.setDataAndType(
                              pdfUri,
                              "application/pdf"
                          )
                          context.startActivity(intent)
                      }
                  }
              
                  companion object {
                      private val TAG = OpenLocalPDF::class.java.simpleName
                  }
              
                  init {
                      contextWeakReference = WeakReference(context)
                      this.fileName = if (fileName!!.endsWith("pdf")) fileName else "$fileName.pdf"
                  }
              }
              

              【讨论】:

                【解决方案11】:

                这是一种使用 zip 文件从资产中打开多个 PDF 文件的方法。

                Step1:将 zip 文件 (pdf.zip) 复制到包含 pdf 列表的 assets 文件夹中

                第 2 步:将 PDF 写入应用程序内部的 Utils 类的外部缓存中

                public static void writePDFs(Context context) {
                        try {
                            InputStream inputStream = context.getApplicationContext().getAssets().open("pdf.zip");
                            ZipInputStream zipInputStream = new ZipInputStream(inputStream);
                            ZipEntry zipEntry;
                            File file = new File(context.getExternalCacheDir().getAbsolutePath(), "PDFs");
                            if (!file.getAbsoluteFile().exists()) {
                                if (file.mkdir()) {
                                    BufferedOutputStream outputStream;
                                    byte[] buffer = new byte[1024];
                                    int count;
                                    while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                                        String s1 = file + "/" + zipEntry.getName();
                                        File file1 = new File(s1);
                                        if (!file1.exists()) {
                                            file1.createNewFile();
                                        }
                                        outputStream = new BufferedOutputStream(new FileOutputStream(file1));
                                        while ((count = zipInputStream.read(buffer)) != -1) {
                                            outputStream.write(buffer, 0, count);
                                        }
                                        outputStream.flush();
                                        outputStream.close();
                                        zipInputStream.closeEntry();
                                    }
                                }
                                zipInputStream.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                

                Step3:在Activities onCreate中调用上述函数

                @Override
                    protected void onCreate(@Nullable Bundle savedInstanceState) {
                        super.onCreate(savedInstanceState);
                        FileUtils.writePDFs(this);
                }
                

                Step4:在Utils类中创建一个打开PDF的常用函数

                public static void openPDF(Activity activity, String fileName) {
                        if (activity == null) return;
                        File file = new File(activity.getExternalCacheDir().getAbsolutePath() + "/PDFs" + "/" + fileName);
                        Uri docUri = GenericFileProvider.getUriForFile(activity, activity.getApplicationContext().getPackageName(), file);
                        try {
                            Intent intent = new Intent();
                            intent.setAction(Intent.ACTION_VIEW);
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                                intent.setDataAndType(docUri, "application/pdf");
                            } else {
                                intent.setDataAndType(Uri.fromFile(file), "application/pdf");
                            }
                            activity.startActivityForResult(intent, ACTIVITY_VIEW_ATTACHMENT);
                        } catch (ActivityNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                

                Step5:在Activity中点击视图调用openPDF函数

                myView.setOnClickListener(v -> ApplicationUtils.openPDF(this, "MyPdfFile.pdf"));
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-03-09
                  • 2023-03-24
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-11-21
                  • 1970-01-01
                  • 2018-01-19
                  相关资源
                  最近更新 更多