Error de permiso de almacenamiento en Marshmallow


159

En Lollipop, la funcionalidad de descarga funciona bien en mi aplicación, pero cuando actualicé a Marshmallow, mi aplicación se bloquea y da este error cuando intento descargar de Internet en la tarjeta SD:

Neither user  nor current process has android.permission.WRITE_EXTERNAL_STORAGE

Se queja de esta línea de código:

DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);

Tengo los permisos en el manifiesto fuera de la aplicación:

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

Limpié y reconstruí el proyecto, pero aún se bloquea.


Pruebe esto, puede ser de ayuda: - stackoverflow.com/a/41221852/5488468
Bipin Bharti

He preparado una biblioteca que ayudará a manejar fácilmente los permisos de tiempo de ejecución. github.com/nabinbhandari/Android-Permissions
Nabin Bhandari

Respuestas:


357

Debe verificar si el usuario ha otorgado permiso de almacenamiento externo utilizando:

if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    Log.v(TAG,"Permission is granted");
    //File write logic here
    return true;
}

De lo contrario, debe solicitar al usuario que otorgue un permiso a su aplicación:

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);

Por supuesto, estos son solo para dispositivos de malvavisco, por lo que debe verificar si su aplicación se está ejecutando en Marshmallow:

 if (Build.VERSION.SDK_INT >= 23) {
      //do your check here
 }

Asegúrese también de que su actividad implemente OnRequestPermissionResult

El permiso completo se ve así:

public  boolean isStoragePermissionGranted() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG,"Permission is granted");
            return true;
        } else {

            Log.v(TAG,"Permission is revoked");
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        Log.v(TAG,"Permission is granted");
        return true;
    }
}

Devolución de llamada de resultado de permiso:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
        Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
        //resume tasks needing this permission
    }
}

2
@Houssem encantado de ayudar.
MetaSnarf

14
Esto no funciona para API> = 23, solicitar permiso para Manifest.permission.WRITE_EXTERNAL_STORAGEsiempre devuelve '-1', es decir, Permiso denegado. Consulte la nueva documentación, dice que para API 19 en adelante, no necesita el WRITE_EXTERNAL_STORAGEpermiso. Como se mencionó en algunos de los comentarios anteriores, debe hacer todo esto con elManifest.permission.READ_EXTERNAL_STORAGE
AmeyaB

3
@VSB: Está en un lugar extraño, pero aquí tienes: developer.android.com/guide/topics/manifest/…
AmeyaB

3
@AmeyB Como se dice en la documentación, para API> = 19, no se requiere permiso para escribir en almacenamiento externo para declararse SI la aplicación va a usar su propio directorio específico en almacenamiento externo que es devuelto por getExternalFilesDir(). En otros casos, aún se android.permission.WRITE_EXTERNAL_STORAGEdebe declarar el permiso en la forma más humana.
VSB

1
Si, arreglado. El problema estaba relacionado con la biblioteca de aplicaciones de hockey. Esta biblioteca ha anulado mi permiso de escritura. @MetaSnarf
Selin

38

El sistema de permisos de Android es una de las mayores preocupaciones de seguridad desde que se solicitan esos permisos en el momento de la instalación. Una vez instalada, la aplicación podrá acceder a todas las cosas otorgadas sin que ningún usuario reconozca qué hace exactamente la aplicación con el permiso.

Android 6.0 Marshmallow presenta uno de los cambios más grandes en el modelo de permisos con la adición de permisos de tiempo de ejecución, un nuevo modelo de permisos que reemplaza el modelo de permisos de tiempo de instalación existente cuando apunta a la API 23 y la aplicación se ejecuta en un dispositivo Android 6.0+

La cortesía se dirige a Solicitar permisos en tiempo de ejecución .

Ejemplo

Declara esto como Global

private static final int PERMISSION_REQUEST_CODE = 1;

Agrega esto en tu onCreate()sección

Después de setContentView (R.layout.your_xml);

 if (Build.VERSION.SDK_INT >= 23)
    {
        if (checkPermission())
        {
            // Code for above or equal 23 API Oriented Device 
            // Your Permission granted already .Do next code
        } else {
            requestPermission(); // Code for permission
        }
    }
  else
    {

       // Code for Below 23 API Oriented Device 
       // Do next code
    }

