web-dev-qa-db-fra.com

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

Selon ceci: http://developer.Android.com/preview/features/runtime-permissions.html#coding une application peut rechercher des autorisations d'exécution et demander des autorisations si elle n'a pas déjà été accordée. Le dialogue suivant sera alors affiché:

enter image description here

Si l'utilisateur refuse une autorisation importante, une application doit afficher une explication de la raison pour laquelle l'autorisation est nécessaire et de l'impact de cette suppression. Ce dialogue a deux options:

  1. réessayez à nouveau (l'autorisation est demandée à nouveau)
  2. refuser (l'application fonctionnera sans cette autorisation).

Si l'utilisateur vérifie cependant Never ask again, la deuxième boîte de dialogue contenant l'explication ne devrait pas être affichée, en particulier si l'utilisateur a déjà déjà refusé une fois auparavant ..____. Maintenant, la question est de savoir comment mon application sait si l'utilisateur a coché Never ask again? OMI la onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) ne me donne pas cette information.

Une deuxième question serait: Google envisage-t-il d'incorporer dans la boîte de dialogue des autorisations un message personnalisé expliquant pourquoi l'application a besoin de cette autorisation? De cette façon, il n’y aurait jamais de deuxième dialogue qui permettrait certainement un meilleur résultat.

257
Emanuel Moecklin

Developer Preview 2 apporte quelques modifications à la manière dont les autorisations sont demandées par l'application (voir aussi http://developer.Android.com/preview/support.html#preview2-notes ).

Le premier dialogue ressemble maintenant à ceci:

 enter image description here

Il n'y a pas de case à cocher "Ne plus montrer à nouveau" (contrairement à l'aperçu du développeur 1). Si l'utilisateur refuse l'autorisation et si l'autorisation est essentielle pour l'application, elle peut également présenter une autre boîte de dialogue pour expliquer la raison pour laquelle l'application demande cette autorisation, par exemple. comme ça:

 enter image description here

Si l'utilisateur refuse à nouveau, l'application doit être fermée si elle a absolument besoin de cette autorisation ou continuer à fonctionner avec des fonctionnalités limitées. Si l'utilisateur reconsidère (et sélectionne réessayer), l'autorisation est à nouveau demandée. Cette fois, l'invite ressemble à ceci:

 enter image description here

La deuxième fois, la case à cocher "Ne plus demander" est affichée. Si l'utilisateur refuse à nouveau et si la case à cocher est cochée, rien de plus ne devrait se produire . Si la case à cocher est cochée ou non, elle peut être déterminée en utilisant Activity.shouldShowRequestPermissionRationale (String), par exemple comme ça:

if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {...

C’est ce que dit la documentation Android ( https://developer.Android.com/training/permissions/requesting.html ):

Pour vous aider à trouver les situations dans lesquelles vous devez fournir un supplément explication, le système fournit le Activity.shouldShowRequestPermissionRationale (String). Ce La méthode retourne true si l'application a demandé cette autorisation précédemment et l'utilisateur a refusé la demande. Cela indique que vous devrait probablement expliquer à l'utilisateur pourquoi vous avez besoin de cette permission.

Si l'utilisateur a précédemment refusé la demande d'autorisation et choisi l'option Ne plus demander dans la boîte de dialogue du système de demande d'autorisation, cette méthode retourne false. La méthode retourne également false si le périphérique La politique interdit à l'application d'avoir cette autorisation. 

Pour savoir si l'utilisateur a refusé avec "ne plus jamais demander", vous pouvez vérifier à nouveau la méthode shouldShowRequestPermissionRationale dans votre onRequestPermissionsResult lorsque l'utilisateur n'a pas accordé l'autorisation.

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == REQUEST_PERMISSION) {
        // for each permission check if the user granted/denied them
        // you may want to group the rationale in a single dialog,
        // this is just an example
        for (int i = 0, len = permissions.length; i < len; i++) {
            String permission = permissions[i];
            if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
            // user rejected the permission
                boolean showRationale = shouldShowRequestPermissionRationale( permission );
                if (! showRationale) {
                    // user also CHECKED "never ask again"
                    // you can either enable some fall back,
                    // disable features of your app
                    // or open another dialog explaining
                    // again the permission and directing to
                    // the app setting
                } else if (Manifest.permission.WRITE_CONTACTS.equals(permission)) {
                    showRationale(permission, R.string.permission_denied_contacts);
                    // user did NOT check "never ask again"
                    // this is a good place to explain the user
                    // why you need the permission and ask if he wants
                    // to accept it (the rationale)
                } else if ( /* possibly check more permissions...*/ ) {
                }
            }
        }
    }
}

