android - usar - shouldshowrequestpermissionrationale
Solicitar y permitir el permiso WRITE_EXTERNAL_STORAGE en tiempo de ejecución no tiene ningún efecto en la sesión actual (2)
Yo tuve el mismo problema. Resulta que esto parece ser un problema más grande. Cambiar el permiso para escribir en el almacenamiento externo cambia el GID para este proceso (en el lado de Linux). Para cambiar la ID, el proceso debe ser reiniciado. La próxima vez que abra la aplicación, se establecerá el nuevo ID de grupo y se otorgará el permiso.
En pocas palabras, me temo que esto no es un error en el emulador sino, de hecho, un problema mayor con Linux y Android.
"Resolví" esto al pedir permiso la primera vez que se ejecuta la aplicación y reiniciarla cuando el permiso se otorga de esta manera:
PackageManager packageManager = getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage(getPackageName());
ComponentName componentName = intent.getComponent();
Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName);
startActivity(mainIntent);
System.exit(0);
Puede intentar crear un servicio que se ejecute en segundo plano (con otro ID de proceso) y otorgarle el permiso. De esa manera solo necesitarías reiniciar el servicio y no la aplicación completa. En el lado negativo, esto podría hacer más trabajo para usted.
Espero que esto ayude.
--- EDITAR ---
El usuario M66B ( https://stackoverflow.com/a/32473449/1565635 ) encontró una lista de las gids relacionadas. Puede encontrar más información aquí: https://android.googlesource.com/platform/frameworks/base/+/master/data/etc/platform.xml
esto se refiere al nuevo modelo de permisos de tiempo de ejecución introducido en Android Marshmallow al solicitar el permiso Manifest.permission.WRITE_EXTERNAL_STORAGE
.
En resumen, lo que estoy experimentando es que si solicito (y el usuario permite) el permiso Manifest.permission.WRITE_EXTERNAL_STORAGE
, la aplicación no podrá leer y escribir desde el directorio de almacenamiento externo hasta que destruya y reinicie la aplicación .
Esto es lo que estoy haciendo / experimentando:
Mi aplicación comienza desde un estado donde:
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
Esto es, no tengo permisos para acceder al almacenamiento externo.
Luego, solicito permiso para Manifest.permission.WRITE_EXTERNAL_STORAGE tal como lo explica Google
private void requestWriteExternalStoragePermission() {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(this)
.setTitle("Inform and request")
.setMessage("You need to enable permissions, bla bla bla")
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MendeleyActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_PERMISSION_WRITE_EXTERNAL_STORAGE);
}
})
.show();
} else {
ActivityCompat.requestPermissions(MendeleyActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_PERMISSION_WRITE_EXTERNAL_STORAGE);
}
}
Una vez que el usuario permite el permiso, se invoca onRequestPermissionsResult
.
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case RC_PERMISSION_WRITE_EXTERNAL_STORAGE: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && PackageManager.PERMISSION_GRANTED
// allowed
} else {
// denied
}
break;
}
}
}
El bloque allowed
se ejecuta, confirmando que el usuario ha otorgado permisos.
Inmediatamente después de esto, si no destruyo y abro la aplicación nuevamente, aún no tengo permiso de acceso al almacenamiento externo. Más específicamente:
hasWriteExternalStoragePermission(); // returns true
Environment.getExternalStorageDirectory().canRead(); // RETURNS FALSE!!
Environment.getExternalStorageDirectory().canWrite(); // RETURNS FALSE!!
Entonces, parece que el tiempo de ejecución de Android cree que tengo permisos, pero el sistema de archivos no ... De hecho, al intentar acceder a Environment.getExternalStorageDirectory()
produce la excepción:
android.system.ErrnoException: open failed: EACCES (Permission denied)
at libcore.io.Posix.open(Native Method)
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
at libcore.io.IoBridge.open(IoBridge.java:438)
at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
Si ahora destruyo la aplicación y la abro nuevamente , el comportamiento se vuelve como debería, pudiendo leer y escribir en la carpeta de almacenamiento externo.
¿Alguien está experimentando esto?
Estoy usando un emulador oficial con:
- Última Android 6.0 (API 23) API 23, Rev 1.
- Emulador que ejecuta Intel x86 Atom System Image, API 23, Rev 1.
Construyo la aplicación con:
android {
compileSdkVersion 23
buildToolsVersion "22.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
}
...
}
Si alguien confirma esto y no soy el único, creo que tendremos que abrir un error, pero espero que esté haciendo algo mal, ya que creo que es poco probable que una función tan básica tenga errores en el SDK.
http://developer.android.com/reference/android/Manifest.permission.html#WRITE_EXTERNAL_STORAGE :
A partir del nivel 19 de la API, este permiso no es necesario para leer / escribir archivos en los directorios específicos de su aplicación que devuelven getExternalFilesDir (String) y getExternalCacheDir ().
La "solicitud de permiso en tiempo de ejecución" comienza en el nivel de API 23, obviamente por encima de 19, por lo que ya no se requiere el permiso, a menos que esté accediendo a los datos fuera de la carpeta señalada por getExternalFilesDir (). Así que creo que esto es un error del emulador.
En objetivos inferiores por debajo del nivel 19, que no admiten la solicitud de permiso en tiempo de ejecución, simplemente solicite el permiso en manifiesto y funcionará.