Android 获取权限拒绝异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22178041/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 05:37:27  来源:igfitidea点击:

Getting Permission Denial Exception

android

提问by mario595

I have an activity in my app that allows the user to select several files from the device one by one, I am using an intent like this:

我的应用程序中有一个活动,允许用户从设备中一个一个地选择多个文件,我使用的是这样的意图:

Intent intent = new Intent();
intent.setType("*/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, getString(R.string.select_attachments_activity_chooser_label)), SELECT_PICTURE);

This is working perfectly fine, I am getting the Uri's of the files selected, they look like this:

这工作得很好,我选择了文件的 Uri,它们看起来像这样:

content://com.android.providers.media.documents/document/image%3A42555

Then, if the file is an image, I am decoding it with:

然后,如果文件是图像,我将使用以下命令对其进行解码:

InputStream streamForDecodeBitmap = MyApp.getContext().getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(streamForDecodeBitmap, null, options);

When the user clicks a button, I pass the list of Uris to another activity via intent and in this activity, in an AsyncTask, I am encoding the file in base64 for send it over the network:

当用户单击按钮时,我通过 Intent 将 Uris 列表传递给另一个活动,在此活动中,在 AsyncTask 中,我将文件编码为 base64,以便通过网络发送:

InputStream is = MyApp.getContext().getContentResolver().openInputStream(uri);
byte[] inputData = getBytes(is);
is.close();
return Base64.encodeToString(inputData, Base64.DEFAULT);

The problem is when I open the inputStream, sometimes it works but most of the times I am getting this exception:

问题是当我打开 inputStream 时,有时它可以工作,但大多数时候我都会遇到此异常:

E/AndroidRuntime(22270): Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{42858fe0 22270:co.uk.manifesto.freeagentapp/u0a246} (pid=22270, uid=10246) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS

These are all the permissions in my manifest:

这些是我的清单中的所有权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>

I am testing in a device with KITKAT (API 19).

我正在使用 KITKAT (API 19) 的设备进行测试。

回答by Pararth

Please check these questions too:
Android KitKat securityException when trying to read from MediaStore
Permission denial: opening provider

也请检查这些问题:
Android KitKat securityException when试图读取 MediaStore
Permission denial: opening provider

For the same problem on KitKat, I used this. It's an option/workaround I had found from one of the Stack Overflow links, you will be able to select files from Downloads/Recent.

对于 KitKat 上的同样问题,我使用了这个。这是我从 Stack Overflow 链接中找到的一个选项/解决方法,您将能够从下载/最近选择文件。

public static final int KITKAT_VALUE = 1002;

Intent intent;

if (Build.VERSION.SDK_INT < 19) {
    intent = new Intent();
    intent.setAction(Intent.ACTION_GET_CONTENT);
    intent.setType("*/*");
    startActivityForResult(intent, KITKAT_VALUE);
} else {
    intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("*/*");
    startActivityForResult(intent, KITKAT_VALUE);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == KITKAT_VALUE ) {
        if (resultCode == Activity.RESULT_OK) {
            // do something here
        }
    }
}

Reference: Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENThttp://developer.android.com/guide/topics/providers/document-provider.html#client

参考: KitKat 上的 Android Gallery 为 Intent.ACTION_GET_CONTENT 返回不同的 Uri http://developer.android.com/guide/topics/providers/document-provider.html#client

回答by marc

When control and data is returned to your activity in

当控制和数据返回到您的活动时

protected void onActivityResult(int reqCode, int resultCode, Intent data)

your activity, at the same time, is given permissions to access the image url in the passed intent. Your activity will be able to read the url in the intent and display the image. But you wont be able to pass any permissions on to other activities or to a new thread of execution. That is why you are getting the SecurityException for android.permission.MANAGE_DOCUMENTS.

