46

java.lang.SecurityException: Permission Denial: 从 ProcessRecord{430b1748 29271:com.xxx/u0a88} (pid=29271, uid=10088) 打开提供程序 com.android.providers.media.MediaDocumentsProvider 需要 android.permission.MANAGE_DOCUMENTS 或 android。权限.MANAGE_DOCUMENTS

我已经添加了MANAGE_DOCUMENTSREAD_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;
}

根据要求的清单片段:

<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" />
4

6 回答 6

44

前两天遇到同样的问题。尝试了一些解决方案,但由于某种原因,即使我在清单中添加了 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();

希望这可以帮助。

于 2013-11-25T07:31:13.033 回答
13

在用于提示用户添加文件的 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中所述,使用 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

于 2014-08-08T00:43:16.863 回答
12

好的,我找到了一个可以解决问题的工作示例:

            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 多个小时内没有触摸它),它表现得好像找不到文件(我敢肯定,如果通过调试器观看,我会再次看到非关键错误出现。

所以现在的问题是:一旦我知道文件(名称)是什么,我们如何保持权限?

于 2014-08-12T15:46:16.837 回答
3

MANAGE_DOCUMENTS权限只能由系统持有:

MANAGE_DOCUMENTS 权限。默认情况下,每个人都可以使用提供程序。添加此权限会将您的提供者限制在系统中。此限制对于安全性很重要。

(取自存储访问框架

因此,通过在您的系统中使用此权限,您DocumentProvider将对您的提供商的访问权限限制在系统中。这意味着只有这些System UI picker人才能访问您的文件。因此,为了让应用程序从您的文件中选择一个文件,Provider它必须启动一个Intentwith ACTION_OPEN_DOCUMENT,这实际上会启动System UI picker,用户将从那里选择一个文件,然后URI将返回给您。

于 2014-03-18T10:39:52.113 回答
3

我假设您要显示的 Uri 引用了来自提供程序的图像,该提供程序实现了 Android 4.4 KitKat 引入的新存储访问框架。这可以是图库以及 Google-Drive。访问这些文档的唯一方法似乎是使用系统文件选择器。如果用户选择要打开的文件,系统会授予应用程序权限,从而启动文件打开对话框。只要设备未重新启动,这些权限就有效。其他图像无法访问并导致安全异常。

如果 Uri 被持久化,那么授予访问 Uri 的权限也必须被持久化。有关更多详细信息,请参见此处: https ://developer.android.com/guide/topics/providers/document-provider.html#permissions

于 2014-02-08T00:29:41.630 回答
0

该解决方案似乎是使用http://developer.android.com/guide/topics/providers/document-provider.html#client来访问图库中的图像

我不确定为什么其他方法不起作用。但它现在是一个短期的解决方案。

于 2013-11-13T11:18:20.813 回答