如何检查可用于 Intent 的 ContentProvider(或阻止特定的)
Posted
技术标签:
【中文标题】如何检查可用于 Intent 的 ContentProvider(或阻止特定的)【英文标题】:How to inspect ContentProvider available for Intent (or block specific one) 【发布时间】:2018-01-27 20:04:43 【问题描述】:我使用 Intent 机制让用户通过标准方式选择图像
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
intent.addCategory(Intent.CATEGORY_OPENABLE)
ctx.startActivityForResult(intent, RequestCodes.SelectPhoto)
然后我将 Uri 传递给另一个活动以裁剪照片。我需要 Uri 之前进行一些预检查。
在 android 模拟器上,Photos 等默认提供程序(显然)授予我整个应用程序打开 Uri 的权限,而不仅仅是请求活动。然而,在亚洲有一个“奇怪”的提供者 com.miui.gallery.provider.GalleryOpenProvider
没有——在cropper 中发生了一个邪恶的 SecurityException。
所以我尝试使用 ACTION_OPEN_DOCUMENT,根据规范,它会授予我的整个应用程序权限,直到设备重新启动,但不幸的是,在模拟器中不支持云中的 Google 照片。
所以我正在寻找一种方法来确定com.miui.gallery.provider.GalleryOpenProvider
是否会出现在 GET_CONTENT 的列表中,如果是的话,要么阻止它,要么回退到使用 ACTION_OPEN_DOCUMENT。我想避免在将 Uri 提供给裁剪器之前复制流,裁剪活动将其视为只读。
这是启动裁剪 (kotlin) 的完整功能。 CropActivity 是对旧的开源图库应用 com.android.gallery3d 的修改。
private fun startCrop(ctx: Activity, uri: Uri)
val intent = Intent(ctx, CropActivity::class.java)
intent.data = uri
val file = this.createImageFile(ctx, "photofinal")
if (file == null)
this.showStorageUnavailable(ctx)
return
val outputUri = Uri.fromFile(file)
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri)
intent.putExtra(CropExtras.KEY_MIN_CROP_SIDE, Config.minimumImageDimension)
intent.putExtra(CropExtras.KEY_MOST_OBLONG_ASPECT, Config.maxPhotoAspectRatio)
intent.putExtra(CropExtras.KEY_EXIF_ORIENTATION, exifOrientation)
ctx.startActivityForResult(intent, RequestCodes.CropPhoto)
【问题讨论】:
还显示您开始第二个活动的完整意图。收割机。 通过 ACTION_GET_CONTENT 获得的 Uries 始终是只读的。 缺少FLAG_GRANT_READ_URI_PERMISSION来转移获得的权限。 【参考方案1】:然后我将 Uri 传递给另一个活动以裁剪照片
在Intent
的“数据”方面传递Uri
,并添加FLAG_GRANT_READ_URI_PERMISSION
以将读取访问权转移到其他组件。见this sample app:
@Override
public void onActivityResult(int requestCode, int resultCode,
Intent resultData)
if (resultCode==Activity.RESULT_OK)
getActivity()
.startService(new Intent(getActivity(), DurablizerService.class)
.setData(resultData.getData())
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION));
在这里,我碰巧将Uri
传递给服务,但同样的原则也适用于活动。
有关Uri
访问生命周期的更多信息,另请参阅this blog post。
或者,不要使用单独的活动,而是做其他事情(例如,多个片段)。
在 Android 模拟器上,Photos 等默认提供程序(显然)允许我的整个应用程序打开 Uri,而不仅仅是请求活动。
如果Uri
具有file
方案或来自导出的无权限ContentProvider
,则会发生这种情况。
所以我尝试使用 ACTION_OPEN_DOCUMENT,根据规范,它会授予我的整个应用权限,直到设备重新启动
它遵循与您从ACTION_GET_CONTENT
获得的Uri
值相同的一般规则。
所以我正在寻找一种方法来确定 com.miui.gallery.provider.GalleryOpenProvider 是否会出现在 GET_CONTENT 的列表中
严格来说这是不可能的。任何应用程序都可以从该提供商返回Uri
。在实践中,该提供程序只能由其托管应用程序使用。如果您找到了该提供程序的应用程序包名称,并且您在 PackageManager
上使用了 queryIntentActivities()
和您的 ACTION_GET_CONTENT
Intent
,您可以确定来自该应用程序的活动是否在 ACTION_GET_CONTENT
实现列表中。
但是,如果您使用 FLAG_GRANT_READ_URI_PERMISSION
,正如我之前提到的,那应该没有必要。
如果是这样,要么阻止它
除了滚动您自己的“选择器”式 UI 之外,这在严格意义上是不可能的。
【讨论】:
但我认为,根据文档,FLAG_GRANT_READ_URI_PERMISSION
仅用于表示您已获得来自 ContentProvider 的许可。开发者网站上是否提到了这种用法(转发授予的权限)?
@user3175580:FLAG_GRANT_READ_URI_PERMISSION
的主要用途是将Uri
标识的内容的权限授予Intent
的接收者组件。内容不是您“拥有”的事实并不重要。如果您拥有内容的权利,您可以使用FLAG_GRANT_READ_URI_PERMISSION
和/或FLAG_GRANT_WRITE_URI_PERMISSION
转发这些内容。
@user3175580:“开发者网站上是否提到过这种用法...?” ——嗯,这就是the JavaDocs 所拥有的。例如,它也是used by FileProvider
(在这种情况下,用于授予其他应用程序的权限)。但是,文档还有很多不足之处。 :-(以上是关于如何检查可用于 Intent 的 ContentProvider(或阻止特定的)的主要内容,如果未能解决你的问题,请参考以下文章