Android M: verifica l'autorizzazione di runtime: come determinare se l'utente ha selezionato "Non chiedere più"?


307

In base a questo: http://developer.android.com/preview/features/runtime-permissions.html#coding un'app può verificare le autorizzazioni di runtime e richiedere autorizzazioni se non è già stata concessa. Verrà visualizzata la seguente finestra di dialogo:

inserisci qui la descrizione dell'immagine

Nel caso in cui l'utente rifiuti un'autorizzazione importante, in un'app dovrebbe essere visualizzata una spiegazione del motivo per cui è necessaria l'autorizzazione e quale impatto ha il rifiuto. Quella finestra di dialogo ha due opzioni:

  1. riprovare (viene richiesta nuovamente l'autorizzazione)
  2. nega (l'app funzionerà senza tale autorizzazione).

Se l'utente verifica Never ask againcomunque, la seconda finestra di dialogo con la spiegazione non dovrebbe essere mostrata, specialmente se l'utente ha già rifiutato una volta. Ora la domanda è: come fa la mia app a sapere se l'utente ha verificato il Never ask again? L'IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)non mi fornisce queste informazioni.

Una seconda domanda sarebbe: Google ha in programma di incorporare un messaggio personalizzato nella finestra di dialogo delle autorizzazioni che spiegherebbe perché l'app ha bisogno dell'autorizzazione? In questo modo non ci sarebbe mai un secondo dialogo che renderebbe sicuramente migliore.


9
"Google ha in programma di incorporare un messaggio personalizzato nella finestra di dialogo delle autorizzazioni che spiegherebbe perché l'app necessita dell'autorizzazione?" - nella presentazione di Google I | O sul sistema di autorizzazioni M, mi sembra di ricordare che qualcuno ha chiesto nelle Domande e risposte e la risposta è stata che ci stanno pensando.
CommonsWare

1
Non l'ho provato da solo, ma la documentazione dice di Activity.shouldShowRequestPermissionRationale (String): questo metodo restituisce true se l'app ha richiesto questa autorizzazione in precedenza e l'utente ha rifiutato la richiesta. Ciò indica che probabilmente dovresti spiegare all'utente perché hai bisogno dell'autorizzazione. Se in passato l'utente ha rifiutato la richiesta di autorizzazione e ha scelto l'opzione Non chiedere più nella finestra di dialogo del sistema di richiesta di autorizzazione, questo metodo restituisce false. Il metodo restituisce inoltre false se la politica del dispositivo proibisce all'app di disporre di tale autorizzazione.
Fraid,

1
@Fraid: sembra che abbiano aggiunto questo con l'anteprima n. 2 di Android M: developer.android.com/preview/support.html#preview2-notes ed è probabilmente quello che stavo cercando. Non posso provarlo adesso, ma lo farò la prossima settimana. Se fa quello che spero faccia, puoi pubblicarlo come risposta e ottenere una certa reputazione. Nel frattempo questo potrebbe aiutare gli altri: youtube.com/watch?v=f17qe9vZ8RM
Emanuel Moecklin

esempio di autorizzazioni pericolose e autorizzazioni speciali: github.com/henrychuangtw/AndroidRuntimePermission
HenryChuang

1
@Alex è più difficile per gli sviluppatori, questo è certo, ma dal punto di vista dell'utente è logico poter concedere o negare autorizzazioni specifiche. Il problema principale che vedo è che la granularità delle autorizzazioni è molto incoerente e si finisce per chiedere un'autorizzazione che potrebbe non avere quasi nulla a che fare con ciò che si sta tentando di fare nella propria app (ad esempio l'autorizzazione dei contatti quando si desidera connettersi a Google Drive perché necessita di un elenco degli account del dispositivo a fini di autenticazione e l'autorizzazione dell'account fa parte del gruppo di autorizzazioni di contatto).
Emanuel Moecklin,

Risposte:


341

Developer Preview 2 apporta alcune modifiche al modo in cui le autorizzazioni sono richieste dall'app (vedi anche http://developer.android.com/preview/support.html#preview2-notes ).

La prima finestra di dialogo ora appare così:

inserisci qui la descrizione dell'immagine

Non è presente la casella di controllo "Non mostrare più" (a differenza dell'anteprima per gli sviluppatori 1). Se l'utente nega l'autorizzazione e se l'autorizzazione è essenziale per l'app, potrebbe presentare un'altra finestra di dialogo per spiegare il motivo per cui l'app richiede tale autorizzazione, ad esempio in questo modo:

inserisci qui la descrizione dell'immagine

Se l'utente rifiuta di nuovo l'app dovrebbe spegnersi se necessita assolutamente di tale autorizzazione o continuare a funzionare con funzionalità limitate. Se l'utente riconsidera (e seleziona riprova), l'autorizzazione viene nuovamente richiesta. Questa volta il prompt è simile al seguente:

inserisci qui la descrizione dell'immagine

La seconda volta viene visualizzata la casella di controllo "Non chiedere più". Se l'utente nega di nuovo e la casella di controllo è selezionata, non dovrebbe succedere altro. È possibile determinare se la casella di controllo è selezionata o meno utilizzando Activity.shouldShowRequestPermissionRationale (String), ad esempio in questo modo:

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

Ecco cosa dice la documentazione di Android ( https://developer.android.com/training/permissions/requesting.html ):

Per aiutare a trovare le situazioni in cui è necessario fornire ulteriori spiegazioni, il sistema fornisce il metodo Activity.shouldShowRequestPermissionRationale (String). Questo metodo restituisce true se l'app ha richiesto questa autorizzazione in precedenza e l'utente ha rifiutato la richiesta. Ciò indica che probabilmente dovresti spiegare all'utente perché hai bisogno dell'autorizzazione.

Se in passato l'utente ha rifiutato la richiesta di autorizzazione e ha scelto l'opzione Non chiedere più nella finestra di dialogo del sistema di richiesta di autorizzazione, questo metodo restituisce false. Il metodo restituisce inoltre false se la politica del dispositivo proibisce all'app di disporre di tale autorizzazione.

Per sapere se l'utente negato con "non chiedere mai più" è possibile verificare nuovamente il metodo shouldShowRequestPermissionRationale nel proprio onRequestPermissionsResult quando l'utente non ha concesso l'autorizzazione.

@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...*/ ) {
                }
            }
        }
    }
}

