Android M - Laufzeitberechtigung prüfen - Wie kann festgestellt werden, ob der Benutzer "Nie wieder fragen" aktiviert hat?

307

Demnach: http://developer.android.com/preview/features/runtime-permissions.html#coding Eine App kann nach Laufzeitberechtigungen suchen und Berechtigungen anfordern, wenn diese noch nicht erteilt wurde. Der folgende Dialog wird dann angezeigt:

Geben Sie hier die Bildbeschreibung ein

Falls der Benutzer eine wichtige Berechtigung ablehnt, sollte in einer App eine Erklärung angezeigt werden, warum die Berechtigung benötigt wird und welche Auswirkungen das Ablehnen hat. Dieser Dialog hat zwei Möglichkeiten:

  1. erneut versuchen (Erlaubnis wird erneut angefordert)
  2. verweigern (App funktioniert ohne diese Erlaubnis).

Wenn der Benutzer dies Never ask againjedoch überprüft , sollte der zweite Dialog mit der Erklärung nicht angezeigt werden, insbesondere wenn der Benutzer bereits einmal abgelehnt hat. Die Frage ist nun: Woher weiß meine App, ob der Benutzer das überprüft hat Never ask again? IMO onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)gibt mir diese Informationen nicht.

Eine zweite Frage wäre: Hat Google vor, eine benutzerdefinierte Nachricht in den Berechtigungsdialog aufzunehmen, die erklärt, warum die App die Berechtigung benötigt? Auf diese Weise würde es niemals einen zweiten Dialog geben, der sicherlich zu einem besseren UX führen würde.