Vous pouvez ouvrir les paramètres de votre application avec ce code:

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);

Il n’existe aucun moyen d’envoyer l’utilisateur directement à la page Autorisation.

301
Emanuel Moecklin

Vous pouvez vérifier shouldShowRequestPermissionRationale() dans votre onRequestPermissionsResult().

 shouldShowRequestPermissionRationale https://youtu.be/C8lUdPVSzDk?t=2m23s

Vérifiez si la permission a été accordée ou non dans onRequestPermissionsResult(). Si not, cochez shouldShowRequestPermissionRationale()

  1. Si cette méthode retourne true, montrez une explication indiquant pourquoi cette autorisation particulière est nécessaire. Ensuite, en fonction du choix de l'utilisateur, requestPermissions().
  2. S'il renvoie false, affichez un message d'erreur indiquant que l'autorisation n'a pas été accordée et que l'application ne peut pas continuer ou qu'une fonctionnalité particulière est désactivée.

Vous trouverez ci-dessous un exemple de code.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case STORAGE_PERMISSION_REQUEST:
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission was granted :)
                downloadFile();
            } else {
                // permission was not granted
                if (getActivity() == null) {
                    return;
                }
                if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    showStoragePermissionRationale();
                } else {
                    Snackbar snackbar = Snackbar.make(getView(), getResources().getString(R.string.message_no_storage_permission_snackbar), Snackbar.LENGTH_LONG);
                    snackbar.setAction(getResources().getString(R.string.settings), new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (getActivity() == null) {
                                return;
                            }
                            Intent intent = new Intent();
                            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            Uri uri = Uri.fromParts("package", getActivity().getPackageName(), null);
                            intent.setData(uri);
                            OrderDetailFragment.this.startActivity(intent);
                        }
                    });
                    snackbar.show();
                }
            }
            break;
    }
}

Apparemment, Google Maps fait exactement cela pour obtenir une autorisation de localisation.

84
Abhinav Chauhan

Voici une méthode simple et conviviale pour vérifier l’état actuel des autorisations:

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

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

    @PermissionStatus 
    public static int getPermissionStatus(Activity activity, String androidPermissionName) {
        if(ContextCompat.checkSelfPermission(activity, androidPermissionName) != PackageManager.PERMISSION_GRANTED) {
            if(!ActivityCompat.shouldShowRequestPermissionRationale(activity, androidPermissionName)){
                return BLOCKED_OR_NEVER_ASKED;
            }
            return DENIED;
        }
        return GRANTED;
    }

Caveat: renvoie BLOCKED_OR_NEVER_ASKED au premier démarrage de l'application, avant que l'utilisateur n'accepte/refuse l'autorisation par l'intermédiaire de l'invite de l'utilisateur (sur les périphériques sdk 23+)

Mettre à jour:

La bibliothèque de support Android semble également avoir une classe très similaire Android.support.v4.content.PermissionChecker qui contient une checkSelfPermission() qui retourne:

public static final int PERMISSION_GRANTED = 0;
public static final int PERMISSION_DENIED = -1;
public static final int PERMISSION_DENIED_APP_OP = -2;
33
patrickf

Vous pouvez déterminer en vérifiant si l'autorisation justification doit être affichée dans la méthode de rappel onRequestPermissionsResult(). Et si vous trouvez une autorisation définie sur ne plus demander à nouveau, vous pouvez demander aux utilisateurs d'accorder des autorisations à partir des paramètres.