Puoi aprire le impostazioni dell'app con questo codice:

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

Non è possibile inviare l'utente direttamente alla pagina di autorizzazione.


30
Ho verificato il valore di ritorno del metodo shouldShowRequestPermissionRationale () su false per verificare se l'utente ha selezionato "Non chiedere più". Ma sto anche ottenendo il suo valore come falso per la prima volta quando chiedo il permesso. Quindi non sono in grado di differenziare se l'utente ha selezionato la casella di controllo "Non chiedere più" o meno. Per favore, suggerisci ??
Sagar Trehan

32
Secondo la mia comprensione, il metodo shouldShowRationalePermissionRationale () restituisce false in tre casi: 1. Se chiamiamo questo metodo la prima volta prima di chiedere l'autorizzazione. 2. Se l'utente seleziona "Non chiedere più" e nega l'autorizzazione. 3. Se i criteri del dispositivo vietano all'app di disporre di tale autorizzazione
Sagar Trehan,

24
Tutto bene ... ma noi sviluppatori dobbiamo davvero sapere se l'utente ha detto "non chiedere mai più" o no. Ho un bel pulsante per accedere a una funzione. La prima volta che l'utente fa clic: dovrebbe chiedere la logica? no, chiedi il permesso. L'utente nega. L'utente fa di nuovo clic sul pulsante: razionale? Sì! Mostra logica, l'utente dice Ok, quindi nega e non chiedere mai più (ok lui è un idiota, ma gli utenti spesso lo sono). Successivamente l'utente preme di nuovo il pulsante, razionale? no, chiedi il permesso, non succede nulla per l'utente. Ho davvero bisogno di un modo, lì, per dire all'utente: hey amico, se vuoi questa funzionalità ora vai alle impostazioni dell'app e dai il permesso.
Daniele Segato,

4
Ottimo @EmanuelMoecklin questo è meglio della documentazione di Google ora: D
Daniele Segato,

