Uprawnienia systemu Android M: zdezorientowany użyciem funkcji shouldShowRequestPermissionRationale ()

148

Przeglądałem oficjalny dokument dotyczący nowego modelu uprawnień w systemie Android M. Mówi on o shouldShowRequestPermissionRationale()funkcji, która zwraca, truejeśli aplikacja zażądała wcześniej tego uprawnienia, a użytkownik odmówił. Jeśli użytkownik odrzucił prośbę o pozwolenie w przeszłości i wybrał opcję Nie pytaj ponownie, ta metoda zwraca false.

Ale jak możemy rozróżnić następujące dwa przypadki?

Przypadek 1 : Aplikacja nie ma uprawnień, a użytkownik nie był wcześniej pytany o zgodę. W tym przypadku shouldShowRequestPermissionRationale () zwróci wartość false, ponieważ jest to pierwsze pytanie użytkownika.

Przypadek 2 : Użytkownik odmówił pozwolenia i wybrał „Nie pytaj ponownie”, w tym przypadku również polecenieShowRequestPermissionRationale () zwróci false.

Chciałbym odesłać użytkownika do strony ustawień aplikacji w przypadku 2. Jak mam się zabrać do rozróżnienia tych dwóch przypadków?

akshayt23
źródło
1
Przyjęta odpowiedź jest dobra. Alternatywnie możesz również użyć udostępnionego pref, aby dowiedzieć się, czy aplikacja wcześniej poprosiła o pozwolenie. Po prostu wyrzucam to tam na wypadek, gdyby było to bardziej odpowiednie dla sytuacji innej osoby.
Rockin4Life33
4
Istnieje również przypadek 3: użytkownik został poproszony o pozwolenie i udzielił mu / odmówiono mu pozwolenia, ale użył ustawień uprawnień, aby powrócić do „pytaj za każdym razem”. Testowanie pokazuje, że shouldShowRequestPermissionRationale()w tym przypadku zwraca fałsz, co zaszkodzi każdemu kodowi opartemu na flagi „czy pytałem wcześniej”.
Logan Pickup
oto przykład google przedstawiający sprawdzone metody w permissionssystemie Android. github.com/android/permissions-samples
itabdullah
@itabdullah Przykładowy kod Google jest bezużyteczny, ponieważ nawet nie wzięli pod uwagę bardzo prawdopodobnego przypadku użycia „czy użytkownik ostatnio odmówił pozwolenia”. : - / typowe
Ktoś Gdzieś

Odpowiedzi:

172

Po M Podgląd 1, jeśli okno dialogowe jest wyświetlane po raz pierwszy , nie ma pola wyboru Nigdy więcej nie pytaj .

Jeśli użytkownik odrzuci prośbę o pozwolenie, w oknie dialogowym uprawnień pojawi się pole wyboru Nigdy nie pytaj ponownie, gdy po raz drugi zostanie zażądany pozwolenie.

Więc logika powinna wyglądać następująco:

  1. Prośba o pozwolenie:

    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. Sprawdź, czy zezwolenie zostało odrzucone lub udzielone w onRequestPermissionsResult.

    Jeśli wcześniej odmówiono pozwolenia, tym razem w oknie dialogowym uprawnień pojawi się pole wyboru Nigdy nie pytaj ponownie .

    Zadzwoń, shouldShowRequestPermissionRationaleaby sprawdzić, czy użytkownik zaznaczył Nigdy nie pytaj ponownie . shouldShowRequestPermissionRationalemetoda zwraca wartość false tylko wtedy, gdy użytkownik wybrał opcję Nigdy nie pytaj ponownie lub zasady dotyczące urządzeń zabraniają aplikacji posiadania tego uprawnienia:

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

Nie musisz więc śledzić, czy użytkownik zaznaczył Nigdy więcej nie pytaj, czy nie.