Ma mise en œuvre complète serait comme ci-dessous. Cela fonctionne à la fois pour les requêtes single ou multiple. Utilisez les éléments suivants ou utilisez directement ma bibliothèque.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if(permissions.length == 0){
        return;
    }
    boolean allPermissionsGranted = true;
    if(grantResults.length>0){
        for(int grantResult: grantResults){
            if(grantResult != PackageManager.PERMISSION_GRANTED){
                allPermissionsGranted = false;
                break;
            }
        }
    }
    if(!allPermissionsGranted){
        boolean somePermissionsForeverDenied = false;
        for(String permission: permissions){
            if(ActivityCompat.shouldShowRequestPermissionRationale(this, permission)){
                //denied
                Log.e("denied", permission);
            }else{
                if(ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED){
                    //allowed
                    Log.e("allowed", permission);
                } else{
                    //set to never ask again
                    Log.e("set to never ask again", permission);
                    somePermissionsForeverDenied = true;
                }
            }
        }
        if(somePermissionsForeverDenied){
            final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
            alertDialogBuilder.setTitle("Permissions Required")
                    .setMessage("You have forcefully denied some of the required permissions " +
                            "for this action. Please open settings, go to permissions and allow them.")
                    .setPositiveButton("Settings", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                                    Uri.fromParts("package", getPackageName(), null));
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        }
                    })
                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    })
                    .setCancelable(false)
                    .create()
                    .show();
        }
    } else {
        switch (requestCode) {
            //act according to the request code used while requesting the permission(s).
        }
    }
}
19
Nabin Bhandari

Peut être utile pour quelqu'un: -

Ce que j'ai remarqué, c'est que, si nous vérifions 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 de l'exemple de travail détaillé

19
Nicks

Une fois que l'utilisateur a marqué "Ne plus demander", la question ne peut plus être affichée . Mais vous pouvez expliquer à l'utilisateur qu'il a déjà refusé l'autorisation et qu'il doit accorder l'autorisation dans les paramètres. Et référencez-le aux paramètres, avec le code suivant:

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

    if (grantResults.length > 0
            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        // now, you have permission go ahead
        // TODO: something

    } else {

        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.READ_CALL_LOG)) {
            // now, user has denied permission (but not permanently!)

        } else {

            // now, user has denied permission permanently!

            Snackbar snackbar = Snackbar.make(findViewById(Android.R.id.content), "You have previously declined this permission.\n" +
                "You must approve this permission in \"Permissions\" in the app settings on your device.", Snackbar.LENGTH_LONG).setAction("Settings", new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                startActivity(new Intent(Android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + BuildConfig.APPLICATION_ID)));

            }
        });
        View snackbarView = snackbar.getView();
        TextView textView = (TextView) snackbarView.findViewById(Android.support.design.R.id.snackbar_text);
        textView.setMaxLines(5);  //Or as much as you need
        snackbar.show();

        }

    }
    return;
}
11
רותם ריכטר

Si vous souhaitez détecter tous les "états" (refusés pour la première fois, refusés, refusés avec "jamais demander à nouveau" ou refusés en permanence), vous pouvez procéder comme suit:

Créer 2 booléens

private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;

Définissez le premier avant de demander la permission:

beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Définissez le second dans votre méthode onRequestPermissionsResult:

afterClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Utilisez le "tableau" suivant pour faire tout ce dont vous avez besoin dans onRequestPermissionsResult () (après avoir vérifié que vous n'avez toujours pas l'autorisation):

// before after
// FALSE  FALSE  =  Was denied permanently, still denied permanently --> App Settings
// FALSE  TRUE   =  First time deny, not denied permanently yet --> Nothing
// TRUE   FALSE  =  Just been permanently denied --> Changing my caption to "Go to app settings to edit permissions"
// TRUE   TRUE   =  Wasn't denied permanently, still not denied permanently --> Nothing
9
mVck

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

comment mon application sait-elle si l'utilisateur a coché la case "Plus jamais demander"?

Si l'utilisateur a coché ne plus jamais demander , vous recevrez un rappel sur onPermissionDisabled.

Bonne codage :)

8
muthuraj

Explication complète pour chaque cas d'autorisation

/**
 *    Case 1: User doesn't have permission
 *    Case 2: User has permission
 *
 *    Case 3: User has never seen the permission Dialog
 *    Case 4: User has denied permission once but he din't clicked on "Never Show again" check box
 *    Case 5: User denied the permission and also clicked on the "Never Show again" check box.
 *    Case 6: User has allowed the permission
 *
 */
