我已经设置了一个ContentProvider
,仅供我的应用程序内部使用,用流来响应URI,通过它我构建并提供了一个zip文件。
Uri
作为额外的(Intent.EXTRA_STREAM
)传递给Intent
(Intent.ACTION_SEND
)以便发送。然而,当这样做时,它会间歇性地失败,例外情况如下:
E/DatabaseUtils(26058): java.lang.SecurityException: Permission Denial: reading MyContentProvider uri content://spinner.myapp.db/file/stream/zip/1 from pid=26141, uid=10038 requires the provider be exported, or grantUriPermission()
我尝试过通过intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
授予权限,但没有成功。我也不明白为什么我需要授予权限,因为只有我自己的应用程序在访问ContentProvider
。
更新:
我现在也尝试过使用setClipData()
,但没有成功。Gmail显然忽略了Uri,Dropbox崩溃了。
String[] mimeTypes = { "application/x-compressed" };
ClipData clip = new ClipData("zip data", mimeTypes, new ClipData.Item(uri));
intent.setClipData(clip);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
啊,我明白了,所以发送应用程序必须为每个Uri授予自己的权限,而不是由调用应用程序的Intent隐式提供权限?
我对你的术语感到困惑,所以让我试试这种方法:
实现ContentProvider
:有四种基本方法
-
将其导出,并且不受任何权限的保护。这太愚蠢了。不要这样做。
-
将其导出,但要使用权限(例如
android:readPermission
和android:writePermission
属性)进行保护。这很有效,但仅适用于专门为与ContentProvider
对话而编写的应用程序。它不适用于对ContentProvider
没有先验知识的应用程序,就像大多数支持ACTION_SEND
的活动的实现者一样。 -
不导出它,但允许您为特定请求授予
Uri
的权限。通常,这是通过将FLAG_GRANT_READ_URI_PERMISSION
之类的活动标志添加到与startActivity()
一起使用的Intent
中来完成的,尽管还有其他方法,例如自己调用grantUriPermission()
。当您是需要第三方访问提供商的发起人时,例如使用ACTION_SEND
Intent
启动活动时,这非常有效。 -
不导出它,也不授予对
Uri
的权限。在这种情况下,ContentProvider
仅在您自己的应用程序中可用,第三方根本无法访问,即使您提出要求(例如ACTION_SEND
请求)。
我如何为最终被选择执行发送的应用程序授予权限,还是必须将其授予所有可能的应用程序?
这导致了我的一条评论中的一个错误,对此我深表歉意。
如今,FLAG_GRANT_READ_URI_PERMISSION
在Intent
中授予对Uri
的读取访问权限,无论该Uri
是该Intent
的"数据"还是在额外的数据中。这将被授予Intent
的最终使用者——换句话说,选择器不会以某种方式使用权限,所选活动也没有权限。然而,过去FLAG_GRANT_READ_URI_PERMISSION
只处理"数据",而不处理附加值中的Uri
值,我突然忘记了这个缺陷是什么时候修复的。
grantUriPermission()
要求您知道Intent
的最终消费者是谁,这意味着您需要滚动自己的"选择器",这样您就可以找到用户想要处理您提出的ACTION_SEND
请求的实际应用程序。
FWIW,这里是一个示例应用程序,演示了使用FLAG_GRANT_READ_URI_PERMISSION
来查看由FileProvider
提供的PDF。