Emanuel Moecklin
quelle
9
"Hat Google Pläne, eine benutzerdefinierte Nachricht in den Berechtigungsdialog aufzunehmen, die erklärt, warum die App die Berechtigung benötigt?" - In der Google I | O-Präsentation zum M-Berechtigungssystem erinnere ich mich an jemanden, der in den Fragen und Antworten gefragt wurde, und die Antwort war, dass er darüber nachdenkt.
CommonsWare
1
Ich habe es nicht selbst getestet, aber die Dokumentation sagt etwas über Activity.shouldShowRequestPermissionRationale (String): Diese Methode gibt true zurück, wenn die App diese Berechtigung zuvor angefordert hat und der Benutzer die Anforderung abgelehnt hat. Dies bedeutet, dass Sie dem Benutzer wahrscheinlich erklären sollten, warum Sie die Berechtigung benötigen. Wenn der Benutzer die Berechtigungsanforderung in der Vergangenheit abgelehnt und im Dialogfeld "Berechtigungsanforderungssystem" die Option "Nicht mehr fragen" ausgewählt hat, gibt diese Methode false zurück. Die Methode gibt auch false zurück, wenn die Geräterichtlinie der App diese Berechtigung verbietet.
Fraid
1
@Fraid: Sieht so aus, als hätten sie dies mit der Vorschau Nr. 2 von Android M hinzugefügt: developer.android.com/preview/support.html#preview2-notes und es ist wahrscheinlich das, wonach ich gesucht habe. Ich kann es momentan nicht testen, werde es aber nächste Woche tun. Wenn es das tut, was ich hoffe, können Sie es als Antwort posten und sich einen guten Ruf sichern. In der Zwischenzeit könnte dies anderen helfen: youtube.com/watch?v=f17qe9vZ8RM
Emanuel Moecklin
Beispiel für gefährliche Berechtigungen und Sonderberechtigungen: github.com/henrychuangtw/AndroidRuntimePermission
HenryChuang
1
@Alex schwieriger für Entwickler, das ist sicher, aber aus Anwendersicht ist es sinnvoll, bestimmte Berechtigungen zu erteilen oder zu verweigern. Das Hauptproblem, das ich sehe, ist, dass die Granularität der Berechtigungen sehr inkonsistent ist und Sie am Ende nach einer Berechtigung fragen, die möglicherweise fast nichts mit dem zu tun hat, was Sie in Ihrer App tun möchten (z. B. Kontaktberechtigung, wenn ich eine Verbindung herstellen möchte Google Drive, da hierfür eine Liste der Gerätekonten für Authentifizierungszwecke erforderlich ist und die Kontoberechtigung Teil der Kontaktberechtigungsgruppe ist.
Emanuel Moecklin

Antworten:

341

Die Entwicklervorschau 2 enthält einige Änderungen an der Anforderung von Berechtigungen durch die App (siehe auch http://developer.android.com/preview/support.html#preview2-notes ).

Der erste Dialog sieht nun so aus:

Geben Sie hier die Bildbeschreibung ein

Es gibt kein Kontrollkästchen "Nie wieder anzeigen" (im Gegensatz zur Entwicklervorschau 1). Wenn der Benutzer die Berechtigung verweigert und die Berechtigung für die App wesentlich ist, kann ein weiterer Dialog angezeigt werden, in dem der Grund erläutert wird, warum die App diese Berechtigung anfordert, z. B.:

Geben Sie hier die Bildbeschreibung ein

Wenn der Benutzer erneut ablehnt, sollte die App entweder heruntergefahren werden, wenn diese Berechtigung unbedingt erforderlich ist, oder mit eingeschränkter Funktionalität weiter ausgeführt werden. Wenn der Benutzer es erneut überprüft (und einen erneuten Versuch auswählt), wird die Berechtigung erneut angefordert. Diesmal sieht die Eingabeaufforderung folgendermaßen aus:

Geben Sie hier die Bildbeschreibung ein

Beim zweiten Mal wird das Kontrollkästchen "Nie wieder fragen" angezeigt. Wenn der Benutzer erneut ablehnt und das Kontrollkästchen aktiviert ist, sollte nichts mehr passieren. Ob das Kontrollkästchen aktiviert ist oder nicht, kann mithilfe von Activity.shouldShowRequestPermissionRationale (String) ermittelt werden, z. B.: Z.

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

Das steht in der Android-Dokumentation ( https://developer.android.com/training/permissions/requesting.html ):

Um die Situationen zu finden, in denen Sie zusätzliche Erklärungen benötigen, stellt das System die Activity.shouldShowRequestPermissionRationale (String) -Methode bereit. Diese Methode gibt true zurück, wenn die App diese Berechtigung zuvor angefordert hat und der Benutzer die Anforderung abgelehnt hat. Dies bedeutet, dass Sie dem Benutzer wahrscheinlich erklären sollten, warum Sie die Berechtigung benötigen.

Wenn der Benutzer die Berechtigungsanforderung in der Vergangenheit abgelehnt und im Dialogfeld "Berechtigungsanforderungssystem" die Option "Nicht erneut fragen" ausgewählt hat, gibt diese Methode false zurück. Die Methode gibt auch false zurück, wenn die Geräterichtlinie der App diese Berechtigung verbietet.

Um festzustellen , ob der Benutzer mit "Nie wieder fragen" abgelehnt hat, können Sie die Methode shouldShowRequestPermissionRationale in Ihrem onRequestPermissionsResult erneut überprüfen, wenn der Benutzer die Berechtigung nicht erteilt hat.

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

Sie können Ihre App-Einstellung mit folgendem Code öffnen:

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

Es gibt keine Möglichkeit, den Benutzer direkt zur Autorisierungsseite zu senden.

Emanuel Moecklin
quelle
30
Ich habe den Rückgabewert der Methode shouldShowRequestPermissionRationale () auf false überprüft, um zu überprüfen, ob der Benutzer "Nie wieder fragen" ausgewählt hat. Aber ich bekomme seinen Wert auch zum ersten Mal als falsch, wenn ich um Erlaubnis bitte. Daher kann ich nicht unterscheiden, ob der Benutzer das Kontrollkästchen "Nie wieder fragen" aktiviert hat oder nicht. Bitte vorschlagen??
Sagar Trehan
32
Nach meinem Verständnis gibt die Methode shouldShowRationalePermissionRationale () in drei Fällen false zurück: 1. Wenn wir diese Methode zum ersten Mal aufrufen, bevor wir um Erlaubnis bitten. 2. Wenn der Benutzer "Nicht erneut fragen" auswählt und die Berechtigung verweigert. 3. Wenn die
Geräterichtlinie
24
Alles gut ... aber wir Entwickler müssen wirklich wissen, ob der Benutzer "nie wieder fragen" sagte oder nicht. Ich habe eine nette Schaltfläche, um auf eine Funktion zuzugreifen. Das erste Mal, wenn der Benutzer klickt: Sollte er nach einer Begründung fragen? Nein, bitte um Erlaubnis. Der Benutzer verweigert. Benutzer klicken erneut auf die Schaltfläche: Begründung? ja! Zeigen Sie die Begründung, der Benutzer sagt "OK", dann lehnen Sie ab und fragen Sie nie wieder (ok, er ist ein Idiot, aber die Benutzer sind es oft). Später Benutzer erneut die Taste drücken, Begründung? Nein, bitte um Erlaubnis, nichts passiert für den Benutzer. Ich brauche dort wirklich eine Möglichkeit, dem Benutzer zu sagen: Hey Mann, wenn Sie diese Funktion möchten, gehen Sie jetzt zur App-Einstellung und geben Sie die Erlaubnis.
Daniele Segato
4
Großartig @EmanuelMoecklin das ist jetzt besser als Google Documentation: D
Daniele Segato
4
onRequestPermissionsResult wird nur aufgerufen, wenn Sie die Berechtigung anfordern. Da beim ersten Anfordern der Berechtigung kein Kontrollkästchen "Nie wieder fragen" vorhanden ist, gibt shouldShowRequestPermissionRationale True zurück (Berechtigung angefordert, ohne jedoch erneut zu fragen). Folglich wird die Begründung immer angezeigt, wenn der Benutzer die Berechtigung zum ersten Mal ablehnt, danach jedoch nur, wenn das Kontrollkästchen nicht aktiviert wurde.
Emanuel Moecklin
95

Sie können shouldShowRequestPermissionRationale()Ihre einchecken onRequestPermissionsResult().

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

Überprüfen Sie, ob die Berechtigung erteilt wurde oder nicht onRequestPermissionsResult(). Wenn nicht, dann überprüfen shouldShowRequestPermissionRationale().

  1. Wenn diese Methode zurückgegeben truewird, geben Sie eine Erklärung an, warum diese bestimmte Berechtigung erforderlich ist. Dann je nach Wahl des Benutzers wieder requestPermissions().
  2. Wenn es zurückkehrt false, wird eine Fehlermeldung angezeigt, dass die Berechtigung nicht erteilt wurde und die App nicht weiter fortfahren kann oder eine bestimmte Funktion deaktiviert ist.

Unten finden Sie einen Beispielcode.

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

Anscheinend macht Google Maps genau dies für die Standortberechtigung.

Abhinav Chauhan
quelle
Danke für das Bild und den Youtube Link. Es entspricht mehr oder weniger meiner eigenen Antwort. Es ist zu beachten, dass die Frage gestellt wurde, als nur die Entwicklervorschau 1 verfügbar war, die nicht über die Methode shouldShowRequestPermissionRationale verfügte.
Emanuel Moecklin
Ich bin neu in Android und ich möchte diese onRequestPermissionsResult () -Methode überschreiben. aber ich bekomme die Fehlermeldung, dass es eine Super-Typ-Methode implementieren muss. können Sie sagen, wie man das benutzt
Andrain
39

Hier ist eine nette und einfache Methode, um den aktuellen Berechtigungsstatus zu überprüfen:

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

Vorsichtsmaßnahme: Gibt BLOCKED_OR_NEVER_ASKED beim ersten Start der App zurück, bevor der Benutzer die Berechtigung über die Benutzeraufforderung akzeptiert / verweigert hat (auf SDK 23+ Geräten).

Aktualisieren:

Die Android-Unterstützungsbibliothek scheint nun auch eine sehr ähnliche Klasse zu haben, die eine android.support.v4.content.PermissionCheckerenthält, checkSelfPermission()die Folgendes zurückgibt:

public static final int PERMISSION_GRANTED = 0;
public static final int PERMISSION_DENIED = -1;
public static final int PERMISSION_DENIED_APP_OP = -2;
Patrick Favre
quelle
1
Beim ersten Start speichere ich einen Booleschen Wert in gemeinsamen Einstellungen.
Saeid Farivar
5
Dies wird immer zurückgegeben, BLOCKED_OR_NEVER_ASKEDwenn die Berechtigung noch nicht angefordert wurde.
Saket
6
Ja, das ist der Grund, warum es "BLOCKED_OR_NEVER_ASKED" heißt. Siehe auch den letzten Satz
Patrick Favre,
3
android.content.pmdefiniert bereits PERMISSION_GRANTED = 0und PERMISSION_DENIED = -1. Vielleicht setzen BLOCKED_OR_NEVER_ASKED = PERMISSION_DENIED - 1oder so?
Samis
Siehe MVCK ‚s Antwort unten für die Einschränkung der Handhabung.
Samis
28

Sobald der Benutzer "Nicht erneut fragen" markiert hat, kann die Frage nicht mehr angezeigt werden. Dem Benutzer kann jedoch erklärt werden, dass er zuvor die Berechtigung verweigert hat und in den Einstellungen die Berechtigung erteilen muss. Und verweisen Sie ihn mit dem folgenden Code auf die Einstellungen:

@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;
}
רותם ריכטר
quelle
Bei der Migration zu AndroidX können Sie android.support.design.R durch com.google.android.material.R ersetzen
Ridha Rezzag
26

Kann für jemanden nützlich sein: -

Was mir aufgefallen ist, ist, dass beim Aktivieren des Flags shouldShowRequestPermissionRationale () in der Rückrufmethode onRequestPermissionsResult () nur zwei Zustände angezeigt werden .

Status 1: -Return true: - Jedes Mal, wenn der Benutzer auf Verweigern von Berechtigungen klickt (einschließlich des ersten Males).

Status 2: - Gibt false zurück: - Wenn der Benutzer "Nie wieder fragen" auswählt.

Link zum detaillierten Arbeitsbeispiel

Nicks
quelle
2
Dies ist der richtige Weg, um festzustellen, ob der Benutzer die Option Nie wieder fragen ausgewählt hat.
Muhammad Babar
Ah, der Schlüssel hier ist, dass Sie dies in der behandeln onRequestPermissionsResult, nicht wenn Sie tatsächlich die Erlaubnis anfordern.
Joshua Pinter
26

Sie können bestimmen , es durch Prüfen , ob die Erlaubnis Begründung in der gezeigt werden soll , onRequestPermissionsResult()Callback - Methode. Wenn Sie einen Berechtigungssatz finden , der Sie nie wieder fragen kann, können Sie Benutzer auffordern, Berechtigungen aus den Einstellungen zu erteilen.

Meine vollständige Implementierung wäre wie folgt. Es funktioniert sowohl für Einzel- als auch für Mehrfachberechtigungsanforderungen . Verwenden Sie Folgendes oder direkt meine Bibliothek.

@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).
        }
    }
}
Nabin Bhandari
quelle
hii @nabin meine Anforderung ist, wenn ich auf den Download-Button (der die PDF-Datei herunterlädt) klicke, muss die Zeit überprüft werden, ob die Schreibberechtigung zulässig ist oder verweigert wird, um diesen Code zu verwenden! können Sie mich führen plz
Rucha Bhatt Joshi
hallo @RuchaBhatt Schau dir meine Bibliothek an. github.com/nabinbhandari/Android-Permissions
Nabin Bhandari
15