public void handlePermission() {
    if (ContextCompat.checkSelfPermission(MainActivity.this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        // This is Case 1. Now we need to check further if permission was shown before or not

        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

            // This is Case 4.
        } else {
            // This is Case 3. Request for permission here
        }

    } else {
        // This is Case 2. You have permission now you can do anything related to it
    }
}

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

    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        // This is Case 2 (Permission is now granted)
    } else {
        // This is Case 1 again as Permission is not granted by user

        //Now further we check if used denied permanently or not
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            // case 4 User has denied permission but not permanently

        } else {
            // case 5. Permission denied permanently.
            // You can open Permission setting's page from here now.
        }

    }
}
3
saksham

J'ai rédigé un raccourci pour la demande d'autorisation dans Android M. Ce code gère également la compatibilité avec les versions antérieures d'Android.

Tout le code laid est extrait dans un fragment qui s'attache et se détache de l'activité demandant les autorisations. Vous pouvez utiliser PermissionRequestManager comme suit:

new PermissionRequestManager()
        // We need a AppCompatActivity here, if you are not using support libraries you will have to slightly change 
        // the PermissionReuqestManager class
        .withActivity(this)

        // List all permissions you need
        .withPermissions(Android.Manifest.permission.CALL_PHONE, Android.Manifest.permission.READ_CALENDAR)

        // This Runnable is called whenever the request was successfull
        .withSuccessHandler(new Runnable() {
            @Override
            public void run() {
                // Do something with your permissions!
                // This is called after the user has granted all 
                // permissions, we are one a older platform where 
                // the user does not need to grant permissions 
                // manually, or all permissions are already granted

            }
        })

        // Optional, called when the user did not grant all permissions
        .withFailureHandler(new Runnable() {
            @Override
            public void run() {
                // This is called if the user has rejected one or all of the requested permissions
                L.e(this.getClass().getSimpleName(), "Unable to request permission");

            }
        })

        // After calling this, the user is prompted to grant the rights
        .request();

Jetez un coup d'œil: https://Gist.github.com/crysxd/385b57d74045a8bd67c4110c34ab74aa

2
crysxd

Une fonction utile pour déterminer si une demande de permission arbitraire a été bloquée (en Kotlin):

private fun isPermissionBlockedFromAsking(activity: Activity, permission: String): Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        return ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED
            && !activity.shouldShowRequestPermissionRationale(permission)
            && PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false)
    }
    return false
}

Pour cela, vous devez définir un booléen de préférence partagée avec le nom de votre autorisation souhaitée (par exemple, Android.Manifest.permission.READ_PHONE_STATE) sur true lors de votre première demande d'autorisation. 


Explication:

Build.VERSION.SDK_INT >= Build.VERSION_CODES.M car une partie du code ne peut être exécutée que sur l'API de niveau 23+.

ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED pour vérifier que nous n'avons pas encore l'autorisation.

!activity.shouldShowRequestPermissionRationale(permission) pour vérifier si l'utilisateur a refusé l'application à nouveau. En raison de des bizarreries de cette fonction , la ligne suivante est également requise.

PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false) Ceci est utilisé (avec la définition de la valeur sur true lors de la première demande d'autorisation) pour distinguer les états "jamais demandé" et "ne plus demander", car la ligne précédente ne renvoie pas cette information.

2
JakeSteam

La méthode shouldShowRequestPermissionRationale () peut permettre à l'utilisateur de vérifier si l'utilisateur a sélectionné l'option "ne plus jamais demander" et a refusé l'autorisation. un objectif, car je pense que son nom et sa mise en œuvre compliquent davantage la situation.

Comme expliqué dans Demander des autorisations au moment de l'exécution , cette méthode renvoie true si l'option 'ne plus jamais demander' est visible, false sinon; il renvoie donc false dès la première fois qu'une boîte de dialogue est affichée, puis à partir de la deuxième fois, il renvoie true et si l'utilisateur refuse l'autorisation en sélectionnant l'option, il renvoie à nouveau false.

Pour détecter un tel cas, vous pouvez détecter la séquence false-true-false ou (plus simplement) un indicateur qui garde la trace de la première fois que la boîte de dialogue est affichée. Après cela, cette méthode renvoie true ou false, la valeur false vous permettant de détecter le moment où l'option est sélectionnée.

2
Alessio

Essayez cette simple bibliothèque de permissions. Il gérera toutes les opérations liées aux autorisations en 3 étapes faciles. Cela m'a fait gagner du temps. Vous pouvez terminer tous les travaux liés aux autorisations en 15 minutes.

Il peut gérer refuser, il peut gérer ne plus jamais demander, il peut appeler les paramètres de l'application pour obtenir une autorisation, il peut donner un message rationnel, il peut donner un message de refus, il peut donner une liste des autorisations acceptées autorisations et etc.

https://github.com/ParkSangGwon/TedPermission

Etape 1: ajoutez votre dépendance

dependencies {
     compile 'gun0912.ted:tedpermission:2.1.1'
     //check the above link for latest libraries
}

Step2: Demander les autorisations

TedPermission.with(this)
    .setPermissionListener(permissionlistener)
    .setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
    .setPermissions(Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION)
    .check();

Étape 3: Gestion de la réponse à l'autorisation

PermissionListener permissionlistener = new PermissionListener() {
    @Override
    public void onPermissionGranted() {
        Toast.makeText(MainActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onPermissionDenied(ArrayList<String> deniedPermissions) {
        Toast.makeText(MainActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
    }
};
2
Vignes

Vous pouvez utiliser 

shouldShowRequestPermissionRationale()

à l'intérieur 

onRequestPermissionsResult()

Voir l'exemple ci-dessous:

Vérifiez si l'utilisateur a l'autorisation lorsque l'utilisateur clique sur le bouton:

@Override
public void onClick(View v) {
    if (v.getId() == R.id.appCompatBtn_changeProfileCoverPhoto) {
        if (Build.VERSION.SDK_INT < 23) { // API < 23 don't need to ask permission
            navigateTo(MainActivity.class); // Navigate to activity to change photos
        } else {
            if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED) {
                // Permission is not granted yet. Ask for permission...
                requestWriteExternalPermission();
            } else {
                // Permission is already granted, good to go :)
                navigateTo(MainActivity.class);
            }
        } 
    }
}

Lorsque l'utilisateur répondra à la boîte de dialogue d'autorisation, nous irons à onRequestPermissionResult:

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

    if (requestCode == WRITE_EXTERNAL_PERMISSION_REQUEST_CODE) {
        // Case 1. Permission is granted.  
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {  
            if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                // Before navigating, I still check one more time the permission for good practice.
                navigateTo(MainActivity.class);
            }
        } else { // Case 2. Permission was refused
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                // Case 2.1. shouldShowRequest... returns true because the
                // permission was denied before. If it is the first time the app is running we will 
                // end up in this part of the code. Because he need to deny at least once to get 
                // to onRequestPermissionsResult. 
                Snackbar snackbar = Snackbar.make(findViewById(R.id.relLayout_container), R.string.you_must_verify_permissions_to_send_media, Snackbar.LENGTH_LONG);
                snackbar.setAction("VERIFY", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        ActivityCompat.requestPermissions(SettingsActivity.this
                                , new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}
                                , WRITE_EXTERNAL_PERMISSION_REQUEST_CODE);
                    }
                });
                snackbar.show();
            } else {
                // Case 2.2. Permission was already denied and the user checked "Never ask again". 
                // Navigate user to settings if he choose to allow this time.
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage(R.string.instructions_to_turn_on_storage_permission)
                        .setPositiveButton(getString(R.string.settings), new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Intent settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                Uri uri = Uri.fromParts("package", getPackageName(), null);
                                settingsIntent.setData(uri);
                                startActivityForResult(settingsIntent, 7);
                            }
                        })
                        .setNegativeButton(getString(R.string.not_now), null);
                Dialog dialog = builder.create();
                dialog.show();
            }
        }
    }

}
1
Soon Santos

S'il vous plaît, ne me lancez pas de pierres pour cette solution. 

Cela fonctionne mais est un peu "hacky".

Lorsque vous appelez requestPermissions, enregistrez l’heure actuelle.

        mAskedPermissionTime = System.currentTimeMillis();

Puis dans onRequestPermissionsResult 

si le résultat n'est pas obtenu, vérifiez à nouveau l'heure.

 if (System.currentTimeMillis() - mAskedPermissionTime < 100)

Puisque l'utilisateur n'a pas pu cliquer aussi rapidement sur le bouton de refus, nous savons qu'il a sélectionné "ne plus jamais demander" car le rappel est instantané.

Utilisez à vos risques et périls.

1
Antzi

vous pouvez écouter jolie.

Auditeur

