web-dev-qa-db-fra.com

Autorisations Android M: confondu avec l'utilisation de la fonction shouldShowRequestPermissionRationale ()

Je parcourais la documentation officielle sur le nouveau modèle d'autorisations dans Android M. Il parle de la fonction shouldShowRequestPermissionRationale() qui renvoie true si l'application a déjà demandé cette autorisation et que l'utilisateur l'a refusée. Si l'utilisateur avait précédemment refusé la demande d'autorisation et choisi l'option Ne plus demander, cette méthode renvoie false

Mais comment différencier les deux cas suivants?

Cas 1: L'application n'a pas d'autorisation et l'utilisateur n'a pas encore demandé l'autorisation à l'utilisateur. Dans ce cas, shouldShowRequestPermissionRationale () renverra false car c'est la première fois que nous demandons à l'utilisateur.

Cas 2: L'utilisateur a refusé l'autorisation et sélectionné "Ne plus demander", dans ce cas également, shouldShowRequestPermissionRationale () renverra false. 

Je voudrais envoyer l'utilisateur à la page des paramètres de l'application dans le cas 2. Comment puis-je différencier ces deux cas?

120
akshayt23

Après M Aperçu 1, si la boîte de dialogue est affichée pour la première fois , il n’y a plus de case à cocher Jamais demander à nouveau.

Si l'utilisateur refuse la demande d'autorisation, il y aura une case à cocher Ne plus demander dans la boîte de dialogue d'autorisation la deuxième fois l'autorisation est demandée.

Donc, la logique devrait être comme ça:

  1. Demander la permission:

    if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
    } else {
        //Do the stuff that requires permission...
    }
    
  2. Vérifiez si la permission a été refusée ou accordée dans onRequestPermissionsResult.

    Si l'autorisation a déjà été refusée, cette fois, une case à cocher Ne plus demander apparaît dans la boîte de dialogue des autorisations. 

    Appelez shouldShowRequestPermissionRationale pour voir si l'utilisateur a coché ne plus jamais demander. La méthode shouldShowRequestPermissionRationale renvoie false uniquement si l'utilisateur a sélectionné Ne plus demander ou si la stratégie du périphérique empêche l'application de disposer de cette autorisation:

    if (grantResults.length > 0){
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //Do the stuff that requires permission...
        }else if (grantResults[0] == PackageManager.PERMISSION_DENIED){
            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                //Show permission explanation dialog...
            }else{
                //Never ask again selected, or device policy prohibits the app from having that permission.
                //So, disable that feature, or fall back to another situation...
            }
        }
    }
    

Vous ne devez donc pas savoir si un utilisateur a coché ne plus jamais demander ou non.

144
CanC

J'ai eu le même problème et je l'ai compris. Pour simplifier la vie, j'ai écrit une classe util permettant de gérer les autorisations d'exécution.

public class PermissionUtil {
    /*
    * Check if version is Marshmallow and above.
    * Used in deciding to ask runtime permission
    * */
    public static boolean shouldAskPermission() {
        return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
    }
private static boolean shouldAskPermission(Context context, String permission){
        if (shouldAskPermission()) {
            int permissionResult = ActivityCompat.checkSelfPermission(context, permission);
            if (permissionResult != PackageManager.PERMISSION_GRANTED) {
                return true;
            }
        }
        return false;
    }
public static void checkPermission(Context context, String permission, PermissionAskListener listener){
/*
        * If permission is not granted
        * */
        if (shouldAskPermission(context, permission)){
/*
            * If permission denied previously
            * */
            if (((Activity) context).shouldShowRequestPermissionRationale(permission)) {
                listener.onPermissionPreviouslyDenied();
            } else {
                /*
                * Permission denied or first time requested
                * */
if (PreferencesUtil.isFirstTimeAskingPermission(context, permission)) {
                    PreferencesUtil.firstTimeAskingPermission(context, permission, false);
                    listener.onPermissionAsk();
                } else {
                    /*
                    * Handle the feature without permission or ask user to manually allow permission
                    * */
                    listener.onPermissionDisabled();
                }
            }
        } else {
            listener.onPermissionGranted();
        }
    }
/*
    * Callback on various cases on checking permission
    *
    * 1.  Below M, runtime permission not needed. In that case onPermissionGranted() would be called.
    *     If permission is already granted, onPermissionGranted() would be called.
    *
    * 2.  Above M, if the permission is being asked first time onPermissionAsk() would be called.
    *
    * 3.  Above M, if the permission is previously asked but not granted, onPermissionPreviouslyDenied()
    *     would be called.
    *
    * 4.  Above M, if the permission is disabled by device policy or the user checked "Never ask again"
    *     check box on previous request permission, onPermissionDisabled() would be called.
    * */
    public interface PermissionAskListener {
/*
        * Callback to ask permission
        * */
        void onPermissionAsk();
/*
        * Callback on permission denied
        * */
        void onPermissionPreviouslyDenied();
/*
        * Callback on permission "Never show again" checked and denied
        * */
        void onPermissionDisabled();
/*
        * Callback on permission granted
        * */
        void onPermissionGranted();
    }
}