4
onRequestPermissionsResult non verrà chiamato se non si richiede l'autorizzazione. Poiché non è presente la casella di controllo "Non chiedere mai più" la prima volta che viene richiesta l'autorizzazione, shouldShowRequestPermissionRationale restituirà True (autorizzazione richiesta ma senza mai più chiedere). Di conseguenza, la logica viene sempre mostrata la prima volta che l'utente rifiuta l'autorizzazione, ma solo se la casella di controllo non è stata selezionata.
Emanuel Moecklin,

95

Puoi fare il check- shouldShowRequestPermissionRationale()in onRequestPermissionsResult().

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

Verifica se l'autorizzazione è stata concessa o meno onRequestPermissionsResult(). In caso contrario, controllare shouldShowRequestPermissionRationale().

  1. Se questo metodo viene restituito, truemostra una spiegazione del motivo per cui è necessaria questa autorizzazione specifica. Quindi a seconda della scelta dell'utente di nuovo requestPermissions().
  2. Se ritorna, falsemostra un messaggio di errore in cui l'autorizzazione non è stata concessa e l'app non può procedere oltre o una particolare funzionalità è disabilitata.

Di seguito è riportato un codice di esempio.

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

Apparentemente, google maps fa esattamente questo per l'autorizzazione della posizione.


Grazie per l'immagine e il link Youtube. Abbina più o meno la mia risposta. Va notato che la domanda è stata posta quando era disponibile solo l'anteprima per sviluppatori 1 che non aveva il metodo shouldShowRequestPermissionRationale.
Emanuel Moecklin,

sono nuovo in Android e voglio superare questo metodo onRequestPermissionsResult (). ma sto ricevendo l'errore che deve implementare un metodo di tipo super. puoi dire come usarlo
Andrain,

39

Ecco un metodo semplice e intuitivo per verificare lo stato attuale delle autorizzazioni:

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

Avvertenza: restituisce BLOCKED_OR_NEVER_ASKED al primo avvio dell'app, prima che l'utente abbia accettato / negato l'autorizzazione tramite il prompt utente (su dispositivi SDK 23+)

Aggiornare:

La libreria di supporto Android ora sembra avere anche una classe molto simile android.support.v4.content.PermissionCheckerche contiene una checkSelfPermission()che restituisce:

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

1
Per il primo lancio, sto memorizzando un valore booleano nelle preferenze condivise.
Saeid Farivar,

5
Questo ritorna sempre BLOCKED_OR_NEVER_ASKEDse l'autorizzazione non è ancora stata richiesta.
Saket,

6
sì, questa è la ragione per cui si chiama "BLOCKED_OR_NEVER_ASKED", vedi anche l'ultima frase
Patrick Favre

3
android.content.pmdefinisce già PERMISSION_GRANTED = 0e PERMISSION_DENIED = -1. Forse impostato BLOCKED_OR_NEVER_ASKED = PERMISSION_DENIED - 1o qualcosa del genere?
Samis,

Vedi la risposta di mVck di seguito per gestire l'avvertenza.
Samis,

28

Una volta che l'utente ha contrassegnato "Non fare più domande", la domanda non può più essere visualizzata. Ma può essere spiegato all'utente che ha precedentemente negato l'autorizzazione e deve concedere l'autorizzazione nelle impostazioni. E riferiscilo alle impostazioni, con il seguente codice:

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

nella migrazione ad androidX puoi sostituire android.support.design.R con com.google.android.material.R
Ridha Rezzag il

26

Può essere utile per qualcuno: -

Quello che ho notato è che, se controlliamo il flag shouldShowRequestPermissionRationale () nel metodo di callback onRequestPermissionsResult (), mostra solo due stati .

Stato 1: -Ritorna vero: - Ogni volta che l'utente fa clic su Nega autorizzazioni (inclusa la prima volta).

Stato 2: -Ritorna falso: - se l'utente seleziona "non chiede più".

Link di esempio di lavoro dettagliato


2
Questo è il modo corretto per rilevare se l'utente ha selezionato l'opzione non chiedere più.
Muhammad Babar,

Ah, la chiave qui è che lo gestisci nel onRequestPermissionsResult, non quando effettivamente richiedi l'autorizzazione.
Joshua Pinter

26