同时,您的 Activity 被授予访问传递意图中的图像 url 的权限。您的 Activity 将能够读取 Intent 中的 url 并显示图像。但是您将无法将任何权限传递给其他活动或新的执行线程。这就是为什么您会收到 android.permission.MANAGE_DOCUMENTS 的 SecurityException。

One way to avoid your permission issue, is just to get the data in the activity that has permissions. In your case, from the activity that has permission do your encoding

避免权限问题的一种方法是获取具有权限的活动中的数据。在您的情况下,从有权限的活动中进行编码

InputStream is = getContentResolver().openInputStream(uri);
byte[] inputData = getBytes(is);
is.close();
String encoded = Base64.encodeToString(inputData, Base64.DEFAULT);

Once you have your encoded string you can pass it to any other activities that might need it, or you can pass it to an AsyncTask to be sent elsewhere.

获得编码字符串后,您可以将其传递给可能需要它的任何其他活动,或者您可以将其传递给 AsyncTask 以发送到其他地方。

回答by Alécio Carvalho

Make sure you're using the ContentResolver from the Activity that requested the content, for instance:

确保您正在使用请求内容的 Activity 中的 ContentResolver,例如:

activity.getContentResolver()  

Instead of MyApp.getContext().getContentResolver()

代替 MyApp.getContext().getContentResolver()

It was apparently the case for me and it didn't need to add the android.permission.MANAGE_DOCUMENTSto the manifest.

对我来说显然是这种情况,它不需要将android.permission.MANAGE_DOCUMENTS加到清单中。

And that you call the intent using this:

你使用这个调用意图:

if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
    intent.setAction(Intent.ACTION_GET_CONTENT);
} else {
    intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
}

more info: https://developer.android.com/guide/topics/providers/document-provider.html#client

更多信息:https: //developer.android.com/guide/topics/providers/document-provider.html#client

回答by dhesse

Writing ACTION_OPEN_DOCUMENT is not helping entirely. After a restart your URI Permission is gone even with this action.

编写 ACTION_OPEN_DOCUMENT 并没有完全帮助。重新启动后,即使执行此操作,您的 URI 权限也会消失。

   if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            intent.setAction(Intent.ACTION_GET_CONTENT);
        } else {
            intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
        }

To complete Alécio Carvalho'sanswer look at this documentation onthe same page. There is a good explanation regarding URI Permissions and how to make them persist.

要完成Alécio Carvalho 的回答,请查看同一页面此文档。关于 URI 权限以及如何使它们持久化,有一个很好的解释。

Just add this to your onActivityResult method and your permission persists through a device restart. (Tested with a Google Pixel.)

只需将此添加到您的 onActivityResult 方法,您的权限将在设备重启后持续存在。(使用 Google Pixel 测试。)

override fun onActivityResult(requestCode:Int, resultCode:Int, intent:Intent?) {
if(requestCode == SELECT_PICTURE && intent != null){
    val uri = intent.getData()
    val takeFlags = intent.getFlags() and (Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
    activity.getContentResolver().takePersistableUriPermission(uri, takeFlags)
    PreferenceHelper.setHeaderImageUri(activity, uri.toString())
  }
}

(sorry kotlin lover...java version is inside the link)

(对不起,kotlin 爱好者...java 版本在链接内)

回答by Knossos

Worth noting is that if the user manually removes permissions for a Uri that you have previously saved, then you will get this same Exception.

值得注意的是,如果用户手动删除您之前保存的某个 Uri 的权限,那么您将得到同样的 Exception。

Android settings -> App -> App Name -> Storage -> Clear Access

Android 设置 -> 应用 -> 应用名称 -> 存储 -> 清除访问权限

You need to check that you still have access to the Uri when you use it.

您需要检查在使用它时是否仍然可以访问 Uri。

回答by Carlos Lima

In kotlin solve by placing the operator "?" = (nullable)after Intent

在 kotlin 中,通过将操作符放在"?" = (nullable)Intent 之后解决

as the following code:

如以下代码:

override func onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 
    super.onActivityResult(requestCode, resultCode, data)
}