Et les méthodes PreferenceUtil sont les suivantes.

public static void firstTimeAskingPermission(Context context, String permission, boolean isFirstTime){
SharedPreferences sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE;
 sharedPreference.edit().putBoolean(permission, isFirstTime).apply();
 }
public static boolean isFirstTimeAskingPermission(Context context, String permission){
return context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE).getBoolean(permission, true);
}

Maintenant, tout ce dont vous avez besoin est d’utiliser la méthode checkPermission avec les arguments appropriés.

Voici un exemple,

PermissionUtil.checkPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    new PermissionUtil.PermissionAskListener() {
                        @Override
                        public void onPermissionAsk() {
                            ActivityCompat.requestPermissions(
                                    thisActivity,
              new String[]{Manifest.permission.READ_CONTACTS},
                            REQUEST_EXTERNAL_STORAGE
                            );
                        }
@Override
                        public void onPermissionPreviouslyDenied() {
                       //show a dialog explaining permission and then request permission
                        }
@Override
                        public void onPermissionDisabled() {
Toast.makeText(context, "Permission Disabled.", Toast.LENGTH_SHORT).show();
                        }
@Override
                        public void onPermissionGranted() {
                            readContacts();
                        }
                    });

Cas 1: l'application n'a pas d'autorisation et l'utilisateur n'a pas été demandé la permission avant. Dans ce cas, shouldShowRequestPermissionRationale () retournera false car ceci C'est la première fois que nous demandons à l'utilisateur.

Cas 2: l'utilisateur a refusé l'autorisation et a sélectionné "Ne plus demander ", Dans ce cas également, shouldShowRequestPermissionRationale () will retourne faux.

Je voudrais envoyer l'utilisateur à la page des paramètres de l'application dans le cas 2 . Comment puis-je différencier ces deux cas?

Vous obtiendrez un rappel sur onPermissionAsk pour le cas 1 et onPermissionDisabled pour le cas 2.

Bonne codage :)

20
muthuraj

METTRE À JOUR

Je crois que la réponse ci-dessous de CanC est la bonne à suivre. Le seul moyen de savoir avec certitude est de vérifier cela dans le rappel onRequestPermissionResult à l'aide de shouldShowPermissionRationale. 

==

Ma réponse originale:

La seule façon que j'ai trouvée est de savoir par vous-même si c'est la première fois ou non (par exemple, en utilisant des préférences partagées). Si ce n'est pas la première fois, utilisez shouldShowRequestPermissionRationale() pour vous différencier. 

Voir aussi: Android M - vérifier l'autorisation d'exécution - comment déterminer si l'utilisateur a coché la case "Ne plus demander"?

8
Alex Florescu

Si je comprends bien, shouldShowRequestPermissionRationale () exécute un certain nombre de cas d'utilisation sous le capot et indique à l'application si elle doit ou non afficher une explication sur les autorisations demandées.

L'idée derrière les autorisations d'exécution est que la plupart du temps, l'utilisateur dira Oui à la demande d'autorisation. De cette façon, l'utilisateur n'aura à faire qu'un clic. Bien entendu, la requête doit être utilisée dans le contexte approprié, c'est-à-dire demander l'autorisation de la caméra lorsque le bouton "Caméra" est enfoncé. 

Si l'utilisateur refuse la demande, mais après un certain temps arrive et appuie à nouveau sur le bouton "Caméra", shouldShowRequestPermissionRationale () renverra la valeur true, de sorte que l'application puisse afficher une explication significative du motif de la demande d'autorisation et du refus de l'application. fonctionne correctement sans elle. Normalement, vous afficheriez dans cette boîte de dialogue un bouton pour refuser à nouveau/décider plus tard, et un bouton pour accorder les autorisations. Le bouton d'octroi d'autorisations dans la boîte de dialogue de justification doit relancer la demande d'autorisation. Cette fois, l'utilisateur aura également une case à cocher "Ne plus afficher". S'il décidait de le sélectionner et de refuser à nouveau l'autorisation, le système Android serait averti que l'utilisateur et l'application ne se trouvaient pas sur la même page. Cette action aurait deux conséquences: shouldShowRequestPermissionRationale () renverra toujours false et la méthode requestPermissions () ne montrera aucun dialogue, mais retournera directement refusée au rappel onRequestPermissionsResult. 

