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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:31:47  来源:igfitidea点击:

READ_EXTERNAL_STORAGE permission for Android

javaandroidaudio-playerandroid-external-storageandroid-music-player

提问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):

我已阅读并尝试过(或认为它们不适用于我的问题):

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-

我也有类似的错误日志,这就是我所做的-

  1. In onCreate method we request a Dialog Box for checking permissions

    ActivityCompat.requestPermissions(MainActivity.this,
    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
    
  2. 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
        }
    }
    
  1. 在 onCreate 方法中,我们请求一个对话框来检查权限

    ActivityCompat.requestPermissions(MainActivity.this,
    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
    
  2. 检查结果的方法

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

}