CanC
źródło
49
Należy wyjaśnić, że shouldShowRequestPermissionRationale () zwróci również false, jeśli użytkownik nigdy nie był pytany o pozwolenie (tj. Przy pierwszym uruchomieniu aplikacji). Nie napotkasz tego przypadku, jeśli będziesz postępować zgodnie z logiką podanego przykładu. Ale sformułowanie poniżej 2 roku jest trochę mylące.
Ben
15
Nie jestem pewien, wydaje się to wadliwe. Skąd mamy wiedzieć, czy jest to pierwsze pytanie użytkownika? Muszę śledzić, czy użytkownik został zapytany, a jeśli tak, to muszę odwrócić logikę. Nie ma to dla mnie żadnego sensu.
Daniel F
4
Myślę, że warto zwrócić uwagę, że tam, gdzie są przechodzącą contextw ActivityCompat.shouldShowRequestPermissionRationale(...)parametrze jest rzeczywiście typu Activity. Może nie wpłynąć na was wszystkich, ale w moim przypadku tak.
aProperFox
7
Ta logika Androida jest cholernie głupia! ZMUSZA mnie do wywołania shouldwywołania zwrotnego ORAZ zapisania jej wartości przeciwnej w NVM tylko po to, aby wiedzieć, czy muszę ponownie poprosić o żądanie przy następnym uruchomieniu aplikacji! ... wow (facepalm) ... czy wykonanie tylko jednego wywołania zwracającego wyliczenie statusu było zbyt trudne?
Shockwaver,
2
Myślę, że to duża porażka Google. Oficjalna dokumentacja stwierdza, że ​​shouldShowRequestPermissionRationale () należy wywołać przed sprawdzeniem uprawnień (patrz developer.android.com/training/permissions/requesting#explain ), ale wszystkie odpowiedzi w StackOverflow wywołują ją w onRequestPermissionResult () w celu rozróżnienia, czy użytkownik kliknął „Nigdy więcej nie pytaj” lub nie.
Miloš Černilovský
22

Miałem ten sam problem i rozgryzłem go. Aby znacznie uprościć życie, napisałem klasę util do obsługi uprawnień w czasie wykonywania.

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

A metody PreferenceUtil są następujące.

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

Teraz wystarczy użyć metody checkPermission z odpowiednimi argumentami.

Oto przykład,

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

Przypadek 1: Aplikacja nie ma uprawnień, a użytkownik nie był wcześniej pytany o zgodę. W tym przypadku shouldShowRequestPermissionRationale () zwróci wartość false, ponieważ jest to pierwsze pytanie użytkownika.

Przypadek 2: Użytkownik odmówił pozwolenia i wybrał „Nie pytaj ponownie”, w tym przypadku również polecenieShowRequestPermissionRationale () zwróci false.

Chciałbym odesłać użytkownika do strony ustawień aplikacji w przypadku 2. Jak mam się zabrać do rozróżnienia tych dwóch przypadków?

Otrzymasz oddzwonienie onPermissionAsk dla przypadku 1 i onPermissionDisabled dla przypadku 2.

Miłego kodowania :)