Mais il existe également un autre scénario possible dans lequel onRequestPermissionsResult pourrait être utilisé. Par exemple, certains périphériques peuvent avoir une stratégie de périphérique qui désactive l'appareil photo (fonctionne pour CIA, DARPA, etc.). Sur ces périphériques, onRequestPermissionsResult renverra toujours la valeur false et la méthode requestPermissions () refusera la demande en silence.

C'est ce que j'ai compris en écoutant le podcast avec Ben Poiesz - un chef de produit sous Android.
http://androidbackstage.blogspot.jp/2015/08/episode-33-permission-mission.html

6
Shumoapp

Il suffit de poster une autre option, si quelqu'un peut se sentir comme. Vous pouvez utiliser EasyPermissions, fourni par Google lui-même, pour "comme indiqué précédemment," Simplifier les autorisations du système Android M ".

Dans ce cas, vous n'avez pas à gérer shouldShowRequestPermissionRationale directement.

6
Wei WANG

Vérifiez cette implémentation. travaille très bien pour moi. En gros, vous vérifiez les autorisations dans la méthode checkPermissions () en passant une liste d’autorisations. Vous vérifiez le résultat de la demande d'autorisation sur onRequestPermissionsResult (). La mise en œuvre vous permet de traiter les deux cas lorsque l’utilisateur sélectionne "ne plus jamais demander" ou non. Dans cette implémentation, au cas où il choisit "ne plus jamais demander", la boîte de dialogue a une option pour l'emmener à l'activité Paramètres de l'application. 

Tout ce code est dans mon fragment. Je pensais qu'il serait préférable de créer un cours spécialisé pour le faire, comme un PermissionManager, mais je n'en suis pas sûr.

/**
     * responsible for checking if permissions are granted. In case permissions are not granted, the user will be requested and the method returns false. In case we have all permissions, the method return true.
     * The response of the request for the permissions is going to be handled in the onRequestPermissionsResult() method
     * @param permissions list of permissions to be checked if are granted onRequestPermissionsResult().
     * @param requestCode request code to identify this request in
     * @return true case we already have all permissions. false in case we had to Prompt the user for it.
     */
    private boolean checkPermissions(List<String> permissions, int requestCode) {
        List<String> permissionsNotGranted = new ArrayList<>();
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED)
                permissionsNotGranted.add(permission);
        }

        //If there is any permission we don't have (it's going to be in permissionsNotGranted List) , we need to request.
        if (!permissionsNotGranted.isEmpty()) {
            requestPermissions(permissionsNotGranted.toArray(new String[permissionsNotGranted.size()]), requestCode);
            return false;
        }
        return true;
    }

    /**
     * called after permissions are requested to the user. This is called always, either
     * has granted or not the permissions.
     * @param requestCode  int code used to identify the request made. Was passed as parameter in the
     *                     requestPermissions() call.
     * @param permissions  Array containing the permissions asked to the user.
     * @param grantResults Array containing the results of the permissions requested to the user.
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case YOUR_REQUEST_CODE: {
                boolean anyPermissionDenied = false;
                boolean neverAskAgainSelected = false;
                // Check if any permission asked has been denied
                for (int i = 0; i < grantResults.length; i++) {
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                        anyPermissionDenied = true;
                        //check if user select "never ask again" when denying any permission
                        if (!shouldShowRequestPermissionRationale(permissions[i])) {
                            neverAskAgainSelected = true;
                        }
                    }
                }
                if (!anyPermissionDenied) {
                    // All Permissions asked were granted! Yey!
                    // DO YOUR STUFF
                } else {
                    // the user has just denied one or all of the permissions
                    // use this message to explain why he needs to grant these permissions in order to proceed
                    String message = "";
                    DialogInterface.OnClickListener listener = null;
                    if (neverAskAgainSelected) {
                        //This message is displayed after the user has checked never ask again checkbox.
                        message = getString(R.string.permission_denied_never_ask_again_dialog_message);
                        listener = new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                //this will be executed if User clicks OK button. This is gonna take the user to the App Settings
                                startAppSettingsConfigActivity();
                            }
                        };
                    } else {
                        //This message is displayed while the user hasn't checked never ask again checkbox.
                        message = getString(R.string.permission_denied_dialog_message);
                    }
                    new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme)
                            .setMessage(message)
                            .setPositiveButton(getString(R.string.label_Ok), listener)
                            .setNegativeButton(getString(R.string.label_cancel), null)
                            .create()
                            .show();
                }
            }
            break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    /**
     * start the App Settings Activity so that the user can change
     * settings related to the application such as permissions.
     */
    private void startAppSettingsConfigActivity() {
        final Intent i = new Intent();
        i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        i.addCategory(Intent.CATEGORY_DEFAULT);
        i.setData(Uri.parse("package:" + getActivity().getPackageName()));
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        getActivity().startActivity(i);
    }
