Java Android 的 READ_EXTERNAL_STORAGE 权限
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32431723/
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
READ_EXTERNAL_STORAGE permission for Android
提问by Slim Sim
I'm trying to access media files (music) on the users device to play them; an easy "hello world"-music player app.
我正在尝试访问用户设备上的媒体文件(音乐)来播放它们;一个简单的“你好世界”-音乐播放器应用程序。
I've followed some tutorials and they basically give the same code. But it won't work; it keeps crashing and telling me:
我遵循了一些教程,它们基本上给出了相同的代码。但这行不通;它不断崩溃并告诉我:
error.....
Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media from pid=27696, uid=10059 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
....
Now, this is my manifest file:
现在,这是我的清单文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="slimsimapps.troff" >
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
This is my Java-method:
这是我的 Java 方法:
public void initialize() {
ContentResolver contentResolver = getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor == null) {
// query failed, handle error.
} else if (!cursor.moveToFirst()) {
// no media on the device
} else {
do {
addSongToXML(cursor);
} while (cursor.moveToNext());
}
}
I have tried:
我试过了:
To put this at different places in the manifest file:
要将其放在清单文件中的不同位置:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE”/>
To add android:maxSdkVersion at Read external storage premission:
在读取外部存储权限中添加 android:maxSdkVersion:
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="21" />
To put this in the manifest / application / activity-tag:
把它放在清单/应用程序/活动标签中:
android:exported=“true”
To put grantUriPremission between uri and cursro in the javamethod:
在 javamethod 中将 grantUriPremission 放在 uri 和 cursro 之间:
grantUriPermission(null, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
To use this, it won't crash, but the cursor becomes null:
要使用它,它不会崩溃,但光标变为空:
uri = MediaStore.Audio.Media.getContentUri("EXTERNAL_CONTENT_URI”);
To use INTERNAL content uri, this works as expected, but it only gives "OS-sounds" such as shutter-sound, low-battery-sound, button-click and such:
要使用内部内容 uri,这会按预期工作,但它只提供“操作系统声音”,例如快门声音、低电量声音、按钮点击等:
uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
Pleas help, this should not be a hard problem i know, but i feel like such a beginner!
请帮忙,我知道这应该不是一个很难的问题,但我觉得像这样的初学者!
I have readand tried (or considered them to be not applicable for my problem):
我已阅读并尝试过(或认为它们不适用于我的问题):
- Android READ_EXTERNAL_STORAGE permission not working
- Require permission only for older android versions: maxSdkVersion does not work?
- Get filename and path from URI from mediastore
- Android KitKat securityException when trying to read from MediaStore
- Android: java.lang.SecurityException: Permission Denial: start Intent
- Android READ_EXTERNAL_STORAGE 权限不起作用
- 仅对较旧的 android 版本需要权限:maxSdkVersion 不起作用?
- 从 mediastore 的 URI 获取文件名和路径
- 尝试从 MediaStore 读取时 Android KitKat securityException
- Android:java.lang.SecurityException:权限拒绝:启动意图
Stack trace:
堆栈跟踪:
09-08 06:59:36.619 2009-2009/slimsimapps.troff D/AndroidRuntime﹕ Shutting down VM
--------- beginning of crash
09-08 06:59:36.619 2009-2009/slimsimapps.troff E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: slimsimapps.troff, PID: 2009
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.view.View$DeclaredOnClickListener.onClick(View.java:4452)
at android.view.View.performClick(View.java:5198)
at android.view.View$PerformClick.run(View.java:21147)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.view.View$DeclaredOnClickListener.onClick(View.java:4447)
????????????at android.view.View.performClick(View.java:5198)
????????????at android.view.View$PerformClick.run(View.java:21147)
????????????at android.os.Handler.handleCallback(Handler.java:739)
????????????at android.os.Handler.dispatchMessage(Handler.java:95)
????????????at android.os.Looper.loop(Looper.java:148)
????????????at android.app.ActivityThread.main(ActivityThread.java:5417)
????????????at java.lang.reflect.Method.invoke(Native Method)
????????????at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
????????????at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/audio/media from pid=2009, uid=10059 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
at android.os.Parcel.readException(Parcel.java:1599)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:183)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:421)
at android.content.ContentResolver.query(ContentResolver.java:491)
at android.content.ContentResolver.query(ContentResolver.java:434)
at slimsimapps.troff.MainActivity.initialize(MainActivity.java:106)
at slimsimapps.troff.MainActivity.InitializeExternal(MainActivity.java:80)
????????????at java.lang.reflect.Method.invoke(Native Method)
????????????at android.view.View$DeclaredOnClickListener.onClick(View.java:4447)
????????????at android.view.View.performClick(View.java:5198)
????????????at android.view.View$PerformClick.run(View.java:21147)
????????????at android.os.Handler.handleCallback(Handler.java:739)
????????????at android.os.Handler.dispatchMessage(Handler.java:95)
????????????at android.os.Looper.loop(Looper.java:148)
????????????at android.app.ActivityThread.main(ActivityThread.java:5417)
????????????at java.lang.reflect.Method.invoke(Native Method)
????????????at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
????????????at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
--------- beginning of system
采纳答案by piotrpo
You have two solutions for your problem. The quick one is to lower targetApi to 22 (build.gradle file). Second is to use new and wonderful ask-for-permission model:
您的问题有两种解决方案。最快的方法是将 targetApi 降低到 22(build.gradle 文件)。二是使用新奇的请求权限模型:
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (shouldShowRequestPermissionRationale(
Manifest.permission.READ_EXTERNAL_STORAGE)) {
// Explain to the user why we need to read the contacts
}
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
// MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
// app-defined int constant that should be quite unique
return;
}
Sniplet found here: https://developer.android.com/training/permissions/requesting.html
在这里找到的 Sniplet:https: //developer.android.com/training/permissions/requesting.html
回答by Derek Fung
http://developer.android.com/reference/android/provider/MediaStore.Audio.AudioColumns.html
http://developer.android.com/reference/android/provider/MediaStore.Audio.AudioColumns.html
Try changing the line contentResolver.query
尝试更改线路 contentResolver.query
//change it to the columns you need
String[] columns = new String[]{MediaStore.Audio.AudioColumns.DATA};
Cursor cursor = contentResolver.query(uri, columns, null, null, null);
public static final String MEDIA_CONTENT_CONTROL
Not for use by third-party applications due to privacy of media consumption
public static final String MEDIA_CONTENT_CONTROL
由于媒体消费的隐私,不供第三方应用程序使用
http://developer.android.com/reference/android/Manifest.permission.html#MEDIA_CONTENT_CONTROL
http://developer.android.com/reference/android/Manifest.permission.html#MEDIA_CONTENT_CONTROL
try to remove the <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
first and try again?
尝试删除第<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
一个并重试?
回答by Rajan Bhavsar
Please Check below code that using that You can find all Music Files from sdcard :
请检查以下代码,使用该代码您可以从 sdcard 中找到所有音乐文件:
public class MainActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animations);
getAllSongsFromSDCARD();
}
public void getAllSongsFromSDCARD() {
String[] STAR = { "*" };
Cursor cursor;
Uri allsongsuri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
cursor = managedQuery(allsongsuri, STAR, selection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
String song_name = cursor
.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
int song_id = cursor.getInt(cursor
.getColumnIndex(MediaStore.Audio.Media._ID));
String fullpath = cursor.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.DATA));
String album_name = cursor.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.ALBUM));
int album_id = cursor.getInt(cursor
.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
String artist_name = cursor.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.ARTIST));
int artist_id = cursor.getInt(cursor
.getColumnIndex(MediaStore.Audio.Media.ARTIST_ID));
System.out.println("sonng name"+fullpath);
} while (cursor.moveToNext());
}
cursor.close();
}
}
}
I have also added following line in the AndroidManifest.xml file as below:
我还在 AndroidManifest.xml 文件中添加了以下行,如下所示:
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
回答by Jerry Ejonavi
Has your problem been resolved? What is your target SDK? Try adding android;maxSDKVersion="21"
to <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
您的问题是否已解决?你的目标 SDK 是什么?尝试添加android;maxSDKVersion="21"
到<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
回答by maclir
You have to ask for the permission at run time:
您必须在运行时请求权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
REQUEST_PERMISSION);
dialog.dismiss();
return;
}
And in the callback below you can access the storage without a problem.
在下面的回调中,您可以毫无问题地访问存储。
@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted.
} else {
// User refused to grant permission.
}
}
}
回答by sonnv1368
Step1: add permission on android manifest.xml
Step1:在android manifest.xml上添加权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Step2: onCreate() method
Step2:onCreate() 方法
int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_READ_MEDIA);
} else {
readDataExternal();
}
Step3: override onRequestPermissionsResult method to get callback
步骤 3:覆盖 onRequestPermissionsResult 方法以获取回调
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_MEDIA:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
readDataExternal();
}
break;
default:
break;
}
}
Note: readDataExternal() is method to get data from external storage.
注意: readDataExternal() 是从外部存储中获取数据的方法。
Thanks.
谢谢。
回答by sonnv1368
I also had a similar error log and here's what I did-
我也有类似的错误日志,这就是我所做的-
In onCreate method we request a Dialog Box for checking permissions
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
Method to check for the result
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case 1: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission granted and now can proceed mymethod(); //a sample method called } else { // permission denied, boo! Disable the // functionality that depends on this permission. Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show(); } return; } // add other cases for more permissions } }
在 onCreate 方法中,我们请求一个对话框来检查权限
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
检查结果的方法
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case 1: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission granted and now can proceed mymethod(); //a sample method called } else { // permission denied, boo! Disable the // functionality that depends on this permission. Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show(); } return; } // add other cases for more permissions } }
The official documentation to Requesting Runtime Permissions
请求运行时权限的官方文档
回答by Gian Gomen
In addition of all answers. You can also specify the minsdk to apply with this annotation
除了所有答案。您还可以指定要应用此注释的 minsdk
@TargetApi(_apiLevel_)
I used this in order to accept this request even my minsdk is 18. What it does is that the method only runs when device targets "_apilevel_" and upper. Here's my method:
我使用它是为了接受这个请求,即使我的 minsdk 是 18。它的作用是该方法仅在设备以“_apilevel_”和上层为目标时运行。这是我的方法:
@TargetApi(23)
void solicitarPermisos(){
if (ContextCompat.checkSelfPermission(this,permiso)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (shouldShowRequestPermissionRationale(
Manifest.permission.READ_EXTERNAL_STORAGE)) {
// Explain to the user why we need to read the contacts
}
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
1);
// MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE is an
// app-defined int constant that should be quite unique
return;
}
}