Autorizzazione READ_EXTERNAL_STORAGE per Android


84

Sto cercando di accedere ai file multimediali (musica) sul dispositivo dell'utente per riprodurli; un semplice lettore musicale "ciao mondo".

Ho seguito alcuni tutorial e fondamentalmente danno lo stesso codice. Ma non funzionerà; continua a bloccarsi e mi dice:

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

Ora, questo è il mio file manifest:

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

Questo è il mio metodo 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());
    }
}

Ho provato:

Per inserirlo in punti diversi del file manifest:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE”/>

Per aggiungere android: maxSdkVersion in Read external storage premission:

<uses-permission
    android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="21" />

Per inserirlo nel manifest / application / activity-tag:

android:exported=“true

Per mettere grantUriPremission tra uri e cursro nel javamethod:

grantUriPermission(null, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);

Per usarlo, non si bloccherà, ma il cursore diventa nullo:

uri = MediaStore.Audio.Media.getContentUri("EXTERNAL_CONTENT_URI”);

Per utilizzare l'URI del contenuto INTERNO, funziona come previsto, ma fornisce solo "suoni del sistema operativo" come il suono dell'otturatore, il suono della batteria scarica, il clic dei pulsanti e simili:

uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;

Per favore, questo non dovrebbe essere un problema difficile lo so, ma mi sento come un principiante!

Ho letto e provato (o considerato non applicabile al mio problema):

Traccia dello stack:

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

Strano che l'errore venga visualizzato quando non hai fornito questa riga nel manifest <uses-permission android: name = "android.permission.READ_EXTERNAL_STORAGE" /> stai cercando di leggere alcuni file protetti da altre app?
sole soleggiato

A quale livello di API lo stai provando?
Sharp Edge

Hai provato a pulire il progetto. ?
Sunil soleggiato

@sunilsunny Non sto cercando di leggere alcuni file protetti, non che io sappia comunque, solo un semplice lettore multimediale. Sì, ho provato a pulirlo, ho provato a riavviare il computer, ho provato a generare un APK firmato e pubblicarlo su Google Play e accedervi come tester, senza fortuna ...
Slim Sim

@SharpEdge; Il mio AVD è lo standard Nexus 5, api 23. Il mio modulo gradle ha: compileSdkVersion 23 buildToolsVersion "23.0.0" minSdkVersion 14 targetSdkVersion 23 Quindi direi 23.
Slim Sim

Risposte:


90

Hai due soluzioni per il tuo problema. Il più veloce è abbassare targetApi a 22 (file build.gradle). Il secondo è usare il nuovo e meraviglioso modello di richiesta di autorizzazione:

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 trovato qui: https://developer.android.com/training/permissions/requesting.html

Soluzioni 2: se non funziona, prova questo:

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

return;

}

e poi in callback

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

questo è dai commenti. Grazie


1
Sì, naturalmente! Il nuovo modello di autorizzazione introdotto da Google con l'ultimo Android! Grazie, lo proverò il prima possibile e lo contrassegnerò come corretto se funziona! (e stavo cominciando a pensare che questo fosse dimenticato!)
Slim Sim

1
L'autorizzazione richiesta dovrebbe essere READ_EXTERNAL_STORAGE. Come in questa risposta .
maclir

swap! = PackageManager.READ_EXTERNAL_STORAGE per! =
PackageManager.PERMISSION_GRANTED

1
@Renascienza, si hai ragione. Qualcuno ha modificato questa risposta in modo sbagliato.
piotrpo

2
Cos'è MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE?
Solo

17

Devi chiedere l'autorizzazione in fase di esecuzione:

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

E nella richiamata di seguito puoi accedere allo spazio di archiviazione senza problemi.

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

7

Passaggio 1: aggiungi l'autorizzazione su Android manifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Passaggio 2: metodo 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();
    }

Passaggio 3: eseguire l'override del metodo onRequestPermissionsResult per ottenere la richiamata

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

Nota: readDataExternal () è un metodo per ottenere dati da una memoria esterna.

Grazie.


1
Penso che tu abbia perso l'autorizzazione necessaria qui: è READ_EXTERNAL_STORAGE.
Renascienza

4

Ho anche avuto un registro degli errori simile ed ecco cosa ho fatto-

  1. Nel metodo onCreate richiediamo una finestra di dialogo per il controllo delle autorizzazioni

    ActivityCompat.requestPermissions(MainActivity.this,
    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
    
  2. Metodo per verificare il risultato

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

La documentazione ufficiale per la richiesta di autorizzazioni di runtime


1
l'ho usato e ha funzionato perfettamente funziona su tutti i dispositivi Android?
Mahdi Hraybi

1

Il tuo problema è stato risolto? Qual è il tuo SDK di destinazione? Prova ad aggiungere android;maxSDKVersion="21"a<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />


Ha funzionato per me usando Cordova, impostando solo la versione max SDK in AndroidManifest.xml su 22 (invece di 23)
George Kagan

0

http://developer.android.com/reference/android/provider/MediaStore.Audio.AudioColumns.html

Prova a cambiare linea 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);

stringa finale statica pubblica MEDIA_CONTENT_CONTROL

Non utilizzabile da applicazioni di terze parti a causa della privacy del consumo dei media

http://developer.android.com/reference/android/Manifest.permission.html#MEDIA_CONTENT_CONTROL

provare a rimuovere il <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>primo e riprovare?


Grazie, ho provato il tuo suggerimento ma si è bloccato nello stesso punto ... Sto usando un Mac, può essere un problema?
Slim Sim

aggiornato, provare a rimuovere <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>e provare? Potrebbe creare un comportamento strano perché la richiesta di autorizzazione della tua app non è consentita
Derek Fung

grazie, ho provato a rimuovere quell'autorizzazione, ma si blocca nello stesso punto con lo stesso errore ...
Slim Sim

0

Si prega di controllare sotto il codice che usando quello È possibile trovare tutti i file musicali da 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();
    }
}


}

Ho anche aggiunto la seguente riga nel file AndroidManifest.xml come di seguito:

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

Grazie, ho provato qualcosa di simile prima, ma ho provato il tuo codice e si blocca su "cursor = managedQuery (allsongsuri, STAR, selection, null, null);", lo stesso errore di prima. A proposito; managedQuery è deprecato, ma si blocca ancora se lo cambio in "contentResolver.query", che ha gli stessi parametri di input ...
Slim Sim

Ciao, sono in grado di ottenere tutte le canzoni sdcadr usando il codice sopra. con dispositivo Android versione 4.2.2 e anche in grado di con versione 5.0.2. In cui stai provando. Quale errore hai ricevuto per favore descrivi con la versione Android
Rajan Bhavsar

Ho aggiornato la domanda con lo stack-trace, spero che aiuti. Cosa intendi con la versione Android? (Sto usando APK 23)
Slim Sim

Ok Fammi fornire il codice sorgente completo e verificalo di nuovo.
Rajan Bhavsar

se vuoi provare tu stesso, scarica lo zip qui: drive.google.com/open?id=0B2AV8VRk9HUeVzFXSWVRZU9TRUk quando lo esegui, premi il pulsante di inizializzazione sinistro, per generare il crach.
Slim Sim

0

Oltre a tutte le risposte. Puoi anche specificare il minsdk da applicare con questa annotazione

@TargetApi(_apiLevel_)

L'ho usato per accettare questa richiesta anche il mio minsdk è 18. Quello che fa è che il metodo viene eseguito solo quando il dispositivo ha come destinazione "_apilevel_" e superiore. Ecco il mio metodo:

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

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.