createChooser() 意图异常“需要导出提供程序,或 grantUriPermission()”

Oll*_*e C 4 android android-contentprovider scoped-storage

该应用程序需要与其他应用程序共享存储在cacheDir根目录中的PDF文件。该问题出现在 Android 12 上,也可能出现在其他版本上。

显现:

    <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/file_paths" />
    </provider>
Run Code Online (Sandbox Code Playgroud)

提供者路径:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <cache-path name="cache" path="." />
</paths>
Run Code Online (Sandbox Code Playgroud)

意图:

        val pdfFile = File(requireContext().cacheDir, pdfFileName)
        val fileUri: Uri = FileProvider.getUriForFile(
            requireContext().applicationContext,
            requireContext().packageName.toString() + ".provider",
            pdfFile
        )
        val intent = Intent()
        intent.action = Intent.ACTION_SEND
        intent.putExtra(Intent.EXTRA_STREAM, fileUri)
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        intent.type = "application/pdf"
        startActivity(Intent.createChooser(intent, "Share Document"))
Run Code Online (Sandbox Code Playgroud)

共享表成功打开,但此时始终显示此异常,并且随后共享到另一个应用程序失败。

Writing exception to parcel
    java.lang.SecurityException: Permission Denial: reading 
androidx.core.content.FileProvider uri
content://uk.co.packagename.provider/cache/8BEDF7212-0DE46-42B0-9FA9-32C434BDD2F3HO.pdf
from pid=15363, uid=1000 requires the provider be exported, or grantUriPermission()
Run Code Online (Sandbox Code Playgroud)

无法导出整个提供程序,并且 URI 权限似乎已被授予。我已经阅读了 Android 文件共享文档和许多 S/O 答案,但我看不出需要纠正什么,你能吗?

Dim*_*ski 7

引发安全异常(“需要导出提供程序,或 grantUriPermission()”)的原因是 Android 系统尝试访问共享资源,以便让用户预览将要共享的内容。

最好的方法是使用intent.setClipData来共享资源intent.putExtra(Intent.EXTRA_STREAM, fileUri)

代码应该如下所示:

intent.action = Intent.ACTION_SEND
intent.setClipData(ClipData.newRawUri("", fileUri))
intent.putExtra(Intent.EXTRA_STREAM, fileUri)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
Run Code Online (Sandbox Code Playgroud)

@skvalex的上述答案是有效的,但这是一种让 Android 系统访问文件以在应用程序共享选择器屏幕中进行预览的黑客方式。

有关这方面的其他参考,请同时查看FileProvider类。