È possibile determinarlo controllando se la logica di autorizzazione deve essere mostrata all'interno del onRequestPermissionsResult()metodo di callback. E se trovi un'autorizzazione impostata per non chiedere mai più , puoi richiedere agli utenti di concedere le autorizzazioni dalle impostazioni.

La mia piena implementazione sarebbe come di seguito. Funziona con richieste di autorizzazione singole o multiple . Utilizzare quanto segue o utilizzare direttamente la mia libreria.

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

hii @nabin il mio requisito è quando faccio clic sul pulsante di download (che scarica il file pdf) che il tempo deve controllare che l'autorizzazione di scrittura sia consentita o negata, quindi come usare questo codice! puoi guidarmi per favore
Rucha Bhatt Joshi il

ciao @RuchaBhatt Dai un'occhiata alla mia biblioteca. github.com/nabinbhandari/Android-Permissions
Nabin Bhandari

15

Se si desidera rilevare tutti gli "stati" (negato per la prima volta, appena negato, appena negato con "Non chiedere più" o negato in modo permanente) è possibile effettuare le seguenti operazioni:

Crea 2 booleani

private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;

Impostare il primo prima di chiedere l'autorizzazione:

beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Imposta la seconda nel tuo metodo onRequestPermissionsResult:

afterClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Utilizzare la seguente "tabella" per fare tutto il necessario in onRequestPermissionsResult () (dopo aver verificato che non si dispone ancora dell'autorizzazione):

// 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

Non ha senso controllare il mustShowRequestPermissionRationale prima di chiamare requestPermissions a meno che non si desideri mostrare la logica prima di richiedere l'autorizzazione. Mostrare la logica solo dopo che l'utente ha negato l'autorizzazione sembra essere il modo in cui la maggior parte delle app la gestisce al giorno d'oggi.
Emanuel Moecklin,

2
@EmanuelMoecklin, per quanto ne so è l'unico modo per verificare se è già stato negato (controllandolo prima e dopo, come spiegato nella mia tabella di verità) o se è una prima volta negare (nel mio caso reindirizzo l'utente a le impostazioni dell'app se viene negato in modo permanente)
mVck

1
// TRUE FALSEsi verifica anche quando l'utente consente un'autorizzazione dopo averlo precedentemente negato.
Samis,

11

Ho avuto lo stesso problema e l'ho capito. Per rendere la vita molto più semplice, ho scritto una classe util per gestire le autorizzazioni di runtime.

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

E i metodi PreferenceUtil sono i seguenti.

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

Ora, tutto ciò che serve è usare il metodo * checkPermission * con argomenti adeguati.

Ecco un esempio,

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

come fa la mia app a sapere se l'utente ha selezionato "Non chiedere più"?

Se l'utente ha selezionato Non chiedere mai più , riceverai la richiamata su onPermissionDisabled .

Buona programmazione :)


shouldShowRequestPermissionRationale ho ricevuto un errore qui, puoi aiutarmi.
Rucha Bhatt Joshi,

non riesco a trovare questo metodo dovrebbeShowRequestPermissionRationale potrebbe non essere riuscito a ottenere il contesto .. ma va bene ho trovato un'altra soluzione alternativa .. Grazie per l'aiuto :)
Rucha Bhatt Joshi

1
Colpa mia. shouldShowRequestPermissionRationale è disponibile tramite Attività, non contesto. Ho aggiornato la mia risposta trasmettendo il contesto ad Activity prima di chiamare quel metodo.
Dai

1
Questo è l'unico modo per aggirare il primo falso valore restituito shouldShowRequestPermissionRationale, salvando in preferenza la richiesta inviata all'utente. Ho avuto la stessa idea e ho trovato la tua risposta. Bel lavoro uomo
MatPag

4

Spiegazione completa per ogni caso di autorizzazione

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

    }
}

4

Una funzione utile per determinare se un'autorizzazione arbitraria è stata bloccata dalla richiesta (in 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
}

L'uso di questo richiede l'impostazione di una preferenza condivisa booleana con il nome dell'autorizzazione desiderata (ad es. android.Manifest.permission.READ_PHONE_STATE) trueAlla prima richiesta di autorizzazione.


Spiegazione:

Build.VERSION.SDK_INT >= Build.VERSION_CODES.M poiché parte del codice può essere eseguito solo a livello di API 23+.

ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED per verificare che non abbiamo già il permesso.