3
Thiago Saraiva

Peut être utile pour quelqu'un: -

Ce que j'ai remarqué, c'est que si nous actionnons l'indicateur shouldShowRequestPermissionRationale () dans la méthode de rappel onRequestPermissionsResult (), il n'affiche que deux états.

Etat 1: -Return true: - Chaque fois que l'utilisateur clique sur Refuser les autorisations (y compris la toute première fois).

Etat 2: -Retourne false: - si l'utilisateur sélectionne «ne demande jamais plus".

Lien pour un exemple de travail détaillé .

2
Nicks

Si quelqu'un est intéressé par une solution Kotlin, je refacturise @muthuraj pour lui demander d'être à Kotlin. Également modernisé un peu pour avoir un bloc d'achèvement au lieu des auditeurs.

PermissionUtil

object PermissionUtil {
    private val PREFS_FILE_NAME = "preference"

    fun firstTimeAskingPermission(context: Context, permission: String, isFirstTime: Boolean) {
        val sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE)
        sharedPreference.preferences.edit().putBoolean(permission,
                isFirstTime).apply()
    }

    fun isFirstTimeAskingPermission(context: Context, permission: String): Boolean {
        val sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE)
        return sharedPreference.preferences.getBoolean(permission,
                true)
    }
}

PermissionHandler

enum class CheckPermissionResult {
    PermissionAsk,
    PermissionPreviouslyDenied,
    PermissionDisabled,
    PermissionGranted
}

typealias PermissionCheckCompletion = (CheckPermissionResult) -> Unit


object PermissionHandler {

    private fun shouldAskPermission(context: Context, permission: String): Boolean {
        return ContextCompat.checkSelfPermission(context,
                permission) != PackageManager.PERMISSION_GRANTED
    }

    fun checkPermission(context: Context, permission: String, completion: PermissionCheckCompletion) {
        // If permission is not granted
        if (shouldAskPermission(context, permission)) {
            //If permission denied previously
            if ((context as Activity).shouldShowRequestPermissionRationale(permission)) {
                completion(CheckPermissionResult.PermissionPreviouslyDenied)
            } else {
                // Permission denied or first time requested
                if (PermissionUtil.isFirstTimeAskingPermission(context,
                                permission)) {
                    PermissionUtil.firstTimeAskingPermission(context,
                            permission,
                            false)
                    completion(CheckPermissionResult.PermissionAsk)
                } else {
                    // Handle the feature without permission or ask user to manually allow permission
                    completion(CheckPermissionResult.PermissionDisabled)
                }
            }
        } else {
            completion(CheckPermissionResult.PermissionGranted)
        }
    }
}

La mise en oeuvre

PermissionHandler.checkPermission(activity,
                    Manifest.permission.CAMERA) { result ->
                when (result) {
                    CheckPermissionResult.PermissionGranted -> {
                        // openCamera()
                    }
                    CheckPermissionResult.PermissionDisabled -> {
                        // displayAlert(noPermissionAlert)
                    }
                    CheckPermissionResult.PermissionAsk -> {
                        // requestCameraPermissions()
                    }
                    CheckPermissionResult.PermissionPreviouslyDenied -> {
                        // displayAlert(permissionRequestAlert)
                    }
                }
            }
1
bmjohns

On peut le faire de cette façon?

@Retention(RetentionPolicy.SOURCE)
@IntDef({GRANTED, DENIED, NEVER})
public @interface PermissionStatus {
}

public static final int GRANTED = 0;
public static final int DENIED = 1;
public static final int NEVER = 2;

