Autorizzazioni Android M: confuse sull'uso della funzione shouldShowRequestPermissionRationale ()


148

Stavo esaminando il documento ufficiale sul nuovo modello di autorizzazioni in Android M. Parla della shouldShowRequestPermissionRationale()funzione che ritorna truese l'app ha richiesto questa autorizzazione in precedenza e l'utente ha negato la richiesta. Se l'utente ha rifiutato la richiesta di autorizzazione in passato e ha scelto l'opzione Non chiedere più, questo metodo restituisce false.

Ma come possiamo distinguere tra i seguenti due casi?

Caso 1 : l'app non dispone di un'autorizzazione e all'utente non è stata richiesta l'autorizzazione prima. In questo caso, shouldShowRequestPermissionRationale () restituirà false perché è la prima volta che chiediamo all'utente.

Caso 2 : L'utente ha negato l'autorizzazione e selezionato "Non chiedere più", anche in questo caso dovrebbeShowRequestPermissionRationale () restituirà false.

Vorrei inviare l'utente alla pagina delle impostazioni dell'app nel caso 2. Come posso differenziare questi due casi?


1
La risposta accettata è buona. In alternativa, puoi anche utilizzare un pref condiviso per sapere se l'app ha già richiesto l'autorizzazione. Basta buttarlo là fuori nel caso sia più applicabile per la situazione di qualcun altro.
Rockin4Life33

4
C'è anche un caso 3: all'utente è stato chiesto e concesso / negato il permesso, ma ha usato le impostazioni del permesso per tornare a "chiedere ogni volta". Il test mostra che shouldShowRequestPermissionRationale()in questo caso restituisce false, il che danneggerà qualsiasi codice basato su un flag "ho chiesto prima".
Pickup Logan,

ecco un esempio di Google che mostra le migliori pratiche su permissionssu Android. github.com/android/permissions-samples
itabdullah

@itabdullah Il codice di esempio di Google è inutile dal momento che non ha nemmeno considerato il caso molto probabile di "l'utente ha negato l'autorizzazione l'ultima volta". : - / tipico
Someone Somewhere

Risposte:


172

Dopo l'anteprima M 1, se la finestra di dialogo viene visualizzata per la prima volta , non è presente alcuna casella di controllo Non chiedere più .

Se l'utente rifiuta la richiesta di autorizzazione, ci sarà una casella di controllo Non chiedere più nella finestra di dialogo dell'autorizzazione la seconda volta che viene richiesta l'autorizzazione.

Quindi la logica dovrebbe essere così:

  1. Richiesta di permesso:

    if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
    } else {
        //Do the stuff that requires permission...
    }
  2. Verifica se l'autorizzazione è stata negata o concessa in onRequestPermissionsResult.

    Se l'autorizzazione è stata negata in precedenza, questa volta ci sarà una casella di controllo Non chiedere più nella finestra di dialogo delle autorizzazioni.

    Chiama shouldShowRequestPermissionRationaleper vedere se l'utente ha selezionato Non chiedere più . shouldShowRequestPermissionRationaleIl metodo restituisce false solo se l'utente ha selezionato Non chiedere più o se i criteri del dispositivo vietano all'app di disporre di tale autorizzazione:

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

Quindi, non dovrai tracciare se un utente ha selezionato Non chiedere più o meno.


