首页 > 解决方案 > 如何在 SDK Q 及更高版本的下载文件夹中使用 FileProvider 和创建的 PFD

问题描述

最近我更新了一个面向 SDK 30 的应用程序,并调整了使用 Mediastore 创建和存储 PDF 的方式。对于创建和存储,我使用这段代码:

     @RequiresApi(api = Build.VERSION_CODES.Q)
    @NonNull
    private Uri savePDFFile(@NonNull final Context context, @NonNull byte[] in,
                            @NonNull final String mimeType,
                            @NonNull final String displayName, @Nullable final String subFolder) throws IOException {
        String relativeLocation = Environment.DIRECTORY_DOCUMENTS;

        if (!TextUtils.isEmpty(subFolder)) {
            relativeLocation += File.separator + subFolder;
        }

        final ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName);
        contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
        contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
        final ContentResolver resolver = context.getContentResolver();
        OutputStream stream = null;
        Uri uri = null;

        try {
            final Uri contentUri = MediaStore.Files.getContentUri("external");
            uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);
            ParcelFileDescriptor pfd;
            try {
                assert uri != null;
                pfd = context.getContentResolver().openFileDescriptor(uri, "w");
                assert pfd != null;
                FileOutputStream out = new FileOutputStream(pfd.getFileDescriptor());

                out.write(in);

                out.close();

                pfd.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

            contentValues.clear();
            contentValues.put(MediaStore.Video.Media.IS_PENDING, 0);
            context.getContentResolver().update(uri, contentValues, null, null);
            stream = resolver.openOutputStream(uri);
            if (stream == null) {
                throw new IOException("Failed to get output stream.");
            }
            return uri;
        } catch (IOException e) {
            // Don't leave an orphan entry in the MediaStore
            resolver.delete(uri, null, null);
            throw e;
        } finally {
            if (stream != null) {
                stream.close();
                  renderPDF(this.fileName, this.fileType);
            }
        }
    }

PDf 存储在 /storage/emulated/0/Download 中,一旦保存,我想按意图渲染它

        File path = Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_DOWNLOADS);
        File file = new File(path.toString() + "/" + fileName + "." + filetype);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        intent.setDataAndType(FileProvider.getUriForFile(this,  getPackageName() + ".provider",file), "application/pdf");

我的 provider_paths.xml 设置如下:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external"
        path="Download/" />
    <external-files-path
        name="external_files"
        path="Download/" />
    <files-path
        name="files"
        path="Download/" />
</paths>

此时,当您下载 pdf 时会显示您要选择的 pdf 阅读器,当您选择一个时会显示一条消息错误,提示路径太长?!?(已丢弃)或者 Google Drive Pdf 阅读器是否显示一毫秒空白屏幕并再次返回应用程序。

如何正确检索 pdf 文件并使用 FileProvider 启动意图?我认为此时问题出在 FileProvider 中,但我不知道如何...

        intent.setDataAndType(FileProvider.getUriForFile(this,  getPackageName() + ".provider",file), "application/pdf");

标签: javaandroidmediastoreandroid-fileprovider

解决方案


推荐阅读