下载PDF并显示它(FileUriExposedException)

时间:2018-02-12 21:46:16

标签: java android android-studio pdf

作为序言,我熟悉编码(在高中2年),但对于Android Studio(以及一般的Java)来说,我是一个完整的新手。我一直在为我的问题寻找解决方案,但由于我的经验不足,我不知道如何为我的项目实施解决方案。

简而言之,我需要从一些外部URL下载pdf,将其存储到外部存储中,并使用一些pdf-viewer应用程序显示它。我一直在收到错误:

  

...

     

android.os.FileUriExposedException:file:///storage/emulated/0/pdf/Read.pdf通过Intent.getData()暴露在app之外

     

...

我一直在使用this source on using an intent to open a pdf-viewerthis source on "File Provider"作为参考。

以下是我到目前为止:

Fire(带有可点击的 TextView ,应该下载并显示pdf)

public class Fire extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_fire);
    final TextView testButton = findViewById(R.id.testPDF);
    // File file = getFilesDir();

    testButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(Fire.this, pdfView.class);
            startActivity(intent);
        }
    });

pdfView活动

public class pdfView extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_pdf_view);
    String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
    File folder = new File(extStorageDirectory, "pdf");
    folder.mkdir();
    File file = new File(folder, "Read.pdf");
    try {
        file.createNewFile();
    } catch (IOException e1) {
        e1.printStackTrace();
    }
    Downloader.DownloadFile(__PDF_URL___, file);

    showPdf();
}
public void showPdf()
{
    File file = new File(Environment.getExternalStorageDirectory()+"/pdf/Read.pdf");
    PackageManager packageManager = getPackageManager();
    Intent testIntent = new Intent(Intent.ACTION_VIEW);
    testIntent.setType("application/pdf");
    List list = packageManager.queryIntentActivities(testIntent, PackageManager.MATCH_DEFAULT_ONLY);
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_VIEW);
    Uri uri = Uri.fromFile(file);
    intent.setDataAndType(uri, "application/pdf");
    startActivity(intent);
}

下载程序类

public class Downloader {

public static void DownloadFile(String fileURL, File directory) {
try {

        FileOutputStream f = new FileOutputStream(directory);
        URL u = new URL(fileURL);
        HttpURLConnection c = (HttpURLConnection) u.openConnection();
        c.setRequestMethod("GET");
        c.setDoOutput(true);
        c.connect();

        InputStream in = c.getInputStream();

        byte[] buffer = new byte[1024];
        int len1 = 0;
        while ((len1 = in.read(buffer)) > 0) {
            f.write(buffer, 0, len1);
        }
        f.close();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

根据我的研究,似乎我的问题源于我使用URI而不是“文件提供程序”。此外,实现“文件提供者”的解决方案似乎以某种形式使用 Context ,而我对上下文的目的是什么以及如何实现它感到困惑。

如果你没有答案那么好。任何有关如何理解或甚至理解这个概念的信息对我来说都足够了。

1 个答案:

答案 0 :(得分:0)

如果你的targetSdkVersion> = 24,那么我们必须使用FileProvider类来访问特定文件或文件夹,以使其可供其他应用访问。

1)首先在AndroidManifest.xml中的标签下添加一个FileProvider标签,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    <application
        ...
        <provider
            android:name=".GenericFileProvider"
            android:authorities="${applicationId}.my.package.name.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
    </application>
</manifest>

2)然后在res / xml文件夹中创建provider_paths.xml文件。如果文件夹不存在,则可能需要创建文件夹。

<paths>
    <external-path name="external_files" path="."/>
</paths>

3)现在创建PdfDownload.java类文件并粘贴到代码下面:

public class PdfDownload extends Activity {
    TextView tv_loading;
    Context context;

    int downloadedSize = 0, totalsize;
    float per = 0;

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