49
Un punto di chiarimento, shouldShowRequestPermissionRationale () restituirà anche false se l'utente non è mai stato invitato a chiedere l'autorizzazione (ovvero la prima volta che l'applicazione viene eseguita). Non ti imbatteresti in quel caso se seguissi la logica dell'esempio fornito. Ma la formulazione, sotto 2 è un po 'fuorviante.
Ben

15
Non sono sicuro, questo sembra imperfetto. Come possiamo sapere se è la prima volta che viene chiesto all'utente? Devo tracciare se l'utente è stato chiesto, e se lo ha fatto, allora devo invertire la logica. Non ha alcun senso per me.
Daniel F,

4
Penso che vale la pena notare che, quando si passa contextnel ActivityCompat.shouldShowRequestPermissionRationale(...)parametro è in realtà di tipo Activity. Potrebbe non interessarti tutti, ma nel mio caso lo fa.
aProperFox,

7
Questa logica androide è così maledettamente stupida! Mi FORZA di richiamare il shouldcallback E salvare il suo controvalore in NVM solo per sapere se devo richiedere nuovamente la richiesta alla successiva apertura dell'app! ... wow (facepalm) ... è stato troppo difficile effettuare una sola chiamata restituendo un elenco di status ??
Shockwaver,

2
Penso che questo sia un grosso fallimento di Google. Gli stati di documentazione ufficiale che lo shouldShowRequestPermissionRationale () dovrebbe essere chiamato prima di controllare i permessi (vedi developer.android.com/training/permissions/requesting#explain ), ma tutte le risposte a StackOverflow chiamano in onRequestPermissionResult () al fine di distinguere se il l'utente ha fatto clic su "Non chiedere più" o no.
Miloš Černilovský

22

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 è utilizzare il metodo checkPermission con argomenti appropriati.

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

Caso 1: l'app non dispone di un'autorizzazione e all'utente non è stata richiesta l'autorizzazione prima. In questo caso, shouldShowRequestPermissionRationale () restituirà false perché è la prima volta che chiediamo all'utente.

Caso 2: L'utente ha negato l'autorizzazione e selezionato "Non chiedere più", anche in questo caso dovrebbeShowRequestPermissionRationale () restituirà false.

Vorrei inviare l'utente alla pagina delle impostazioni dell'app nel caso 2. Come posso differenziare questi due casi?

Riceverai la richiamata su onPermissionAsk per il caso 1 e onPermissionDisabled per il caso 2.

Buona programmazione :)


Ottima spiegazione fratello. Seguito la stessa identica procedura. :)
Sumit Jha,