Wenn Sie alle "Zustände" erkennen möchten (erstmalig abgelehnt, nur abgelehnt, nur mit "Nie wieder fragen" verweigert oder dauerhaft abgelehnt), können Sie Folgendes tun:

Erstellen Sie 2 Boolesche Werte

private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;

Stellen Sie den ersten ein, bevor Sie um Erlaubnis bitten:

beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Legen Sie die zweite in Ihrer onRequestPermissionsResult-Methode fest:

afterClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Verwenden Sie die folgende "Tabelle", um alles zu tun, was Sie in onRequestPermissionsResult () benötigen (nachdem Sie überprüft haben, dass Sie noch nicht über die Berechtigung verfügen):

// 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
mVck
quelle
Es macht keinen Sinn, die shouldShowRequestPermissionRationale vor dem Aufrufen von requestPermissions zu überprüfen, es sei denn, Sie möchten die Begründung anzeigen, bevor Sie die Berechtigung anfordern. Die Begründung erst zu zeigen, nachdem der Benutzer die Berechtigung verweigert hat, scheint jedoch zu sein, wie die meisten Apps heutzutage damit umgehen.
Emanuel Moecklin
2
@EmanuelMoecklin, soweit ich weiß, ist dies die einzige Möglichkeit zu überprüfen, ob es bereits abgelehnt wurde (indem es vorher und nachher überprüft wird, wie in meiner Wahrheitstabelle erläutert) oder ob es ein erstes Mal verweigert wird (in meinem Fall leite ich den Benutzer um die App-Einstellungen, wenn es dauerhaft verweigert wird)
mVck
1
// TRUE FALSEtritt auch auf, wenn der Benutzer eine Berechtigung zulässt, nachdem er sie zuvor verweigert hat.
Samis
11

