【发布时间】:2017-10-09 06:58:14
【问题描述】:
我在本地应用程序中存储了一些与特定上下文(如联系人)相关的图像。我通过ChooserTargetService 使用直接共享(API 23+)来显示这些以供选择,我希望ChooserTarget 实例让Icon 填充这些图像。
所以我想我可以为此使用android.support.v4.content.FileProvider(在ChooserTargetService::onGetChooserTargets 内):
val file = File(File(filesDir, "images"), imageFileName)
val contentUri = FileProvider.getUriForFile(this, "com.company.fileprovider", file)
val icon = Icon.createWithContentUri(contentUri)
并在清单中:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mycompany.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths"/>
</provider>
但问题是我遇到了异常
05-10 16:06:09.100 32444-32444/android:ui W/Icon: Unable to load image from URI: content://com.mycompany.fileprovider/images/icon_dice.png
java.lang.SecurityException: Permission Denial: reading android.support.v4.content.FileProvider uri content://com.mycompany.fileprovider/images/icon_dice.png from pid=32444, uid=1000 requires the provider be exported, or grantUriPermission()
at android.os.Parcel.readException(Parcel.java:1684)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:146)
at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:692)
at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1147)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:984)
at android.content.ContentResolver.openInputStream(ContentResolver.java:704)
at android.graphics.drawable.Icon.loadDrawableInner(Icon.java:335)
at android.graphics.drawable.Icon.loadDrawable(Icon.java:272)
at com.android.internal.app.ChooserActivity$ChooserTargetInfo.<init>(ChooserActivity.java:645)
at com.android.internal.app.ChooserActivity$ChooserListAdapter.addServiceResults(ChooserActivity.java:1003)
at com.android.internal.app.ChooserActivity$1.handleMessage(ChooserActivity.java:126)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
不可能遵循“导出”的建议,因为FileProvider 不幸的是硬编码不允许它(来自FileProvider.java android 支持库源代码):
// Sanity check our security
if (info.exported) {
throw new SecurityException("Provider must not be exported");
}
if (!info.grantUriPermissions) {
throw new SecurityException("Provider must grant uri permissions");
}
所以我试着打电话
grantUriPermission("<something goes here>", contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
但不清楚应该将什么作为包名的第一个参数。从异常详细信息中可以推断出代码在com.android.internal.app.ChooserActivity 中并被系统调用。
编辑:
使用Icon.createWithFilePath 是不可能的,因为你不能从不同的进程访问文件:
W/Icon: Unable to load image from path: /data/user/0/com.mycompany.app/files/images/image.png
java.io.FileNotFoundException: /data/user/0/com.mycompany.app/files/images/image.png (Permission denied)
如果您尝试将文件设置为已弃用的Context.MODE_WORLD_READABLE,您会得到:
java.lang.SecurityException: MODE_WORLD_READABLE no longer supported
在 Andorid 7 上。
【问题讨论】:
-
恕我直言,最好使用不同的
ContentProvider,它对您的文件具有只读支持并且可以导出。您提出的 hack 让我印象深刻,因为它可能适用于某些设备,但不适用于其他设备,基于 Android 更改、设备制造商更改、自定义 ROM 更改等。最终,我计划将此功能添加到myStreamProvider。恕我直言,ChooserTargetService应该为您处理权限问题。 -
@CommonsWare 谢谢。我可能会使用您的
StreamProvider。我最初尝试的是android:exported="true"+android:readPermission="android.permission.BIND_CHOOSER_TARGET_SERVICE"(与我的ChooserTargetService实现的客户端所需的权限相同),如果不是FileProvider中的硬编码ifs,它应该是简单有效且安全的。这个hack真的可以破解吗?应用程序选择器/直接共享处理程序是系统的一部分,不能像例如默认启动器应用程序。 -
我不能排除有人将使用
Icon的系统部分的应用程序ID 更改为ChooserTargetService的可能性。欢迎您尝试com.android.systemui的软件包,因为它有效for notification sounds。或者,如果文件在外部存储上,请使用Uri.fromFile()和StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().build());撤消FileUriExposedException检查。 -
相关,但不完全相同:stackoverflow.com/questions/37860874/…
标签: android android-support-library android-contentprovider android-intent-chooser