interface PermissionListener {
    fun onNeedPermission()
    fun onPermissionPreviouslyDenied(numberDenyPermission: Int)
    fun onPermissionDisabledPermanently(numberDenyPermission: Int)
    fun onPermissionGranted()
}

MainClass pour permission

class PermissionUtil {

    private val PREFS_FILENAME = "permission"
    private val TAG = "PermissionUtil"

    private fun shouldAskPermission(context: Context, permission: String): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val permissionResult = ActivityCompat.checkSelfPermission(context, permission)
            if (permissionResult != PackageManager.PERMISSION_GRANTED) {
                return true
            }
        }
        return false
    }

    fun checkPermission(context: Context, permission: String, listener: PermissionListener) {

        Log.i(TAG, "CheckPermission for $permission")

        if (shouldAskPermission(context, permission)) {

            // Load history permission
            val sharedPreference = context.getSharedPreferences(PREFS_FILENAME, 0)
            val numberShowPermissionDialog = sharedPreference.getInt(permission, 0)

            if (numberShowPermissionDialog == 0) {

                (context as? Activity)?.let {
                    if (ActivityCompat.shouldShowRequestPermissionRationale(it, permission)) {
                        Log.e(TAG, "User has denied permission but not permanently")
                        listener.onPermissionPreviouslyDenied(numberShowPermissionDialog)
                    } else {
                        Log.e(TAG, "Permission denied permanently.")
                        listener.onPermissionDisabledPermanently(numberShowPermissionDialog)
                    }
                } ?: kotlin.run {
                    listener.onNeedPermission()
                }

            } else {
                // Is FirstTime
                listener.onNeedPermission()
            }


            // Save history permission
            sharedPreference.edit().putInt(permission, numberShowPermissionDialog + 1).apply()


        } else {
            listener.onPermissionGranted()
        }

    }
}

Utilisé de cette façon  

      PermissionUtil().checkPermission(this, Manifest.permission.ACCESS_FINE_LOCATION,
                object : PermissionListener {
                    override fun onNeedPermission() {
                        log("---------------------->onNeedPermission")

//                            ActivityCompat.requestPermissions(this@SplashActivity,
//                                    Array(1) { Manifest.permission.ACCESS_FINE_LOCATION },
//                                    118)

                    }

                    override fun onPermissionPreviouslyDenied(numberDenyPermission: Int) {
                        log("---------------------->onPermissionPreviouslyDenied")
                    }

                    override fun onPermissionDisabledPermanently(numberDenyPermission: Int) {
                        log("---------------------->onPermissionDisabled")
                    }

                    override fun onPermissionGranted() {
                        log("---------------------->onPermissionGranted")
                    }

                })

override onRequestPermissionsResult en activité ou fragmnet

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
 if (requestCode == 118) {
        if (permissions[0] == Manifest.permission.ACCESS_FINE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            getLastLocationInMap()
        }
        }
    }
1
Rasoul Miri
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    switch (requestCode) {
        case PERMISSIONS_REQUEST_EXTERNAL_STORAGE: {
            if (grantResults.length > 0) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    // Denied
                } else {
                    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                        // To what you want
                    } else {
                       // Bob never checked click
                    }
                }
            }
        }
    }
}
0
Vinod Ranga

En développant la réponse de mVck ci-dessus, la logique suivante détermine si "Jamais demander à nouveau" a été vérifié pour une demande de permission donnée:

bool bStorage = grantResults[0] == Permission.Granted;
bool bNeverAskForStorage =
    !bStorage && (
        _bStorageRationaleBefore == true  && _bStorageRationaleAfter == false ||
        _bStorageRationaleBefore == false && _bStorageRationaleAfter == false
    );

qui est extrait d'en bas (pour l'exemple complet voir cette réponse )

private bool _bStorageRationaleBefore;
private bool _bStorageRationaleAfter;        
private const int Android_PERMISSION_REQUEST_CODE__SDCARD = 2;
//private const int Android_PERMISSION_REQUEST_CODE__CAMERA = 1;
private const int Android_PERMISSION_REQUEST_CODE__NONE = 0;

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode)
    {
        case Android_PERMISSION_REQUEST_CODE__SDCARD:               
            _bStorageRationaleAfter = ShouldShowRequestPermissionRationale(Android.Manifest.Permission.WriteExternalStorage);
            bool bStorage = grantResults[0] == Permission.Granted;
            bool bNeverAskForStorage =
                !bStorage && (
                    _bStorageRationaleBefore == true  && _bStorageRationaleAfter == false ||
                    _bStorageRationaleBefore == false && _bStorageRationaleAfter == false
                );      
            break;                
    }
}

