1

我设置了一个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);
4

1 回答 1

0

啊,我明白了,所以发送应用程序必须为每个 Uri 授予自己的权限,而不是由调用应用程序的 Intent 隐式提供?

我对你的术语感到困惑,所以让我试试这种方法:

有四种基本方法来实现 a ContentProvider

  1. 将其导出并且不受任何权限的保护。这是愚蠢的。不要这样做。

  2. 是否将其导出但受权限(例如android:readPermissionandroid:writePermission属性)保护。这很好用,但仅适用于专门编写用于与您的ContentProvider. 它不适用于没有先验知识的应用程序ContentProvider,例如支持活动的大多数实施者ACTION_SEND

  3. 不要将其导出,而是让您授予Uri特定请求的权限。通常,这是通过添加到used with的活动标志FLAG_GRANT_READ_URI_PERMISSION来完成的,尽管还有其他方法,例如调用自己。当您是需要第三方访问您的提供商的发起者时,这非常有用,例如使用.IntentstartActivity()grantUriPermission()ACTION_SEND Intent

  4. 让它不被导出,并且不授予对Uri. 在这种情况下,ContentProvider只有在您自己的应用程序中可用,并且第三方根本无法访问,即使您提出请求(例如,您的ACTION_SEND请求)。

如何授予最终被选择执行发送的应用程序的权限,还是必须将其授予所有可能的应用程序?

这在我的一条评论中出现了错误,对此我深表歉意。

FLAG_GRANT_READ_URI_PERMISSIONUri如今,您可以在您的 中授予对您的读取访问权限Intent,无论那Uri是其中的“数据”Intent还是额外的。这将被授予最终消费者Intent- 换句话说,选择者不会以某种方式使用权限并且选择的活动没有权限。然而,它曾经FLAG_GRANT_READ_URI_PERMISSION只对“数据”起作用,而不是对Uri附加值中的值起作用,而且我完全忘记了这个缺陷是什么时候修复的。

grantUriPermission()要求您知道最终消费者是谁Intent,这意味着您需要推出自己的“选择器”,这样您就可以找出用户想要处理您提出的ACTION_SEND请求的实际应用程序。

FWIW,这里是一个示例应用程序,它演示了如何使用FLAG_GRANT_READ_URI_PERMISSION, 查看由FileProvider.

于 2014-09-26T18:06:14.363 回答