Marsmallow: Cambio de permisos en la aplicación de lockings en tiempo de ejecución

Marsmallow ha rediseñado la obtención de permisos. Así que maneja los permisos antes de llamar al método que necesita permisos y funciona bien, pero se bloquea en el siguiente escenario:

Paso 1: aplicación abierta y dio todos los permisos necesarios

Paso 2: botón de inicio hecho clic (por lo que la aplicación está en segundo plano)

Paso 3: cambio manual de los permisos en la Configuración

Paso 4: Lanzó la aplicación desde multitareas, ahora se bloquea debido a que el contexto de la aplicación se vuelve inválido

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

Es debido a las características adicionales agregadas de Marshmallow. Debe solicitarlo al usuario en tiempo de ejecución. Para esto usa esta clase que he hecho. Luego úselo cuando se requiera

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

A continuación, coloque 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.

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

Porque cuando los permisos cambian, la aplicación “estado” debe invalidarse. La forma correcta de hacerlo es destruir el contexto raíz, que es la aplicación en sí misma.

Debe verificar el estado de los permisos otorgados cada vez que consulta los métodos API que requieren estos permisos. No puede confiar en un indicador de SharedPreferences que indique que “el usuario otorgó los permisos de incorporación, vale, diviértase “. Haga que su aplicación sea sin estado a este respecto.

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

Defina un valor booleano al principio

  private boolean isPermissionGranted = false; 

Y luego verifique si se concede permiso:

 if (!isPermissionGranted) { checkPermission(); } 

El código actual para la verificación del permiso 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 referencia del código anterior e implementarlo en su aplicación.