private List<string> GetRequiredPermissions(out int requestCode)
{
    // Android v6 requires explicit permission granting from user at runtime for security reasons            
    requestCode = Android_PERMISSION_REQUEST_CODE__NONE; // 0
    List<string> requiredPermissions = new List<string>();

    _bStorageRationaleBefore = ShouldShowRequestPermissionRationale(Android.Manifest.Permission.WriteExternalStorage);
    Permission writeExternalStoragePerm = ApplicationContext.CheckSelfPermission(Android.Manifest.Permission.WriteExternalStorage);
    //if(extStoragePerm == Permission.Denied)
    if (writeExternalStoragePerm != Permission.Granted)
    {
        requestCode |= Android_PERMISSION_REQUEST_CODE__SDCARD;
        requiredPermissions.Add(Android.Manifest.Permission.WriteExternalStorage);
    }

    return requiredPermissions;
}

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

        // Android v6 requires explicit permission granting from user at runtime for security reasons
        int requestCode;
        List<string> requiredPermissions = GetRequiredPermissions(out requestCode);
        if (requiredPermissions != null && requiredPermissions.Count > 0)
        {
            if (requestCode >= Android_PERMISSION_REQUEST_CODE__SDCARD)                    
            {
                _savedInstanceState = savedInstanceState;
                RequestPermissions(requiredPermissions.ToArray(), requestCode);
                return;
            }
        }
    }            

    OnCreate2(savedInstanceState);
}
0
samis

Au lieu de cela, vous recevrez un rappel sur onRequestPermissionsResult() sous la forme PERMISSION_DENIED lorsque vous redemanderez une autorisation alors que vous tombez dans une condition fausse de shouldShowRequestPermissionRationale()

De doc Android:

Lorsque le système demande à l'utilisateur d'accorder une autorisation, l'utilisateur a la possibilité de demander au système de ne plus demander cette autorisation. Dans ce cas, chaque fois qu'une application utilise requestPermissions() pour demander à nouveau cette autorisation, le système refuse immédiatement la demande. Le système appelle votre méthode de rappel onRequestPermissionsResult() et transmet PERMISSION_DENIED de la même manière que si l'utilisateur avait explicitement rejeté votre demande. Cela signifie que lorsque vous appelez requestPermissions(), vous ne pouvez pas supposer qu'une interaction directe avec l'utilisateur a eu lieu.

0
Farhan

Pour répondre à la question avec précision, Que se passe-t-il lorsque l'utilisateur appuie sur "Ne plus demander"?

La méthode/fonction remplacée

onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray)

Le tableau grantResult est vide, vous pouvez donc faire quelque chose? Mais pas la meilleure pratique.

Comment gérer "ne jamais demander à nouveau"?

Je travaille avec Fragment, qui nécessitait l'autorisation READ_EXTERNAL_STORAGE.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        when {
            isReadPermissionsGranted() -> {

                /**
                 * Permissions has been Granted
                 */

                getDirectories()
            }

            isPermissionDeniedBefore() -> {

                /**
                 * User has denied before, explain why we need the permission and ask again
                 */

                updateUIForDeniedPermissions()
                checkIfPermissionIsGrantedNow()

            }
            else -> {

                /**
                 * Need to ask For Permissions, First Time
                 */

                checkIfPermissionIsGrantedNow()

                /**
                 * If user selects, "Dont Ask Again" it will never ask again! so just update the UI for Denied Permissions
                 */

                updateUIForDeniedPermissions()

            }
        }
    }

Les autres fonctions sont triviales.