Ahora agregando checkPermission () y requestPermission ()

 private boolean checkPermission() {
    int result = ContextCompat.checkSelfPermission(Your_Activity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (result == PackageManager.PERMISSION_GRANTED) {
        return true;
    } else {
        return false;
    }
}

private void requestPermission() {

    if (ActivityCompat.shouldShowRequestPermissionRationale(Your_Activity.this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
        Toast.makeText(Your_Activity.this, "Write External Storage permission allows us to do store images. Please allow this permission in App Settings.", Toast.LENGTH_LONG).show();
    } else {
        ActivityCompat.requestPermissions(Your_Activity.this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.e("value", "Permission Granted, Now you can use local drive .");
            } else {
                Log.e("value", "Permission Denied, You cannot use local drive .");
            }
            break;
    }
}

FYI

onRequestPermissionsResult

Esta interfaz es el contrato para recibir los resultados de las solicitudes de permisos.


29

Verifique el permiso múltiple en el nivel 23 de API Paso 1:

 String[] permissions = new String[]{
        Manifest.permission.INTERNET,
        Manifest.permission.READ_PHONE_STATE,
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.VIBRATE,
        Manifest.permission.RECORD_AUDIO,
};

Paso 2:

 private boolean checkPermissions() {
    int result;
    List<String> listPermissionsNeeded = new ArrayList<>();
    for (String p : permissions) {
        result = ContextCompat.checkSelfPermission(this, p);
        if (result != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(p);
        }
    }
    if (!listPermissionsNeeded.isEmpty()) {
        ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), 100);
        return false;
    }
    return true;
}

Paso 3:

 @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    if (requestCode == 100) {
        if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // do something
        }
        return;
    }
}

Paso 4: en onCreate of Activity checkPermissions ();


2
Gracias. Esto parece una respuesta prometedora para múltiples permisos. Pero falta un poco en los ejemplos. ¿Cómo se maneja never ask againy faltan algunos permisos? ¿El usuario recibe algún comentario? Hubiera sido agradable ver un ejemplo real de este o más comentarios en sus fragmentos de código.
not2qubit

Para tratar, no vuelva a preguntar rodeando los permisos de agregar si se bloquea con if (shouldshowpermissionrationale ()) {} ... es cierto si se necesita el permiso y no se descarta para siempre
me_

Esta debería ser la respuesta correcta y optimizada.
VikaS GuttE

21

A menos que exista un requisito definitivo de escritura en almacenamiento externo, siempre puede elegir guardar archivos en el directorio de la aplicación. En mi caso tuve que guardar archivos y después de perder 2 o 3 días descubrí si cambio la ruta de almacenamiento de

Environment.getExternalStorageDirectory()

a

getApplicationContext().getFilesDir().getPath() //which returns the internal app files directory path

Funciona a la perfección en todos los dispositivos. Esto se debe a que para escribir en almacenamiento externo necesita permisos adicionales, pero escribir en el directorio interno de la aplicación es simple.


¿Dónde escribes este código? No recuerdo haber usado Environment.getExternalStorageDiretory () en mi código
royjavelosa

5

debe usar el permiso de tiempo de ejecución en malvavisco https://developer.android.com/training/permissions/requesting.html

puedes consultar la información de la aplicación -> permiso

¿su aplicación obtiene permiso para escribir almacenamiento externo o no?


2
en realidad esta información de la aplicación de respuesta -> el permiso resolvió el bloqueo :), pero acepté la otra respuesta para los detalles de qué hacer. Desearía poder aceptar las dos Gracias ua mucho
Badr

Gracias, eso solucionó el problema de descarga del navegador en el emulador de Android
sdaffa23fdsf

4

Parece que el usuario ha rechazado el permiso y la aplicación intenta escribir en un disco externo, causando un error.

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

Consulte https://developer.android.com/training/permissions/requesting.html

Este video le dará una mejor idea sobre UX, manejo de permisos de tiempo de ejecución https://www.youtube.com/watch?v=iZqDdvhTZj0


1

