尝试从 MediaStore 读取时出现 Android KitKat securityException
Posted
技术标签:
【中文标题】尝试从 MediaStore 读取时出现 Android KitKat securityException【英文标题】:Android KitKat securityException when trying to read from MediaStore 【发布时间】:2013-11-19 04:22:14 【问题描述】:java.lang.SecurityException: Permission Denial: 从 ProcessRecord430b1748 29271:com.xxx/u0a88 (pid=29271, uid=10088) 打开提供程序 com.android.providers.media.MediaDocumentsProvider 需要 android.permission.MANAGE_DOCUMENTS或 android.permission.MANAGE_DOCUMENTS
我添加了MANAGE_DOCUMENTS
和READ_EXTERNAL_STORAGE
权限,但我仍然收到此错误。违规代码:
public static String getImagePath(HailoDriverApplication app, Uri uri)
Cursor cursor = null;
if (uri == null)
return null;
try
cursor = app.getContentResolver().query(uri, new String[]
MediaStore.Images.Media.DATA
, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if (cursor.moveToFirst())
return cursor.getString(column_index);
finally
if (cursor != null)
cursor.close();
return null;
根据要求的清单sn-p:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.x.x.x" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COURSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission
android:name="android.permission.UPDATE_DEVICE_STATS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.intent.action.BATTERY_CHANGED" />
<uses-permission
android:name="android.permission.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
【问题讨论】:
您是否正确添加了权限?也许发布manafest?最近几天遇到了同样的问题。尝试了一些解决方案,但由于某种原因,即使我已将 android.permission.MANAGE_DOCUMENTS 权限添加到清单中,我也会在某些图像的 Uri 内容提供程序上获得权限拒绝。
暂时这里有一个解决方法:
i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, CHOOSE_IMAGE);
这会强制打开旧的图片库而不是新的 Kitkat 文档视图。
现在,您可以通过在 onActivityResult 中调用以下内容来获取 Uri:
Uri selectedImageURI = data.getData();
希望这会有所帮助。
【讨论】:
很好的解决方法,但这只能解决一个小问题,但我使用其他东西来阅读视频,我该如何解决我的问题?【参考方案2】:在用于提示用户添加文件的 Intent 中,使用 Intent.ACTION_OPEN_DOCUMENT(在 KitKat API 19 或更高版本上)而不是 Intent.ACTION_GET_CONTENT 或 Intent.ACTION_PICK。然后,当您想使用 Uri 时,请按照 @feri 的链接 (https://developer.android.com/guide/topics/providers/document-provider.html#permissions) 中所述,获取由 Intent.ACTION_OPEN_DOCUMENT 设置的先前持久权限:
final int takeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(originalUri, takeFlags);
您可以在此处详细了解 Intent.ACTION_GET_CONTENT、Intent.ACTION_PICK 和 Intent.ACTION_OPEN_DOCUMENT 之间的区别:http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT
【讨论】:
【参考方案3】:好的,我找到了一个可以解决问题的工作示例:
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, myClassConstant.SELECT_PICTURE);
这是我学到的……这是 KitKat 中的一个更改,此代码仅适用于 API 19 及更高版本。它不适用于旧版本,因此您还需要有用于 pre-KitKat 的方法。使用 Category_Openable 参数获取文件后,在我的例子中是图像,然后您可以通过将其引用为 URI 来使用它。就我而言,我存储了 URIString(文件路径),并且在打开发生后我可以用它做我想做的事情。
我现在要弄清楚的问题是文件权限持续多长时间。它似乎从昨天开始过期,因为我的代码查找 UriString,然后尝试打开文件。如果我使用上面的代码选择图像,它可以工作 - 它存储名称,并且我能够退出程序,返回并且它仍然有效......但是,我今天早上第一次运行程序(之后在 12 多个小时内没有触摸它),它表现得好像找不到文件(我敢肯定,如果通过调试器观看,我会再次看到非严重错误。
所以现在的问题是:一旦我知道文件(名称)是什么,我们如何保持权限?
【讨论】:
19 岁及以上的工作解决方案【参考方案4】:我假设您要显示的 Uri 引用了来自提供程序的图像,该提供程序实现了 Android 4.4 KitKat 引入的新存储访问框架。 这可以是图库以及 Google-Drive。 访问这些文档的唯一方法似乎是使用系统文件选择器。 如果用户选择要打开的文件,系统会授予应用程序权限,从而启动文件打开对话框。只要设备未重新启动,这些权限就有效。其他图片无法访问,导致安全异常。
如果 Uri 被持久化,那么授予访问 Uri 的权限也必须被持久化。更多详情请看这里: https://developer.android.com/guide/topics/providers/document-provider.html#permissions
【讨论】:
【参考方案5】:MANAGE_DOCUMENTS
权限只能由系统持有:
MANAGE_DOCUMENTS 权限。默认情况下,每个人都可以使用提供程序。添加此权限会将您的提供者限制在系统中。此限制对安全性很重要。
(取自Storage Access Framework)
因此,通过在您的DocumentProvider
中使用此权限,您将对您的提供者的访问权限限制在系统中。这意味着只有System UI picker
才能访问您的文件。因此,为了让应用程序从您的Provider
中选择一个文件,它必须使用ACTION_OPEN_DOCUMENT
启动一个Intent
,实际上这将启动System UI picker
,用户将从那里选择一个文件,然后URI
将返回给您。
【讨论】:
【参考方案6】:解决方案似乎是使用http://developer.android.com/guide/topics/providers/document-provider.html#client 来访问图库中的图像
我不确定为什么其他方法不起作用。但它现在是一个短期的解决方案。
【讨论】:
以上是关于尝试从 MediaStore 读取时出现 Android KitKat securityException的主要内容,如果未能解决你的问题,请参考以下文章
尝试从 Java 中的二进制文件中读取 Int 时出现 BufferUnderflowException
尝试从主机连接到 mysql docker 容器时出现“读取初始通信数据包”错误
尝试从 BigQuery 读取表并使用 Airflow 将其保存为数据框时出现 _pickle.PicklingError
尝试从 WinJS 读取 C# WinRT 组件中的空字符串时出现异常