Ich hatte das gleiche Problem und habe es herausgefunden. Um das Leben viel einfacher zu machen, habe ich eine util-Klasse geschrieben, um Laufzeitberechtigungen zu verarbeiten.

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

Die PreferenceUtil- Methoden lauten wie folgt.

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

Jetzt müssen Sie nur noch die Methode * checkPermission * mit den richtigen Argumenten verwenden.

Hier ist ein Beispiel,

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

Woher weiß meine App, ob der Benutzer das Kontrollkästchen "Nie wieder fragen" aktiviert hat?

Wenn der Benutzer Nie wieder fragen aktiviert ist , erhalten Sie einen Rückruf auf onPermissionDisabled .

Viel Spaß beim Codieren :)

Muthuraj
quelle
shouldShowRequestPermissionRationale Ich habe hier einen Fehler. Können Sie mir bitte helfen?
Rucha Bhatt Joshi
Ich kann diese Methode nicht finden sollteShowRequestPermissionRationale kann sein, dass ich keinen Kontext bekommen habe .. aber es ist in Ordnung, ich habe eine andere alternative Lösung gefunden .. Danke für die Hilfe :)
Rucha Bhatt Joshi
1
Mein Fehler. shouldShowRequestPermissionRationale ist über Activity und nicht über den Kontext verfügbar. Ich habe meine Antwort aktualisiert, indem ich den Kontext in Aktivität umgewandelt habe, bevor ich diese Methode aufgerufen habe. Schau es
dir an
1
Dies ist die einzige Möglichkeit, den ersten von zurückgegebenen falschen Wert shouldShowRequestPermissionRationalezu umgehen und die an den Benutzer gesendete Anforderung zu speichern. Ich hatte die gleiche Idee und fand Ihre Antwort. Netter Job Mann
MatPag
4