Cosa devo compilare per thisActivity? public void onPermissionAsk() { ActivityCompat.requestPermissions( thisActivity, ... .
Mardymar,

@Mardymar thisActivitynon è altro che YourActivity.this.
muthuraj,

1
come gestire più autorizzazioni e come integrare questo codice all'interno del frammento.
Taimur,

Che tipo di contextstai usando? shouldShowRequestPermissionRationale(permission)non esiste in android.content.Context. è in ActivityCompat
Hilikus il

9

AGGIORNARE

Credo che la risposta di CanC qui sotto sia quella corretta che dovrebbe essere seguita. L'unico modo per saperlo con certezza è verificarlo nel callback onRequestPermissionResult usando shouldShowPermissionRationale.

==

La mia risposta originale:

L'unico modo che ho trovato è di tenere traccia da solo se questa è la prima volta o meno (ad esempio utilizzando le preferenze condivise). Se non è la prima volta, utilizzare shouldShowRequestPermissionRationale()per differenziare.

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


1
Sì, sono anche d'accordo sul fatto che il metodo CanC è quello che dovrebbe essere seguito. Lo segnerò come risposta accettata.
akshayt23,

6

Per come lo capisco, shouldShowRequestPermissionRationale () esegue una serie di casi d'uso sotto il cofano e notifica all'app se mostrare o meno una spiegazione delle autorizzazioni richieste.

L'idea alla base delle autorizzazioni di runtime è che la maggior parte delle volte l'utente dirà Sì alla richiesta di autorizzazione. In questo modo l'utente dovrà fare solo un clic. Ovviamente la richiesta dovrebbe essere utilizzata nel contesto corretto, ovvero richiedere l'autorizzazione della fotocamera quando si preme il pulsante "Camera".

Se l'utente rifiuta la richiesta, ma dopo qualche tempo arriva e preme di nuovo il pulsante "Camera", shouldShowRequestPermissionRationale () restituirà true, quindi l'app può mostrare alcune spiegazioni significative sul motivo per cui è richiesta l'autorizzazione e perché l'app non lo farà funziona correttamente senza di essa. Normalmente in quella finestra di dialogo mostreresti un pulsante per negare di nuovo / decidere in seguito, e un pulsante per concedere le autorizzazioni. Il pulsante delle autorizzazioni di concessione nella finestra di dialogo logica dovrebbe riavviare la richiesta di autorizzazione. Questa volta l'utente avrà anche una casella di controllo "Non mostrare più". Se dovesse decidere di selezionarlo e negare nuovamente l'autorizzazione, notificherebbe al sistema Android che l'utente e l'app non si trovano sulla stessa pagina. Tale azione avrebbe due conseguenze: shouldShowRequestPermissionRationale () restituirà sempre false,

Ma esiste anche un altro possibile scenario in cui onRequestPermissionsResult potrebbe essere utilizzato. Ad esempio, alcuni dispositivi potrebbero avere una politica dei dispositivi che disabilita la videocamera (funzionante per CIA, DARPA, ecc.). Su questi dispositivi, onRequestPermissionsResult restituirà sempre false e il metodo requestPermissions () rifiuterà silenziosamente la richiesta.

È quello che ho raccolto ascoltando il podcast con Ben Poiesz, un product manager nel framework Android.
http://androidbackstage.blogspot.jp/2015/08/episode-33-permission-mission.html


6

Basta pubblicare un'altra opzione, se qualcuno può sentirsi come. Puoi utilizzare EasyPermissions fornito da Google stesso per, come detto, "Semplificare le autorizzazioni del sistema Android M".

Quindi non devi gestire shouldShowRequestPermissionRationaledirettamente.


perché non ho visto prima questo progetto :)
Vlad

Il problema con EasyPermissions rimane quasi lo stesso. Chiedere permissionPermanentlyDeniedinternamente solo chiamate shouldShowPermissionsRationalee ritorna truenel caso in cui l'utente non è mai stato invitato a concedere le autorizzazioni.
hgoebl,

4

Se qualcuno è interessato a una soluzione Kotlin, ho riformulato la risposta di @muthuraj per essere a Kotlin. Anche modernizzato un po 'per avere un blocco di completamento anziché ascoltatori.

PermissionUtil

object PermissionUtil {
    private val PREFS_FILE_NAME = "preference"

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

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

PermissionHandler

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

typealias PermissionCheckCompletion = (CheckPermissionResult) -> Unit


object PermissionHandler {

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

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

Implementazione

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

3

Controlla questa implementazione. funziona abbastanza bene per me. fondamentalmente controlli le autorizzazioni nel metodo checkPermissions () passando un elenco di autorizzazioni. Si controlla il risultato della richiesta di autorizzazione su onRequestPermissionsResult (). L'implementazione consente di affrontare entrambi i casi quando l'utente seleziona "non chiedere più" o meno. In questa implementazione, nel caso in cui selezioni "non chiedere più", la finestra di dialogo ha un'opzione per portarlo all'attività Impostazioni app.

Tutto questo codice è nel mio frammento. Stavo pensando che sarebbe meglio creare una classe specializzata per fare questo, come un PermissionManager, ma non ne sono sicuro.

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

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

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

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

2

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 per un esempio di lavoro dettagliato .


6
restituisce false per la prima volta. non è vero
JoM

Sì, è quello che ho menzionato, se si controlla il flag nel metodo di callback onRequestPermissionsResult (), avrà solo due stati, in particolare in questo callback.
Nicks

2
Sfortunatamente, shouldShowRequestPermissionRationale restituisce sempre false, indipendentemente dal fatto che l'utente abbia mai negato l'autorizzazione o meno.
IgorGanapolsky,

1

Possiamo farlo in questo modo?

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

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

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

Sfortunatamente, questo codice non distingue tra una situazione in cui l'autorizzazione non è mai stata richiesta prima e dove è stato verificato "mai più richiesta".
Ben

dovresti usare la combinazione di questo + la classe helper per l'autorizzazione per verificare se l'autorizzazione è concessa o meno.
Dr. aNdRO,

0

shouldShowRequestPermissionRationale per l'autorizzazione SPECIALE restituisci sempre VERO SOLO dopo che l'utente lo ha negato senza casella di controllo

Siamo interessati al valore FALSO

Quindi ci sono 3 casi persi con valore falso :

1. non vi era alcuna azione di questo tipo in precedenza e ora l'utente decide di accettare o negare.

Definisci semplicemente una preferenza ASKED_PERMISSION_*che non esiste ora e che sarebbe vera nel onRequestPermissionsResultsuo inizio in ogni caso di essere d'accordo o negare

Quindi, sebbene questa preferenza non esista, non c'è motivo di verificareshouldShowRequestPermissionRationale

2. l' utente ha cliccato d'accordo.

Fai semplicemente:

checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED

Che tornerà vero e non c'è motivo di verificareshouldShowRequestPermissionRationale

3. utente cliccato nega con casella di controllo (richiesto il secondo o più tempo)

E ' IL TEMPO di lavorare con shouldShowRequestPermissionRationaleche restituirà FALSE

(la preferenza esiste e non abbiamo un permesso)


0

Questo codice chiede all'utente di chiedere l'autorizzazione durante il runtime, se l'utente lo consente, esegue il metodo del risultato, se l'utente nega, lo chiede di nuovo con discription con l'utente nega (chiede di nuovo con le istruzioni), ma se l'utente sceglie di non chiedere mai più. gestisce mai più chiedere, visualizzare l'opzione di impostazioni aperte con le istruzioni.

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

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

    setContentView(R.layout.activity_main);

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

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

}

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

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


private void result(){
          //your code
}

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


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

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