获取权限拒绝例外

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

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); 

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

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

那么,如果该文件是一个图像,我解码它:

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

当用户点击一个按钮时,我通过intent将Uris列表传递给另一个活动,并且在这个活动中,在一个AsyncTask中,我使用base64对文件进行编码以便通过网络发送:

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

问题是,当我打开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 

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

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

我正在用KITKAT(API 19)进行测试。

请检查这些问题:
尝试从MediaStore读取时出现Android KitKat securityException
权限拒绝:开放提供商

对于KitKat上的同样的问题,我用这个。 这是从Stack Overflow链接中找到的选项/解决方法,您可以从Downloads / Recent中选择文件。

 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 } } } 

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

当控制和数据返回到你的活动中

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

您的活动在同一时间被赋予访问被传递的意图中的图像url的权限。 您的活动将能够读取意图中的网址并显示图像。 但是你不能将任何权限传递给其他活动或执行的新线程。 这就是为什么你会得到android.permission.MANAGE_DOCUMENTS的SecurityException。

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

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

一旦你有你的编码字符串,你可以将它传递给任何可能需要它的活动,或者你可以将它传递给一个AsyncTask发送到其他地方。

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

 activity.getContentResolver() 

而不是MyApp.getContext().getContentResolver()

这显然是我的情况,它不需要将android.permission.MANAGE_DOCUMENTS添加到清单。

而你打电话的目的是这样的:

 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); } 

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

编写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); } 

要完成AlécioCarvalho的回答,请在同一页面查看此文档 。 关于URI权限以及如何使其持久存在很好的解释。

只需将此添加到您的onActivityResult方法,您的权限通过设备重新启动持续存在。 (使用Google像素测试)

 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()) } } 

(对不起kotlin的爱人… java版本是链接里面)

值得注意的是,如果用户手动删除了先前保存的Uri的权限,那么您将得到相同的异常。

Android设置 – >应用程序 – >应用程序名称 – >存储 – >清除访问

你需要检查你使用它时是否还能访问Uri。