Vollständige Erklärung für jeden Fall der Erlaubnis

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

    }
}
Saksham
quelle
4

Eine nützliche Funktion, um festzustellen, ob eine beliebige Berechtigung für die Anforderung gesperrt wurde (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
}

Um dies zu verwenden, müssen Sie einen Booleschen Wert für gemeinsame Einstellungen mit dem Namen Ihrer gewünschten Berechtigung (z. B. android.Manifest.permission.READ_PHONE_STATE) festlegen, truewenn Sie zum ersten Mal eine Berechtigung anfordern.


Erläuterung:

Build.VERSION.SDK_INT >= Build.VERSION_CODES.M da ein Teil des Codes möglicherweise nur auf API-Ebene 23+ ausgeführt wird.

ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED Zur Überprüfung haben wir noch keine Erlaubnis.

!activity.shouldShowRequestPermissionRationale(permission)um zu überprüfen, ob der Benutzer die App abgelehnt hat und erneut fragt. Aufgrund von Macken dieser Funktion ist auch die folgende Zeile erforderlich.

PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false) Dies wird verwendet (zusammen mit dem Setzen des Werts auf true bei der ersten Berechtigungsanforderung), um zwischen den Zuständen "Nie gefragt" und "Nie wieder fragen" zu unterscheiden, da die vorherige Zeile diese Informationen nicht zurückgibt.

JakeSteam
quelle
4

Mit der Methode shouldShowRequestPermissionRationale () kann überprüft werden, ob der Benutzer die Option "Nie wieder gefragt" ausgewählt und die Berechtigung verweigert hat. Es gibt viele Codebeispiele, daher würde ich lieber erklären, wie man es für einen solchen Zweck verwendet, da ich denke, dass sein Name und seine Implementierung dies komplizierter machen, als es tatsächlich ist.

Wie unter Anfordern von Berechtigungen zur Laufzeit erläutert , gibt diese Methode true zurück, wenn die Option 'nie wieder fragen' sichtbar ist, andernfalls false. Daher wird beim ersten Anzeigen eines Dialogfelds false zurückgegeben. Ab dem zweiten Mal wird true zurückgegeben. Wenn der Benutzer die Berechtigung zur Auswahl der Option verweigert, wird an diesem Punkt erneut false zurückgegeben.

Um einen solchen Fall zu erkennen, können Sie entweder die Sequenz false-true-false erkennen oder (einfacher) ein Flag verwenden, das die anfängliche Zeit verfolgt, zu der der Dialog angezeigt wird. Danach gibt diese Methode entweder true oder false zurück, wobei Sie mit false erkennen können, wann die Option ausgewählt ist.

