android android-6.0-marshmallow android-permissions

Android Marshmallow: el cambio de permisos en tiempo de ejecución bloquea la aplicación



android-6.0-marshmallow android-permissions (3)

Observé que la aplicación se vuelve a crear, no entiendo por qué sucede esto. ¡Cualquier sugerencia para rectificar este problema sería bienvenida!

Porque cuando los permisos cambian, el "estado" de la aplicación debe ser invalidado. La forma correcta de hacerlo es destruir el contexto raíz, que es la aplicación misma.

Debe verificar el estado de los permisos otorgados cada vez que consulte los métodos API que requieren estos permisos. No puede confiar en alguna bandera de SharedPreferences que indica que "el usuario otorgó los permisos para la incorporación, ok, diviértase " Haga que su aplicación sea apátrida en este sentido.

Por ejemplo, puede crear alguna BaseActivity / BaseFragment o Utility y mover toda la lógica de verificación allí.

Marshmallow ha rediseñado para obtener permisos. Entonces manejó los permisos antes de llamar al método que necesita permisos y funciona bien, pero se bloquea en el siguiente escenario:

Paso 1: abrió la aplicación y otorgó todos los permisos necesarios

Paso 2: haga clic en el botón Inicio (para que la aplicación esté en segundo plano)

Paso 3: cambió manualmente los permisos en la Configuración

Paso 4: Lanzó la aplicación desde multitareas, ahora se bloquea porque el contexto de la aplicación deja de ser válido

Observé que la aplicación se vuelve a crear, no entiendo por qué sucede esto. ¡Cualquier sugerencia para rectificar este problema sería bienvenida!


Definir un valor booleano al principio

private boolean isPermissionGranted = false;

Y luego verifique si se otorgó el permiso:

if (!isPermissionGranted) { checkPermission(); }

El código real para la verificación de permisos de tiempo de ejecución es el siguiente:

private void checkPermission() { int hasPermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.CAMERA); int hasWritePermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE); if (hasPermission != PackageManager.PERMISSION_GRANTED && hasWritePermission != PackageManager.PERMISSION_GRANTED) { if (!ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.CAMERA) && !ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { showMessage(getString(R.string.allow_access_to_camera_external_storage), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_ASK_PERMISSIONS); } }); return; } ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_ASK_PERMISSIONS); return; } else { isPermissionGranted = true; } } private void showMessage(String message, DialogInterface.OnClickListener listener) { new AlertDialog.Builder(UserProfile.this) .setMessage(message) .setPositiveButton(R.string.ok, listener) .setNegativeButton(R.string.cancel, null) .create() .show(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case REQUEST_CODE_ASK_PERMISSIONS: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { isPermissionGranted = true; } else { isPermissionGranted = false; Toast.makeText(UserProfile.this, R.string.permission_denied, Toast.LENGTH_SHORT) .show(); } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } }

Puede tomar la referencia del código anterior e implementarlo en su aplicación.


Se debe a las características adicionales agregadas de Marshmallow. Debe solicitar al usuario en tiempo de ejecución. Para esto usa esta clase que he hecho. Luego úselo cuando sea necesario

public class AppPermission { public static boolean isMarshmallowPlusDevice() { return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1; } @TargetApi(Build.VERSION_CODES.M) public static boolean isPermissionRequestRequired(Activity activity, @NonNull String[] permissions, int requestCode) { if (isMarshmallowPlusDevice() && permissions.length > 0) { List<String> newPermissionList = new ArrayList<>(); for (String permission : permissions) { if (PackageManager.PERMISSION_GRANTED != activity.checkSelfPermission(permission)) { newPermissionList.add(permission); } } if (newPermissionList.size() > 0) { activity.requestPermissions(newPermissionList.toArray(new String[newPermissionList.size()]), requestCode); return true; } } return false; } }

Luego ponga este código donde requiera permiso del usuario.

if (!AppPermission.isPermissionRequestRequired(SignInActivity.this, new String[]{"android.permission.GET_ACCOUNTS"}, REQUEST_APP_PERMISSION)) { // Your code if permission available }

Después de esto, en su Fragment o Activity ponga este código:

@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case REQUEST_APP_PERMISSION: for (int i = 0; i < permissions.length; i++) { String permission = permissions[i]; int grantResult = grantResults[i]; switch (permission) { case "android.permission.GET_ACCOUNTS": if (PackageManager.PERMISSION_GRANTED == grantResult) { // Your code } break; } } break; } }

El código anterior es para solicitar permiso para GET_ACCOUNTS , puede cambiarlo a lo que sea necesario.