我的应用程序中有一个活动允许用户逐个从设备中选择多个文件,我使用的是这样的意图:
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);
当用户点击一个按钮时,我通过意图将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)测试设备。
答案 0 :(得分:35)
请检查这些问题:
Android KitKat securityException when trying to read from MediaStore
Permission denial: opening provider
对于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
}
}
}
参考: Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENT http://developer.android.com/guide/topics/providers/document-provider.html#client
答案 1 :(得分:20)
当控件和数据返回到
中的活动时protected void onActivityResult(int reqCode, int resultCode, Intent data)
同时,您的活动有权访问传递的意图中的图片网址。您的活动将能够读取意图中的网址并显示图像。但是,您无法将任何权限传递给其他活动或新的执行线程。这就是为什么你得到android.permission.MANAGE_DOCUMENTS的SecurityException。
避免权限问题的一种方法是获取具有权限的活动中的数据。在您的情况下,从具有权限的活动进行编码
InputStream is = getContentResolver().openInputStream(uri);
byte[] inputData = getBytes(is);
is.close();
String encoded = Base64.encodeToString(inputData, Base64.DEFAULT);
获得编码字符串后,您可以将其传递给可能需要它的任何其他活动,或者您可以将其传递给AsyncTask以便发送到其他地方。
答案 2 :(得分:10)
确保您使用请求内容的活动中的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
答案 3 :(得分:3)
写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écio Carvalho's回答,请查看this documentation on同一页面。关于URI权限以及如何使它们保持不变,有一个很好的解释。
只需将此添加到您的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())
}
}
(对不起kotlin情人...... java版本在链接里面)
答案 4 :(得分:0)
值得注意的是,如果用户手动删除您之前保存的Uri的权限,那么您将获得相同的异常。
Android设置 - &gt;应用 - &gt;应用名称 - &gt;存储 - &gt;清除访问
使用它时,您需要检查是否仍然可以访问Uri。
答案 5 :(得分:0)
在kotlin中通过在Intent
之后放置运算符"?" = (nullable)
来解决
如下代码:
override func onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
}