Alessio
quelle
3

Bitte werfen Sie für diese Lösung keine Steine ​​auf mich.

Das funktioniert aber ist ein bisschen "hacky".

Wenn Sie anrufen requestPermissions, registrieren Sie die aktuelle Uhrzeit.

        mAskedPermissionTime = System.currentTimeMillis();

Dann in onRequestPermissionsResult

Wenn das Ergebnis nicht gewährt wird, überprüfen Sie die Uhrzeit erneut.

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

Da der Benutzer möglicherweise nicht so schnell auf die Schaltfläche "Verweigern" klicken kann, wissen wir, dass er "Nie wieder fragen" ausgewählt hat, da der Rückruf sofort erfolgt.

Verwendung auf eigenes Risiko.

Antzi
quelle
Was ist, wenn wir den angeforderten Dialog 5 Minuten lang sehen und dann ablehnen?
Saksham
Was nützt das dann, wenn es die Grundvoraussetzung nicht erfüllen kann? Ein Code kann ein Hack sein, wenn er akzeptiert wird, wenn er alle Anforderungen eindeutig erfüllt, sonst nicht.
Saksham
Ja das ist schlecht Automatische Tester wie dieser könnten möglicherweise schneller klicken: developer.android.com/training/testing/crawler
stackzebra
2

Ich habe eine Abkürzung für die Berechtigungsanforderung in Android M geschrieben. Dieser Code behandelt auch die Abwärtskompatibilität mit älteren Android-Versionen.

Der gesamte hässliche Code wird in ein Fragment extrahiert, das sich an die Aktivität anfügt und von dieser löst, um die Berechtigungen anzufordern. Sie können PermissionRequestManagerFolgendes verwenden:

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

Schauen Sie sich das an: https://gist.github.com/crysxd/385b57d74045a8bd67c4110c34ab74aa

crysxd
quelle
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
                    }
                }
            }
        }
    }
}
Vinod Ranga
quelle
2

Probieren Sie diese einfache Berechtigungsbibliothek aus. Alle mit der Berechtigung verbundenen Vorgänge werden in drei einfachen Schritten ausgeführt. Das hat mir Zeit gespart. Sie können alle berechtigungsbezogenen Arbeiten in 15 Minuten beenden .

Es kann mit Verweigern umgehen, es kann mit Nie wieder fragen umgehen, es kann App-Einstellungen zur Erlaubnis aufrufen, es kann eine rationale Nachricht geben, es kann eine Verweigerungsnachricht geben, es kann eine Liste akzeptierter Berechtigungen geben, es kann eine Liste verweigerter Nachrichten geben Berechtigungen und etc.

https://github.com/ParkSangGwon/TedPermission

Schritt 1: Fügen Sie Ihre Abhängigkeit hinzu

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

Schritt 2: Fragen Sie nach Berechtigungen

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

Schritt 3: Berechtigungsantwort verarbeiten

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();
    }
};
Vignes
quelle
Toll. Es hat mir Zeit gespart
Vigneswaran A
Schön, einfach zu bedienen
Uray Febri
2

Sie können hübsch zuhören.

Hörer

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

Hauptklasse zur Erlaubnis

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

    }
}

Auf diese Weise verwendet

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

                })

onRequestPermissionsResult in activity oder fragmnet überschreiben

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()
        }
        }
    }
Rasoul Miri
quelle
1

Stattdessen erhalten Sie einen Rückruf onRequestPermissionsResult()als PERMISSION_DENIED, wenn Sie erneut um Erlaubnis bitten, während Sie in den falschen Zustand von fallenshouldShowRequestPermissionRationale()

Aus dem Android-Dokument:

Wenn das System den Benutzer auffordert, eine Berechtigung zu erteilen, hat der Benutzer die Möglichkeit, das System anzuweisen, diese Berechtigung nicht erneut anzufordern. In diesem Fall lehnt requestPermissions()das System die Anforderung jedes Mal sofort ab , wenn eine App diese Berechtigung erneut anfordert. Das System ruft Ihre onRequestPermissionsResult()Rückrufmethode auf und übergibt sie PERMISSION_DENIEDgenauso, wie wenn der Benutzer Ihre Anfrage erneut explizit abgelehnt hätte. Dies bedeutet, dass Sie beim Anruf requestPermissions()nicht davon ausgehen können, dass eine direkte Interaktion mit dem Benutzer stattgefunden hat.