!activity.shouldShowRequestPermissionRationale(permission)per verificare se l'utente ha negato di nuovo la richiesta dell'app. A causa di stranezze di questa funzione , è richiesta anche la seguente riga.

PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false) questo viene utilizzato (insieme all'impostazione del valore su true alla prima richiesta di autorizzazione) per distinguere tra gli stati "Mai chiesto" e "Non chiedere più", poiché la riga precedente non restituisce queste informazioni.


4

Il metodo shouldShowRequestPermissionRationale () può essere utilizzato per verificare se l'utente ha selezionato l'opzione "mai più richiesta" e ha negato l'autorizzazione. Ci sono molti esempi di codice, quindi preferirei spiegare come usarlo per tale scopo, perché penso che il suo nome e la sua implementazione rendano questo più complicato di quanto non sia in realtà.

Come spiegato in Richiesta di autorizzazioni in fase di esecuzione , tale metodo restituisce true se l'opzione "non chiedere più" è visibile, false in caso contrario; quindi restituisce false la prima volta che viene visualizzata una finestra di dialogo, quindi dalla seconda volta restituisce true e solo se l'utente nega l'autorizzazione selezionando l'opzione, a quel punto restituisce nuovamente false.

Per rilevare un caso del genere, è possibile rilevare la sequenza false-true-false o (più semplice) è possibile avere un flag che tenga traccia del tempo iniziale in cui viene mostrata la finestra di dialogo. Dopodiché, quel metodo restituisce vero o falso, dove il falso ti permetterà di rilevare quando l'opzione è selezionata.


3

Per favore, non lanciarmi pietre per questa soluzione.

Funziona ma è un po '"confuso".

Quando chiami requestPermissions, registra l'ora corrente.

        mAskedPermissionTime = System.currentTimeMillis();

Quindi dentro onRequestPermissionsResult

se il risultato non viene concesso, controllare di nuovo l'ora.

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

Dal momento che l'utente non ha potuto fare clic così velocemente sul pulsante nega, sappiamo che ha selezionato "non chiedere più" perché il callback è istantaneo.

Utilizzare a proprio rischio.


cosa succede se vediamo quella finestra di dialogo richiesta per 5 minuti e poi neghiamo?
saksham,

Allora a che serve questo se non è in grado di soddisfare i requisiti di base. Un codice può essere un hack come accettato se soddisfa chiaramente tutti i requisiti in ogni caso, altrimenti.
saksham,

Sì, questo è male. Tester automatici come questo potrebbero forse fare clic più velocemente di quello: developer.android.com/training/testing/crawler
stackzebra

2

Ho scritto una scorciatoia per la richiesta di autorizzazione in Android M. Questo codice gestisce anche la compatibilità con le versioni precedenti di Android.

Tutto il brutto codice viene estratto in un frammento che si attacca e si stacca dall'attività richiedendo i permessi. Puoi usare PermissionRequestManagercome segue:

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

Dai un'occhiata: https://gist.github.com/crysxd/385b57d74045a8bd67c4110c34ab74aa


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

2

Prova questa semplice libreria di autorizzazioni. Gestirà tutte le operazioni relative all'autorizzazione in 3 semplici passaggi. Mi ha risparmiato tempo. Puoi completare tutti i lavori relativi alle autorizzazioni in 15 minuti .

Può gestire Nega, Può gestire Non chiedere mai più, Può chiamare le impostazioni dell'app per l'autorizzazione, Può dare un messaggio Razionale, Può dare un messaggio Nega, Può dare un elenco di autorizzazioni accettate, Può dare un elenco di negato permessi e ecc.

https://github.com/ParkSangGwon/TedPermission

Passaggio 1: aggiungi la tua dipendenza

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

Passaggio 2: chiedere autorizzazioni

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

Passaggio 3: gestire la risposta dell'autorizzazione

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

Grande. Mi ha salvato il tempo
Vigneswaran,

Bello, facile da usare
Uray Febri

2

puoi ascoltare abbastanza.

Ascoltatore

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

MainClass per autorizzazione

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

    }
}

Usato in questo modo

      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 in activity o 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