muthuraj
źródło
Doskonałe wyjaśnienie, stary. Wykonałem dokładnie tę samą procedurę. :)
Sumit Jha
Co mam wypełnić dla tej czynności? public void onPermissionAsk() { ActivityCompat.requestPermissions( thisActivity, ... .
Mardymar
@Mardymar thisActivityto nic innego YourActivity.this.
muthuraj
1
jak obsługiwać wiele uprawnień i jak zintegrować ten kod wewnątrz fragmentu.
Taimur
Jakiego rodzaju contextużywasz? shouldShowRequestPermissionRationale(permission)nie istnieje w android.content.Context. jest w ActivityCompat
Hilikus
8

AKTUALIZACJA

Uważam, że poniższa odpowiedź CanC jest właściwa, której należy przestrzegać. Jedynym sposobem, aby się upewnić, jest zweryfikowanie tego w wywołaniu zwrotnym onRequestPermissionResult przy użyciu metody shouldShowPermissionRationale.

==

Moja pierwotna odpowiedź:

Jedynym sposobem, który znalazłem, jest samodzielne śledzenie, czy jest to pierwszy raz, czy nie (np. Przy użyciu wspólnych preferencji). Jeśli to nie pierwszy raz, użyj shouldShowRequestPermissionRationale()do rozróżnienia.

Zobacz też: Android M - sprawdź uprawnienia runtime - jak sprawdzić, czy użytkownik zaznaczył „Nigdy więcej nie pytaj”?

Alex Florescu
źródło
1
Tak, nawet ja zgadzam się, że metoda CanC jest tą, której należy przestrzegać. Oznaczę to jako zaakceptowaną odpowiedź.
akshayt23
6

Tak jak rozumiem, shouldShowRequestPermissionRationale () uruchamia szereg przypadków użycia pod maską i powiadamia aplikację, czy wyświetlić wyjaśnienie dotyczące żądanych uprawnień.

Ideą uprawnień Run Time jest to, że przez większość czasu użytkownik powie „Tak” prośbie o pozwolenie. W ten sposób użytkownik będzie musiał wykonać tylko jedno kliknięcie. Oczywiście żądanie powinno być używane w odpowiednim kontekście - tj. Pytając o pozwolenie kamery po naciśnięciu przycisku „Kamera”.

Jeśli użytkownik odrzuci żądanie, ale po jakimś czasie nadejdzie i ponownie wciśnie przycisk „Aparat”, funkcja shouldShowRequestPermissionRationale () zwróci wartość „prawda”, więc aplikacja może wyświetlić sensowne wyjaśnienie, dlaczego żąda się pozwolenia, a dlaczego nie. działają poprawnie bez niego. Zwykle w tym oknie dialogowym pojawia się przycisk, aby ponownie odmówić / zdecydować później, oraz przycisk, aby udzielić uprawnień. Przycisk przyznania uprawnień w oknie dialogowym uzasadnienia powinien ponownie uruchomić prośbę o pozwolenie. Tym razem użytkownik będzie miał również pole wyboru „Nigdy więcej nie pokazuj”. Jeśli zdecyduje się go wybrać i ponownie odmówi pozwolenia, powiadomi system Android, że użytkownik i aplikacja nie znajdują się na tej samej stronie. Ta akcja miałaby dwie konsekwencje - shouldShowRequestPermissionRationale () zawsze zwróci false,

Ale jest też inny możliwy scenariusz, w którym można by użyć onRequestPermissionsResult. Na przykład niektóre urządzenia mogą mieć zasady dotyczące urządzeń, które wyłączają kamerę (działa dla CIA, DARPA itp.). Na tych urządzeniach onRequestPermissionsResult zawsze zwróci wartość false, a metoda requestPermissions () dyskretnie odrzuci żądanie.

Właśnie to zebrałem, słuchając podcastu z Benem Poieszem - menedżerem produktu na platformie Android.
http://androidbackstage.blogspot.jp/2015/08/episode-33-permission-mission.html

Shumoapp
źródło
6

Po prostu opublikuj inną opcję, jeśli ktoś ma na to ochotę. Możesz użyć EasyPermissions, które zostało dostarczone przez samą Google, aby, jak powiedziano, „uprościć uprawnienia systemu Android M”.

Wtedy nie musisz zajmować się shouldShowRequestPermissionRationalebezpośrednio.

Wei WANG
źródło
dlaczego wcześniej nie widziałem tego projektu :)
Vlad
Problem z EasyPermissions pozostaje prawie taki sam. Pytanie permissionPermanentlyDeniedwewnętrzne tylko wywołuje shouldShowPermissionsRationalei zwraca truew przypadku, gdy użytkownik nigdy nie był proszony o przyznanie uprawnień.
hgoebl
4

Jeśli ktoś jest zainteresowany rozwiązaniem Kotlin, refaktoryzowałem odpowiedź @muthuraj, aby być w Kotlinie. Zmodernizowano go również nieco, aby zamiast słuchaczy miał blok uzupełniania.

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

Realizacja

PermissionHandler.checkPermission(activity,
                    Manifest.permission.CAMERA) { result ->
                when (result) {
                    CheckPermissionResult.PermissionGranted -> {
                        // openCamera()
                    }
                    CheckPermissionResult.PermissionDisabled -> {
                        // displayAlert(noPermissionAlert)
                    }
                    CheckPermissionResult.PermissionAsk -> {
                        // requestCameraPermissions()
                    }
                    CheckPermissionResult.PermissionPreviouslyDenied -> {
                        // displayAlert(permissionRequestAlert)
                    }
                }
            }
bmjohns
źródło
3

Sprawdź tę implementację. działa dla mnie całkiem nieźle. po prostu sprawdzasz uprawnienia w metodzie checkPermissions () przekazując listę uprawnień. Sprawdzasz wynik żądania uprawnień w onRequestPermissionsResult (). Implementacja pozwala ująć oba przypadki, gdy użytkownik wybierze „nigdy więcej nie pytaj” lub nie. W tej implementacji, jeśli se wybierze „nigdy więcej nie pytaj”, w oknie dialogowym pojawi się opcja przeniesienia go do działania ustawień aplikacji.

Cały ten kod znajduje się w moim fragmencie. Pomyślałem, że lepiej byłoby utworzyć wyspecjalizowaną klasę do tego celu, na przykład PermissionManager, ale nie jestem tego pewien.

/**
     * 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);
    }
Thiago Saraiva
źródło
2

Może być przydatny dla kogoś: -

Zauważyłem, że jeśli sprawdzimy flagę shouldShowRequestPermissionRationale () w metodzie wywołania zwrotnego onRequestPermissionsResult (), to pokazuje tylko dwa stany.

Stan 1: -Return true: - Za każdym razem, gdy użytkownik kliknie opcję Odmów uprawnień (w tym za pierwszym razem).

Stan 2: -Zwraca fałsz: - jeśli użytkownik wybierze „nigdy więcej nie pyta”.

Link do szczegółowego przykładu roboczego .

Nicki
źródło
6
zwraca false po raz pierwszy. nieprawda
JoM
Tak, o tym wspomniałem, jeśli zaznaczysz flagę w metodzie wywołania zwrotnego onRequestPermissionsResult (), będzie ona miała tylko dwa stany, szczególnie w tym wywołaniu zwrotnym.
Nicks
2
Niestety, shouldShowRequestPermissionRationale zawsze zwraca wartość false - niezależnie od tego, czy użytkownik kiedykolwiek odmówił pozwolenia, czy nie.
Igor Ganapolsky,
1

Możemy to zrobić w ten sposób?

@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;
        }
    }
}
Dr. aNdRO
źródło
Niestety, ten kod nie rozróżnia sytuacji, w której nigdy wcześniej nie żądano pozwolenia, od sytuacji, w której zaznaczono opcję „nigdy więcej nie żądaj”.
Ben
powinieneś użyć kombinacji this + klasa pomocnika uprawnień, aby sprawdzić, czy zezwolenie zostało przyznane, czy nie.
Dr. aNdRO
0

shouldShowRequestPermissionRationale dla zezwolenia SPECJALNEGO zawsze zwracają PRAWDA TYLKO po tym, jak użytkownik odmówił tego bez pola wyboru

Interesuje nas wartość FAŁSZ

Więc są 3 przypadki utracone z fałszywą wartością:

1. wcześniej nie było takiej akcji, a teraz użytkownik decyduje się wyrazić zgodę lub odmówić.

Proszę określić preferencje ASKED_PERMISSION_*, które nie istnieją obecnie i będzie prawdą w onRequestPermissionsResultna to zacząć w każdym razie zgodzić się lub odmówić

Więc chociaż ta preferencja nie istnieje, nie ma powodu, aby to sprawdzaćshouldShowRequestPermissionRationale

2. użytkownik kliknął zgodę.

Po prostu zrób:

checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED

Która zwróci prawdę i nie ma powodu, aby to sprawdzaćshouldShowRequestPermissionRationale

3. użytkownik kliknął przycisk „odmów” za pomocą pola wyboru (pytanie o drugi lub więcej razy)

Nadszedł CZAS na pracę, z shouldShowRequestPermissionRationalektórym wróci FAŁSZ

(preferencja istnieje i nie mamy pozwolenia)

Vlad
źródło
0

Ten kod prosi użytkownika o pozwolenie w czasie wykonywania, jeśli użytkownik na to zezwala, wykonuje metodę wyniku, jeśli użytkownik odmówi, pyta ponownie z opisem z odmową użytkownika (pyta ponownie z instrukcjami), ale jeśli użytkownik wybierze, nigdy więcej nie pytaj. obsługuje nigdy nie pytaj ponownie, wyświetla opcję otwartych ustawień z instrukcjami.

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;
                }
        }
}
Abhishek Garg
źródło