@PermissionStatus
public static int getPermissionStatus(Activity activity, String permission) {
    if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
        return DENIED;
    } else {
        if (ActivityCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED) {
            return GRANTED;
        } else {
            return NEVER;
        }
    }
}
1
Dr. aNdRO

Ce code demande à l'utilisateur de demander la permission pendant l'exécution, Si l'utilisateur le permet, il exécute la méthode du résultat, Si l'utilisateur refuse, il demande à nouveau avec discription avec l'utilisateur refuse (il demande à nouveau avec des instructions), Mais si l’utilisateur choisit de ne plus jamais demander . il gère de ne plus jamais demander, affiche l’option des paramètres ouverts avec les instructions.

public String storagePermissions = Manifest.permission.READ_EXTERNAL_STORAGE;   
private static final int REQUEST_ACCESS =101;  

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      if(checkSelfPermission(storagePermissions)== PackageManager.PERMISSION_GRANTED){
          result();    // result  is your block of code 
      }else {
          requestPermissions(new String[]{storagePermissions},REQUEST_ACCESS);
      }

    }
    else{
        result();    //so if user is lower than api verison M, no permission is requested
    } 

}

 private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
    new AlertDialog.Builder(MainActivity.this)
            .setMessage(message)
            .setTitle("Hi User..")
            .setPositiveButton("Ok", okListener)
            .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {        //idea calling showMessage funtion again
                    Snackbar mySnackbar = Snackbar.make( findViewById(R.id.coordinatorlayout),"You Press Cancel.. ", Snackbar.LENGTH_INDEFINITE);
                    mySnackbar.setAction("Exit", new cancelButton());
                    mySnackbar.show();

                }
            })
            .create()
            .show();
}


private void result(){
          //your code
}

    @RequiresApi(api = Build.VERSION_CODES.M)
public class NeverAskAgain implements View.OnClickListener{
    @Override
    public void onClick(View view)
    {
        goToSettings();
    }
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void goToSettings() {
    Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
    finish();
    myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
    myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivityForResult(myAppSettings, REQUEST_APP_SETTINGS);
}
public class cancelButton implements View.OnClickListener{
    @Override
    public void onClick(View view){
        Toast.makeText(MainActivity.this,"To use this app , you must grant storage permission",Toast.LENGTH_SHORT);
        finish();
    }
    }


 @Override
@RequiresApi(api = Build.VERSION_CODES.M)
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode,permissions,grantResults);

    switch(requestCode) {
        case REQUEST_ACCESS:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission is granted
                    result();
                    break;
                }
                else if (!shouldShowRequestPermissionRationale(permissions[0])){
                    showMessageOKCancel("You choose Never Ask Again,option",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Snackbar mySnackbar = Snackbar.make(findViewById(R.id.coordinatorlayout), "Permission=>Storage=>On", Snackbar.LENGTH_INDEFINITE);
                        mySnackbar.setAction("Settings", new NeverAskAgain());
                        mySnackbar.show();
                    }
                     });
                    break;
                }
                else {
                    showMessageOKCancel("You Denid permission Request..",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            requestPermissions(new String[]{storagePermissions}, REQUEST_ACCESS);
                        }
                    });
                    break;
                }
        }
}
0
Abhiode

shouldShowRequestPermissionRationalefor permission SPECIAL renvoie toujours TRUE ONLY après que l'utilisateur l'ait refusé sans case à cocher

Nous sommes intéressés par la valeur FALSE

Donc, il y a 3 cas perdus avec la valeur false

1. il n'y avait aucune action de ce type auparavant et maintenant l'utilisateur décide d'accepter ou de refuser. 

Définissez simplement une préférence ASKED_PERMISSION_* qui n'existe pas maintenant et qui serait true dans onRequestPermissionsResult à son début dans tous les cas d'accord ou de refus

Ainsi, bien que cette préférence n'existe pas, il n'y a que aucune raison de cocher shouldShowRequestPermissionRationale

2. l'utilisateur a cliqué sur accepter. 

Faites simplement:

checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED

Ce qui retournera true et il n'y a aucune raison de vérifier shouldShowRequestPermissionRationale

3. L'utilisateur a cliqué sur Refuser avec la case à cocher (deuxième fois ou plus)

C'est THE TIME de travailler avec shouldShowRequestPermissionRationale qui retournera FALSE

(la préférence existe et nous n'avons pas de permission)

0
V. Kalyuzhnyu