Farhan
quelle
1

Mit der if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)Methode können Sie feststellen, ob nie gefragt aktiviert ist oder nicht.

Weitere Informationen: Überprüfen Sie dies

Um nach mehreren Berechtigungen zu suchen, verwenden Sie:

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

EXPLAIN () -Methode

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

Der obige Code zeigt auch ein Dialogfeld an, in dem der Benutzer zum Bildschirm mit den App-Einstellungen weitergeleitet wird, von dem aus er die Berechtigung erteilen kann, wenn er die Schaltfläche Nie wieder fragen aktiviert hat.

user6435056
quelle
1

Sie können verwenden

shouldShowRequestPermissionRationale()

Innerhalb

onRequestPermissionsResult()

Siehe das folgende Beispiel:

Überprüfen Sie, ob die Berechtigung vorliegt, wenn der Benutzer auf die Schaltfläche klickt:

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

Wenn der Benutzer das Berechtigungsdialogfeld beantwortet, gehen wir zu 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();
            }
        }
    }

}
Bald Santos
quelle
0

Ich möchte auch die Information erhalten, ob der Benutzer "Nie wieder fragen" ausgewählt hat oder nicht. Ich habe mit einer hässlich aussehenden Flagge eine „fast Lösung“ erreicht, aber bevor ich Ihnen sage, wie, werde ich Ihnen von meiner Motivation erzählen:

Ich möchte zunächst die Berechtigungsverweisfunktion anbieten. Wenn der Benutzer es verwendet und keine Rechte hat, erhält er entweder den 1. Dialog von oben oder sowohl den 2. als auch den 3. Dialog. Wenn der Benutzer "Nie wieder fragen" gewählt hat, möchte ich die Funktionalität deaktivieren und anders anzeigen. - Meine Aktion wird durch eine Spinner-Texteingabe ausgelöst. Ich möchte dem angezeigten Beschriftungstext auch '(Berechtigung widerrufen)' hinzufügen. Dies zeigt dem Benutzer: "Es gibt Funktionen, die ich jedoch aufgrund meiner Berechtigungseinstellungen nicht verwenden kann." Dies scheint jedoch nicht möglich zu sein, da ich nicht überprüfen kann, ob "Nie wieder fragen" gewählt wurde.

Ich bin zu einer Lösung gekommen, mit der ich leben kann, indem meine Funktionalität immer mit einer aktiven Berechtigungsprüfung aktiviert wurde. Bei einer negativen Antwort wird in onRequestPermissionsResult () eine Toast-Nachricht angezeigt, jedoch nur, wenn ich mein benutzerdefiniertes Begründungs-Popup nicht angezeigt habe. Wenn der Benutzer "Nie wieder fragen" gewählt hat, erhält er nur eine Toastnachricht. Wenn der Benutzer nicht "Nie wieder fragen" wählt, erhält er nur die benutzerdefinierte Begründung und das Popup "Berechtigungsanforderung" vom Betriebssystem, jedoch keinen Toast, da drei Benachrichtigungen hintereinander zu schmerzhaft wären.

ChristianKoelle
quelle
0

Ich muss eine dynamische Berechtigung für die Kamera implementieren. Wo 3 mögliche Fälle auftreten: 1. Zulassen, 2. Verweigert, 3. Nicht erneut fragen.

 @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;
    }
}
hitesh141
quelle
0

Ausgehend von der obigen Antwort von mVck bestimmt die folgende Logik, ob "Nie wieder fragen" für eine bestimmte Berechtigungsanforderung überprüft wurde:

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

welches von unten extrahiert wird (für das vollständige Beispiel siehe diese Antwort )

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);
}
Sam ist
quelle
0

Um die Frage genau zu beantworten: Was passiert, wenn der Benutzer "Nie wieder fragen" drückt?

Die überschriebene Methode / Funktion

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

Das GrantResult-Array wird als leer ausgegeben, sodass Sie dort möglicherweise etwas tun können. Aber nicht die beste Vorgehensweise.

Wie gehe ich mit "Nie wieder fragen" um?

Ich arbeite mit Fragment, für das die Berechtigung READ_EXTERNAL_STORAGE erforderlich war.

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

            }
        }
    }

Die anderen Funktionen sind trivial.

// 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)
}
devDeejay
quelle