Desde la versión de malvavisco, los desarrolladores deben solicitar permisos de tiempo de ejecución al usuario. Déjame darte todo el proceso para solicitar permisos de tiempo de ejecución.

Estoy usando referencia desde aquí: permisos de tiempo de ejecución de malvavisco android .

Primero cree un método que verifique si se otorgan o no todos los permisos

private  boolean checkAndRequestPermissions() {
        int camerapermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        int writepermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        int permissionLocation = ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION);
        int permissionRecordAudio = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO);


        List<String> listPermissionsNeeded = new ArrayList<>();

        if (camerapermission != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.CAMERA);
        }
        if (writepermission != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
        }
        if (permissionLocation != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
        if (permissionRecordAudio != PackageManager.PERMISSION_GRANTED) {
            listPermissionsNeeded.add(Manifest.permission.RECORD_AUDIO);
        }
        if (!listPermissionsNeeded.isEmpty()) {
            ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
            return false;
        }
        return true;
    } 

Ahora aquí está el código que se ejecuta después del método anterior. Anularemos el onRequestPermissionsResult()método:

 @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        Log.d(TAG, "Permission callback called-------");
        switch (requestCode) {
            case REQUEST_ID_MULTIPLE_PERMISSIONS: {

                Map<String, Integer> perms = new HashMap<>();
                // Initialize the map with both permissions
                perms.put(Manifest.permission.CAMERA, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.RECORD_AUDIO, PackageManager.PERMISSION_GRANTED);
                // Fill with actual results from user
                if (grantResults.length > 0) {
                    for (int i = 0; i < permissions.length; i++)
                        perms.put(permissions[i], grantResults[i]);
                    // Check for both permissions
                    if (perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
                            && perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED 
&& perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED 
&& perms.get(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
                        Log.d(TAG, "sms & location services permission granted");
                        // process the normal flow
                        Intent i = new Intent(MainActivity.this, WelcomeActivity.class);
                        startActivity(i);
                        finish();
                        //else any one or both the permissions are not granted
                    } else {
                        Log.d(TAG, "Some permissions are not granted ask again ");
                        //permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
//                        // shouldShowRequestPermissionRationale will return true
                        //show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
                        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) 
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) 
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)
 || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
                            showDialogOK("Service Permissions are required for this app",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            switch (which) {
                                                case DialogInterface.BUTTON_POSITIVE:
                                                    checkAndRequestPermissions();
                                                    break;
                                                case DialogInterface.BUTTON_NEGATIVE:
                                                    // proceed with logic by disabling the related features or quit the app.
                                                    finish();
                                                    break;
                                            }
                                        }
                                    });
                        }
                        //permission is denied (and never ask again is  checked)
                        //shouldShowRequestPermissionRationale will return false
                        else {
                            explain("You need to give some mandatory permissions to continue. Do you want to go to app settings?");
                            //                            //proceed with logic by disabling the related features or quit the app.
                        }
                    }
                }
            }
        }

    }

Si el usuario hace clic en la opción Denegar , el showDialogOK()método se usará para mostrar el diálogo

Si el usuario hace clic en Denegar y también hace clic en una casilla de verificación que dice "nunca volver a preguntar" , explain()se utilizará el método para mostrar el diálogo.

métodos para mostrar diálogos:

 private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", okListener)
                .create()
                .show();
    }
    private void explain(String msg){
        final android.support.v7.app.AlertDialog.Builder dialog = new android.support.v7.app.AlertDialog.Builder(this);
        dialog.setMessage(msg)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        //  permissionsclass.requestPermission(type,code);
                        startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:com.exampledemo.parsaniahardik.marshmallowpermission")));
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        finish();
                    }
                });
        dialog.show();
    }

El fragmento de código anterior solicita cuatro permisos a la vez. También puede solicitar cualquier número de permisos en cualquier actividad según sus requisitos.


0

Después de mucha búsqueda, este código me funciona:

Verifique que el permiso ya tenga: Verifique el permiso WRITE_EXTERNAL_STORAGE ¿Permitido o no?

if(isReadStorageAllowed()){
            //If permission is already having then showing the toast
            //Toast.makeText(SplashActivity.this,"You already have the permission",Toast.LENGTH_LONG).show();
            //Existing the method with return
            return;
        }else{
            requestStoragePermission();
        }