        tv_loading = new TextView(this);
        tv_loading.setGravity(Gravity.CENTER);
        tv_loading.setTypeface(null, Typeface.BOLD);
        setContentView(tv_loading);
        downloadAndOpenPDF();
    }


    public static String getLastBitFromUrl(final String url) {
        return url.replaceFirst(".*/([^/?]+).*", "$1");
    }

    void downloadAndOpenPDF() {
        final String download_file_url = getIntent().getStringExtra("url");
        new Thread(new Runnable() {
            public void run() {
                Uri path = Uri.fromFile(downloadFile(download_file_url));
                try {
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    Uri uri = FileProvider.getUriForFile(PdfDownload.this, BuildConfig.APPLICATION_ID, downloadFile(download_file_url));
                    intent.setDataAndType(uri, "application/pdf");
                    startActivity(intent);
                    finish();


                } catch (ActivityNotFoundException e) {
                    tv_loading
                            .setError("PDF Reader application is not installed in your device");
                }
            }
        }).start();

    }

    File downloadFile(String dwnload_file_path) {
        File file = null;
        try {
            URL url = new URL(dwnload_file_path);
            HttpURLConnection urlConnection = (HttpURLConnection) url
                    .openConnection();

            urlConnection.connect();

            String test = getLastBitFromUrl(dwnload_file_path);
            String dest_file_path = test.replace("%20", "_");
            // set the path where we want to save the file
            File SDCardRoot = Environment.getExternalStorageDirectory();
            // // create a new file, to save the downloaded file
            file = new File(SDCardRoot, dest_file_path);
            if (file.exists()) {
                return file;
            }
            FileOutputStream fileOutput = new FileOutputStream(file);

            // Stream used for reading the data from the internet
            InputStream inputStream = urlConnection.getInputStream();

            // this is the total size of the file which we are
            // downloading
            totalsize = urlConnection.getContentLength();
            setText("Starting PDF download...");

            // create a buffer...
            byte[] buffer = new byte[1024 * 1024];
            int bufferLength = 0;

            while ((bufferLength = inputStream.read(buffer)) > 0) {
                fileOutput.write(buffer, 0, bufferLength);
                downloadedSize += bufferLength;
                per = ((float) downloadedSize / totalsize) * 100;
                if ((totalsize / 1024) <= 1024) {
                    setText("Total PDF File size  : " + (totalsize / 1024)
                            + " KB\n\nDownloading PDF " + (int) per + "% complete");
                } else {
                    setText("Total PDF File size  : " + (totalsize / 1024) / 1024
                            + " MB\n\nDownloading PDF " + (int) per + "% complete");
                }
                // setText("configuring your book pleease wait a moment");
            }
            // close the output stream when complete //
            fileOutput.close();
            // setText("Download Complete. Open PDF Application installed in the device.");
            setText("configuaration is completed now your book is ready to read");
        } catch (final MalformedURLException e) {
            setTextError("Some error occured. Press back and try again.",
                    Color.RED);
        } catch (final IOException e) {
            setTextError("Some error occured. Press back and try again.",
                    Color.RED);
        } catch (final Exception e) {
            setTextError(
                    "Failed to download image. Please check your internet connection.",
                    Color.RED);
        }
        return file;
    }

    void setTextError(final String message, final int color) {
        runOnUiThread(new Runnable() {
            public void run() {
                tv_loading.setTextColor(color);
                tv_loading.setText(message);
            }
        });
    }

    void setText(final String txt) {
        runOnUiThread(new Runnable() {
            public void run() {
                tv_loading.setText(txt);
            }
        });

    }

    private static final String TAG = "MyActivity";

    public boolean isStoragePermissionGranted() {
        if (Build.VERSION.SDK_INT >= 23) {
            if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                Log.v(TAG, "Permission is granted");
                return true;
            } else {

                Log.v(TAG, "Permission is revoked");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                return false;
            }
        } else { //permission is automatically granted on sdk<23 upon installation
            Log.v(TAG, "Permission is granted");
            return true;
        }


    }


    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG, "Permission: " + permissions[0] + "was " + grantResults[0]);

        }
    }

}