【问题标题】:File Provider Android 11文件提供程序 Android 11
【发布时间】:2022-12-15 18:21:31
【问题描述】:

由于在 Android 11、SDK 30 上进行的存储访问更改,我更改了保存 PDF 文件和图像的路径。

之前,我用这个:

File file = new File(Environment.getExternalStorageDirectory() + "/" + folderName + "/" + fileName);

这是文件提供者:

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

这是路径更改前的 provider_paths.xml:

<paths>
    <external-path name="external_files" path="myFolder/"/>
    <files-path name="files" path="docs/" />
</paths>

现在,我改变了路径:

 File file = new File(context.getExternalFilesDir(null) + "/" + folderName + "/" + fileName);

PDF 文件和图像已成功保存。

但是,当我尝试在应用程序中从我的 PDFView 共享 PDF 时,应用程序在 FileProvider.getUriForFile(...) 处崩溃。在我改变路径之前它工作正常。

case R.id.action_share:
    Intent intentShare = null;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        Uri u=FileProvider.getUriForFile(getBaseActivity(), AUTHORITY, file);
        intentShare = new Intent(Intent.ACTION_SEND);
        intentShare.setType("application/pdf");
        intentShare.putExtra(Intent.EXTRA_STREAM, u);
        intentShare.putExtra(Intent.EXTRA_SUBJECT, "Sharing File...");
        intentShare.putExtra(Intent.EXTRA_TEXT, "Sharing File...");
        intentShare.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

        startActivity(intentShare);

    }

getBaseActivity() 返回上下文

AUTHORITY 是“[包裹名称].provider”

我已经多次更改 File Provider,尝试了很多组合,包括以下(我将所有内容分开放置,而不是一次全部放置)但似乎没有任何效果..

<external-files-path name="external_files" path="." />
<external-files-path name="external_files" path="/" />
<external-files-path name="my_folder" path="myFolder/" />
<external-path name="my_folder" path="Android/data/[name of the package]/files/myFolder" />
<files-path name="files" path="." />
<external-files-path name="external_files" path="." />

我一直收到这个错误,我找不到合适的解决方案,我已经被困在这里 3 周了......

这是 logcat 行:

2021-12-09 15:09:09.771 23495-23495/[包名] k E/AndroidRuntime: 致命异常: main 进程:[包名],PID:23495 java.lang.IllegalArgumentException:无法找到包含 /storage/emulated/0/Android/data/[package 名称]/files/myFolder/879881480803.pdf 在 androidx.core.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:744) 在 androidx.core.content.FileProvider.getUriForFile(FileProvider.java:418) 在 hr.asseco.ui.activity.fragment.PdfFragment.onOptionsItemSelected(PdfFragment.java:145) 在 androidx.fragment.app.Fragment.performOptionsItemSelected(Fragment.java:2733) 在 androidx.fragment.app.FragmentManagerImpl.dispatchOptionsItemSelected(FragmentManagerImpl.java:2758) 在 androidx.fragment.app.FragmentController.dispatchOptionsItemSelected(FragmentController.java:411) 在 androidx.fragment.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:390) 在 androidx.appcompat.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:228) 在 androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109) 在 androidx.appcompat.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:109) 在 androidx.appcompat.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:65) 在 androidx.appcompat.widget.Toolbar$1.onMenuItemClick(Toolbar.java:207) 在 androidx.appcompat.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:779) 在 androidx.appcompat.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:834) 在 androidx.appcompat.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158) 在 androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:985) 在 androidx.appcompat.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:975) 在 androidx.appcompat.widget.ActionMenuView.invokeItem(ActionMenuView.java:623) 在 androidx.appcompat.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:151) 在 android.view.View.performClick(View.java:7161) 在 android.view.View.performClickInternal(View.java:7138) 在 android.view.View.access$3500(View.java:811) 在 android.view.View$PerformClick.run(View.java:27419) 在 android.os.Handler.handleCallback(Handler.java:883) 在 android.os.Handler.dispatchMessage(Handler.java:100) 在 android.os.Looper.loop(Looper.java:221) 在 android.app.ActivityThread.main(ActivityThread.java:7542) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

【问题讨论】:

标签: java android android-11 android-fileprovider


【解决方案1】:

以下是 Kotlin 代码,但对我有用,我认为它会帮助您解决问题

显现

<application
        ....
        android:requestLegacyExternalStorage="true">

               <provider
                android:name="androidx.core.content.FileProvider"
                android:authorities="com.example.pdf.provider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths" />
                </provider>
</application>

xml/provider_paths

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

代码

var myPdfFilePath: File? = null
myPdfFilePath= File(checkFolder(), "myPdfFile.pdf") 

private fun checkFolder(): File {

    val root = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
        File(getExternalFilesDir(null), folderName)
    } else {
        File(Environment.getExternalStorageDirectory(), folderName)
    }

    var isDirectoryCreated: Boolean = root.exists()
    if (!isDirectoryCreated) {
        isDirectoryCreated = root.mkdir()
    }
    Log.d("Folder", "Created ? $isDirectoryCreated")
    return root
}

private fun sharePdfFile() {
        val contentUri: Uri = FileProvider.getUriForFile(
            applicationContext,
            "com.example.pdf.provider",
            myPdfFilePath!!
        )

        if (myPdfFilePath?.exists()!!) {
            val shareIntent = Intent()
            shareIntent.action = Intent.ACTION_SEND
            shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            shareIntent.setDataAndType(contentUri, contentResolver.getType(contentUri))
            shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(myPdfFilePath))
            startActivity(Intent.createChooser(shareIntent, "Choose an app"))
        }

    }

【讨论】:

  • Uri.FromFile(myPdfFilePath) 没问题,但在 startActivity 上我得到 Method throw 'android.os.FileUriExposedException' 异常。
  • FileProvider 仍然给出相同的错误 btw。
【解决方案2】:
For Android 11 and Above:

**Manifest File**:

 <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="(packagename).provider"(.provider name would be used to pass in parameter so please provide same name here too)
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

**file_xml**:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="logs" path="/" />

</paths>

You can understand the the type of path from [docs][1].

And if your path contains "storage/emulated/0" just pass "/" in path value of xml.

And in code just call:
Uri uri = FileProvider.getUriForFile(getActivity(),
                "provider"(provide the same name defined in manifest of provider)enter code here, // Over here
                new File(filePath));


  [1]: https://developer.android.com/reference/androidx/core/content/FileProvider

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 2021-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-23
    相关资源
    最近更新 更多