// Is Read Write Permissions Granted
fun isReadWritePermissionGranted(context: Context): Boolean {
    return (ContextCompat.checkSelfPermission(
        context as Activity,
        Manifest.permission.READ_EXTERNAL_STORAGE
    ) == PackageManager.PERMISSION_GRANTED) and
            (ContextCompat.checkSelfPermission(
                context,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED)
}

fun isReadPermissionDenied(context: Context) : Boolean {
    return ActivityCompat.shouldShowRequestPermissionRationale(
        context as Activity,
        PermissionsUtils.READ_EXTERNAL_STORAGE_PERMISSIONS)
}
0
devDeejay

vous pouvez lire le document officiel Android Demander des autorisations d'applications

ou vous pouvez trouver de nombreuses bibliothèques de permission Android populaires sur Github

0
shellhub

Je voudrais aussi obtenir l'information si l'utilisateur a sélectionné ou non "ne plus jamais demander". J'ai atteint une "presque solution" avec un drapeau qui a l'air laid, mais avant de vous dire comment, je vais vous parler de ma motivation:

Je voudrais offrir la fonctionnalité de référence de permission initialement. Si l'utilisateur l'utilise sans droits, il obtient le 1 er dialogue par le haut ou les 2 et 3. Lorsque l'utilisateur a choisi "Ne plus jamais demander", je souhaite désactiver la fonctionnalité et l'afficher différemment. - Mon action est déclenchée par une entrée de texte en rotation. J'aimerais également ajouter '(Autorisation révoquée)' au texte de l'étiquette affiché. Cela montre à l'utilisateur: "Il existe une fonctionnalité, mais je ne peux pas l'utiliser en raison de mes paramètres d'autorisation." Cependant, cela ne semble pas être possible, car je ne peux pas vérifier si l'option «Ne plus demander» a été choisie.

Je suis arrivé à une solution avec laquelle je peux vivre en ayant toujours activé ma fonctionnalité avec une vérification active des autorisations. Je montre un message Toast dans onRequestPermissionsResult () en cas de réponse négative, mais uniquement si je n'ai pas affiché ma fenêtre contextuelle de justification personnalisée. Ainsi, si l'utilisateur a choisi de ne plus jamais demander, il reçoit uniquement un message de pain grillé. Si l'utilisateur hésite à choisir de ne plus jamais demander, il obtient uniquement la justification personnalisée et la demande de permission par le système d'exploitation, mais pas de pain grillé, car trois notifications consécutives seraient trop pénibles.

0
ChristianKoelle

Je dois implémenter une autorisation dynamique pour la caméra. Lorsque 3 cas possibles se produisent: 1. Autoriser, 2. Refusé, 3. Ne plus demander.

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

    for (String permission : permissions) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permission)) {
            //denied
            Log.e("denied", permission);
        } else {
            if (ActivityCompat.checkSelfPermission(getActivity(), permission) == PackageManager.PERMISSION_GRANTED) {
                //allowed
                Log.e("allowed", permission);
            } else {
                //set to never ask again
                Log.e("set to never ask again", permission);
                //do something here.
            }
        }
    }
    if (requestCode != MaterialBarcodeScanner.RC_HANDLE_CAMERA_PERM) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        return;
    }
    if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        mScannerView.setResultHandler(this);
        mScannerView.startCamera(mCameraId);
        mScannerView.setFlash(mFlash);
        mScannerView.setAutoFocus(mAutoFocus);
        return;
    } else {
        //set to never ask again
        Log.e("set to never ask again", permissions[0]);
    }
    DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
        }
    };
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setTitle("Error")
            .setMessage(R.string.no_camera_permission)
            .setPositiveButton(Android.R.string.ok, listener)
            .show();


}

private void insertDummyContactWrapper() {
        int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CAMERA);
        if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.CAMERA},
                    REQUEST_CODE_ASK_PERMISSIONS);
            return;
        }
        mScannerView.setResultHandler(this);
        mScannerView.startCamera(mCameraId);
        mScannerView.setFlash(mFlash);
        mScannerView.setAutoFocus(mAutoFocus);
    }

private int checkSelfPermission(String camera) {
    if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        return REQUEST_CODE_ASK_PERMISSIONS;
    } else {
        return REQUEST_NOT_CODE_ASK_PERMISSIONS;
    }
}
0
hitesh141

Vous pouvez utiliser la méthode if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA) pour déterminer si jamais demander est cochée ou non.

Pour plus de référence: Cochez cette case

Pour vérifier plusieurs autorisations, utilisez:

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

méthode explicit ()

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

Le code ci-dessus affichera également une boîte de dialogue, qui redirigera l'utilisateur vers l'écran des paramètres de l'application à partir duquel il pourra donner sa permission s'il avait coché ne plus jamais demander le bouton.

0
user6435056