Riceverai invece la richiamata onRequestPermissionsResult()come PERMISSION_DENIED quando richiedi di nuovo l'autorizzazione mentre cadi in una falsa condizione dishouldShowRequestPermissionRationale()

Dal documento Android:

Quando il sistema chiede all'utente di concedere un'autorizzazione, l'utente ha la possibilità di dire al sistema di non richiedere nuovamente tale autorizzazione. In tal caso, ogni volta che un'app utilizza requestPermissions()per richiedere nuovamente tale autorizzazione, il sistema rifiuta immediatamente la richiesta. Il sistema chiama il onRequestPermissionsResult()metodo di callback e passa PERMISSION_DENIED, come farebbe se l'utente avesse rifiutato esplicitamente di nuovo la richiesta. Ciò significa che quando chiami requestPermissions(), non puoi presumere che abbia avuto luogo un'interazione diretta con l'utente.


1

È possibile utilizzare il if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)metodo per rilevare se non è mai stato verificato o meno il controllo.

Per ulteriori riferimenti: controllare questo

Per verificare più autorizzazioni utilizzare:

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

Spiega il metodo

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

Il codice sopra mostrerà anche la finestra di dialogo, che reindirizzerà l'utente alla schermata delle impostazioni dell'app da cui può dare l'autorizzazione se avesse controllato non chiedere più il pulsante.


1

Puoi usare

shouldShowRequestPermissionRationale()

dentro

onRequestPermissionsResult()

Vedi l'esempio seguente:

Verifica se dispone dell'autorizzazione quando l'utente fa clic sul pulsante:

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

Quando l'utente risponde alla finestra di dialogo delle autorizzazioni, andremo su 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();
            }
        }
    }

}

0

Vorrei anche ottenere le informazioni indipendentemente dal fatto che l'utente abbia o meno selezionato "non chiedere più". Ho raggiunto una "soluzione quasi" con una brutta bandiera, ma prima di dirti come, ti parlerò della mia motivazione:

Vorrei offrire inizialmente l'autorizzazione facendo riferimento alla funzionalità. Se l'utente lo utilizza e non ha diritti, ottiene la prima finestra di dialogo dall'alto o la seconda e la terza. Quando l'utente ha scelto "Non chiedere più", desidero disabilitare la funzionalità e visualizzarla in modo diverso. - La mia azione è innescata da una voce di testo del filatore, vorrei anche aggiungere "(autorizzazione revocata)" al testo dell'etichetta visualizzato. Questo mostra all'utente: "C'è funzionalità ma non posso usarla, a causa delle mie impostazioni di autorizzazione". Tuttavia, ciò non sembra possibile, poiché non posso verificare se è stato scelto o meno "Non chiedere più".

Sono arrivato a una soluzione con cui posso vivere avendo la mia funzionalità sempre abilitata con un controllo delle autorizzazioni attivo. Sto mostrando un messaggio Toast in onRequestPermissionsResult () in caso di una risposta negativa, ma solo se non ho mostrato il mio popup di logica personalizzata. Pertanto, se l'utente ha scelto "Non chiedere più", riceve solo un messaggio di brindisi. Se l'utente è riluttante a scegliere "non chiedere mai più", ottiene solo la logica personalizzata e il pop-up della richiesta di autorizzazione dal sistema operativo, ma non brinda, poiché tre notifiche di fila sarebbero troppo dolorose.


0

Devo implementare un'autorizzazione dinamica per la fotocamera. Dove si verificano 3 casi possibili: 1. Consenti, 2. Negato, 3. Non chiedere più.

 @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

Espandendo la risposta di mVck sopra, la seguente logica determina se "Non chiedere più" è stato verificato per una determinata richiesta di autorizzazione:

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

che viene estratto dal basso (per l'esempio completo vedere questa risposta )

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

Per rispondere esattamente alla domanda, cosa succede quando l'utente preme "Non chiedere più"?

Il metodo / funzione sovrascritti

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

L'array grantResult risulta essere vuoto, quindi puoi fare qualcosa lì forse? Ma non è la migliore pratica.

Come gestire "Non chiedere più"?

Sto lavorando con Fragment, che ha richiesto l'autorizzazione 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()

            }
        }
    }

Le altre funzioni sono banali.

// 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)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.