private boolean isReadStorageAllowed() {
    //Getting the permission status
    int result = ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);

    //If permission is granted returning true
    if (result == PackageManager.PERMISSION_GRANTED)
        return true;

    //If permission is not granted returning false
    return false;
}

//Requesting permission
private void requestStoragePermission(){

    if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)){
        //If the user has denied the permission previously your code will come to this block
        //Here you can explain why you need this permission
        //Explain here why you need this permission
    }

    //And finally ask for the permission
    ActivityCompat.requestPermissions(this,new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_WRITE_STORAGE);
}

Implemente el método Override onRequestPermissionsResult para verificar si el usuario permite o deniega

 @Override
 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    //Checking the request code of our request
    if(requestCode == REQUEST_WRITE_STORAGE){

        //If permission is granted
        if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){

            //Displaying a toast
            Toast.makeText(this,"Permission granted now you can read the storage",Toast.LENGTH_LONG).show();

        }else{
            //Displaying another toast if permission is not granted
            Toast.makeText(this,"Oops you just denied the permission",Toast.LENGTH_LONG).show();
        }
    }

0

me ha funcionado

 boolean hasPermission = (ContextCompat.checkSelfPermission(AddContactActivity.this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
    if (!hasPermission) {
        ActivityCompat.requestPermissions(AddContactActivity.this,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_WRITE_STORAGE);
    }

   @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode)
    {
        case REQUEST_WRITE_STORAGE: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                //reload my activity with permission granted or use the features what required the permission
            } else
            {
                Toast.makeText(AddContactActivity.this, "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
            }
        }
    }

}

0
   Try this



int permission = ContextCompat.checkSelfPermission(MainActivity.this,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE);

     if (permission != PackageManager.PERMISSION_GRANTED) {
                Log.i("grant", "Permission to record denied");

                if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setMessage(getString(R.string.permsg))
                            .setTitle(getString(R.string.permtitle));

                    builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog, int id) {
                            Log.i("grant", "Clicked");
                            makeRequest();
                        }
                    });

                    AlertDialog dialog = builder.create();
                    dialog.show();

                } else {

                    //makeRequest1();
                    makeRequest();
                }
            }


     protected void makeRequest() {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    500);
        }



     @Override
        public void onRequestPermissionsResult(int requestCode,
                                               String permissions[], int[] grantResults) {
            switch (requestCode) {
                case 500: {

                    if (grantResults.length == 0
                            || grantResults[0] !=
                            PackageManager.PERMISSION_GRANTED) {

                        Log.i("1", "Permission has been denied by user");

                    } else {

                        Log.i("1", "Permission has been granted by user");

                    }
                    return;
                }

            }
        }

0

Antes de comenzar la descarga, verifique los permisos de tiempo de ejecución y, si no tiene permiso, solicite permisos como este método

requestStoragePermission ()

private void requestStoragePermission(){
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, 
                android.Manifest.permission.READ_EXTERNAL_STORAGE))
        {

        }

        ActivityCompat.requestPermissions(this, 
            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
            STORAGE_PERMISSION_CODE);
}

@Override
public void onRequestPermissionsResult(int requestCode, 
                @NonNull String[] permissions, 
                @NonNull int[] grantResults) {

    if(requestCode == STORAGE_PERMISSION_CODE){
        if(grantResults.length >0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
        }
        else{
            Toast.makeText(this,
                           "Oops you just denied the permission", 
                           Toast.LENGTH_LONG).show();
        }
    }
}

0

De una manera simple, el permiso se puede otorgar usando el archivo manifest.xml, pero estuvo bien hasta el nivel 23 de la API sdk versión 6, después de aquí, si queremos obtener el permiso, debemos solicitar el uso para permitir el permiso que son necesarios

Simplemente agregue este código en mainActivity.java

Override
            public void onClick(View view) {
                // Request the permission
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.CAMERA},
                        PERMISSION_REQUEST_CAMERA);

Reemplace la CÁMARA o agregue con WRITE_EXTERNAL_STORAGE si lo desea, y con el código único.

                            new String[]{Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    101);

Este es el código simple para obtener permiso.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.