wake-up-neo.net

Wie unterscheiden wir die nie gestellten Fragen in den Laufzeitberechtigungen von Android M vom Abfragen?

Wenn es um die M Developer Preview-Laufzeitberechtigungen gemäß Google geht:

  1. Wenn Sie noch nie eine bestimmte Erlaubnis beantragt haben, fragen Sie einfach danach

  2. Wenn Sie zuvor gefragt haben und der Benutzer "Nein" gesagt hat und der Benutzer dann versucht, etwas zu tun, für das die abgelehnte Berechtigung erforderlich ist, sollten Sie den Benutzer auffordern, zu erklären, warum Sie die Berechtigung benötigen, bevor Sie die Berechtigung erneut anfordern

  3. Wenn Sie zuvor mehrmals gefragt haben und der Benutzer "Nein und nicht mehr fragen" gefragt hat (über das Kontrollkästchen im Dialogfeld für die Laufzeitberechtigung), sollten Sie die Arbeit einfach beenden (beispielsweise die Benutzeroberfläche deaktivieren, für die die Berechtigung erforderlich ist).

Wir haben jedoch nur eine Methode, shouldShowRequestPermissionRationale(), die eine boolean zurückgibt, und wir haben drei Zustände. Wir brauchen einen Weg, um den nie abgefragten Zustand von dem Stop-Ask-Zustand zu unterscheiden, da wir false von shouldShowRequestPermissionRationale() für beide erhalten.

Für Berechtigungen, die bei der ersten Ausführung der App angefordert werden, ist dies kein großes Problem. Es gibt viele Rezepte, mit denen Sie feststellen können, dass dies wahrscheinlich die erste Ausführung Ihrer App ist (z. B. boolean value in SharedPreferences). Sie gehen also davon aus, dass Sie sich bei der ersten Ausführung Ihrer App im unbefragten Zustand befinden.

Ein Teil der Vision von Laufzeitberechtigungen besteht jedoch darin, dass Sie möglicherweise nicht alle im Vorfeld nach allen Berechtigungen fragen. An Fringe-Funktionen gebundene Berechtigungen, die Sie möglicherweise erst später anfordern, wenn der Benutzer auf etwas tippt, für das diese Berechtigung erforderlich ist. Hier wurde die App möglicherweise schon seit Monaten mehrmals ausgeführt, bevor wir plötzlich eine weitere Genehmigung anfordern müssen.

Sollen wir in diesen Fällen nachprüfen, ob wir selbst um Erlaubnis gebeten haben oder nicht? Oder gibt es etwas in der Android M-API, das ich vermisse, das uns sagt, ob wir vorher gefragt haben oder nicht?

61
CommonsWare

Wie im aktuellen Beispiel: https://github.com/googlesamples/Android-RuntimePermissions/blob/master/Application/src/main/Java/com/example/Android/system/runtimepermissions/MainActivity.Java#L195

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
        int[] grantResults) {
    if (requestCode == REQUEST_CAMERA) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            doThing();
            //STORE FALSE IN SHAREDPREFERENCES
        } else {
            //STORE TRUE IN SHAREDPREFERENCES
        }
    }

Speichern Sie einen Booleschen Wert in SharedPreferences mit dem Schlüssel als Berechtigungscode und Wert wie oben angegeben, um anzugeben, ob diese Einstellung zuvor abgelehnt wurde.

Leider können Sie wahrscheinlich nicht anhand einer Voreinstellung prüfen, die akzeptiert wurde und später abgelehnt wurde, während Ihre App ausgeführt wird. Die endgültige Spezifikation ist nicht verfügbar, es besteht jedoch die Möglichkeit, dass Ihre App entweder neu gestartet wird oder Scheinwerte bis zum nächsten Start erhält.

13

Ich weiß, dass ich sehr spät poste, aber ein detailliertes Beispiel kann für jemanden hilfreich sein.

Was mir aufgefallen ist, wenn wir die shouldShowRequestPermissionRationale () -Flag in der onRequestPermissionsResult () - Callback-Methode markieren, werden nur zwei Zustände angezeigt.

Status 1: -Return true: - Jedes Mal, wenn der Benutzer auf Berechtigungen verweigern klickt (auch beim allerersten Mal).

Status 2: -Returns false: - Wenn der Benutzer s auswählt, fragt er nie mehr.

Hier ist ein Beispiel mit mehrfacher Berechtigungsanfrage: -

Die App benötigt beim Start 2 Berechtigungen. SEND_SMS und ACCESS_FINE_LOCATION (beide werden in manifest.xml erwähnt).

Sobald die App gestartet wird, werden mehrere Berechtigungen gleichzeitig benötigt. Wenn beide Berechtigungen erteilt werden, wird der normale Fluss ausgeführt. 

 enter image description here

public static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if(checkAndRequestPermissions()) {
        // carry on the normal flow, as the case of  permissions  granted.
    }
}

private  boolean checkAndRequestPermissions() {
    int permissionSendMessage = ContextCompat.checkSelfPermission(this,
            Manifest.permission.SEND_SMS);
    int locationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
    List<String> listPermissionsNeeded = new ArrayList<>();
    if (locationPermission != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
    }
    if (permissionSendMessage != PackageManager.PERMISSION_GRANTED) {
        listPermissionsNeeded.add(Manifest.permission.SEND_SMS);
    }
    if (!listPermissionsNeeded.isEmpty()) {
        ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),REQUEST_ID_MULTIPLE_PERMISSIONS);
        return false;
    }
    return true;
}

Wenn eine oder mehrere Berechtigungen nicht erteilt werden, fordert ActivityCompat.requestPermissions () Berechtigungen an, und das Steuerelement geht an die Callback-Methode onRequestPermissionsResult ().

Sie sollten den Wert von shouldShowRequestPermissionRationale () in der Callback-Methode onRequestPermissionsResult () überprüfen. 

Es gibt nur zwei Fälle: -

Fall 1: - Wenn der Benutzer zu einem beliebigen Zeitpunkt auf Ablehnungsberechtigungen (einschließlich des allerersten Mal) klickt, wird true zurückgegeben. Wenn der Benutzer dies ablehnt, können wir weitere Erklärungen anzeigen und erneut fragen.

Fall 2: - Nur wenn der Benutzer "nie wieder gefragt" auswählt, wird "false" zurückgegeben. In diesem Fall können wir mit eingeschränkten Funktionen fortfahren und den Benutzer anweisen, die Berechtigungen aus den Einstellungen für weitere Funktionen zu aktivieren, oder wir können das Setup abschließen, wenn die Berechtigungen für die App trivial sind.

FALL 1

 Case - 1

CASE- 2

 Case - 2

@Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        Log.d(TAG, "Permission callback called-------");
        switch (requestCode) {
            case REQUEST_ID_MULTIPLE_PERMISSIONS: {

                Map<String, Integer> perms = new HashMap<>();
                // Initialize the map with both permissions
                perms.put(Manifest.permission.SEND_SMS, PackageManager.PERMISSION_GRANTED);
                perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
                // Fill with actual results from user
                if (grantResults.length > 0) {
                    for (int i = 0; i < permissions.length; i++)
                        perms.put(permissions[i], grantResults[i]);
                    // Check for both permissions
                    if (perms.get(Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED
                            && perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                        Log.d(TAG, "sms & location services permission granted");
                        // process the normal flow
                        //else any one or both the permissions are not granted
                    } else {
                            Log.d(TAG, "Some permissions are not granted ask again ");
                            //permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
//                        // shouldShowRequestPermissionRationale will return true
                            //show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
                            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.SEND_SMS) || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
                                showDialogOK("SMS and Location Services Permission 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.
                                                        break;
                                                }
                                            }
                                        });
                            }
                            //permission is denied (and never ask again is  checked)
                            //shouldShowRequestPermissionRationale will return false
                            else {
                                Toast.makeText(this, "Go to settings and enable permissions", Toast.LENGTH_LONG)
                                        .show();
    //                            //proceed with logic by disabling the related features or quit the app.
                            }
                    }
                }
            }
        }

    }

    private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", okListener)
                .create()
                .show();
    }
63
Nicks

Nein, Sie müssen nicht nachprüfen, ob Sie nach der Erlaubnis gefragt haben oder nicht, und Sie müssen Nie-Fragen von Stop-Asking unterscheiden.

Die Status 1 und 3 sind für App-Entwickler gleich: Sie benötigen die Berechtigung und ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED. Dann fragen Sie einfach über die Funktion ActivityCompat.requestPermissions() nach der Berechtigung. Immer, wenn der Benutzer die Funktion angetippt hat, für die die Berechtigung erforderlich ist, unabhängig davon, wie oft Sie dies angefordert haben. Der Benutzer wird es irgendwann "gewähren" oder "verweigern", wobei "Nie wieder fragen" markiert ist. Der Entwurf entmutigt Sie NICHT, das Dialogfeld für die Berechtigungsanforderung mehrmals anzuzeigen.

Der Entwurf fordert Sie jedoch auf, den Zweck der Erlaubnis zu einem bestimmten Zeitpunkt zu erläutern - in Ihrem Zustand 2. shouldShowRequestPermissionRationale() wird NICHT verwendet, um zu bestimmen, ob Sie eine Erlaubnis anfordern sollten. Sie wird verwendet, um zu bestimmen, ob Sie Erklärungen anzeigen sollen, BEVOR Sie eine Erlaubnis anfordern .

Noch ein paar Erklärungen zum Zustand 3:

  1. Ja, wir sollten aufhören, den Benutzer zu belästigen, indem wir aufhören, die Erklärung zu zeigen, und nicht die Anfrage abbrechen. Deshalb haben sie die shouldShowRequestPermissionRationale() zur Verfügung gestellt.
  2. Es ist nicht störend, die Bitte um Erlaubnis zu behalten. Nachdem der Benutzer "nie mehr fragen" gewählt hat, wird ActivityCompat.requestPermissions() keine Dialogbox mehr anzeigen.
  3. Es ist besser, die relevante Benutzeroberfläche jedes Mal zu deaktivieren, wenn wir feststellen, dass wir keine Berechtigung haben, während einer Sitzung mit nur einem Benutzer. Deaktivieren Sie die Benutzeroberfläche, nachdem shouldShowRequestPermissionRationale() false zurückgegeben wurde.
6
ed9er

Ich habe einen Lösungsansatz für Ihr Problem, es scheint ziemlich gut für mich zu funktionieren.

Ich unterscheide Nie nie Fragen von Stop-Asking mit den SharedPreferences. Ich gebe Ihnen ein Beispiel, wie ich das benutze.

private void requestAccountPermission() {

        SharedPreferences mPreferences = getSharedPreferences("configuration", MODE_PRIVATE);
        boolean firstTimeAccount = mPreferences.getBoolean("firstTimeAccount", true);

        if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.GET_ACCOUNTS)) {
            // 2. Asked before, and the user said "no"
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.GET_ACCOUNTS}, REQUEST_CODE_ACCOUNTS);
        }else {
            if(firstTimeAccount) { 
                // 1. first time, never asked 
                SharedPreferences.Editor editor = mPreferences.edit();
                editor.putBoolean("firstTimeAccount", false);
                editor.commit();

                // Account permission has not been granted, request it directly.
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.GET_ACCOUNTS},REQUEST_CODE_ACCOUNTS);
            }else{
                // 3. If you asked a couple of times before, and the user has said "no, and stop asking"

                // Your code
            }
        }
    }
2
Joacer

Hier ist eine Methode, mit der Sie nachverfolgen können, wann der Berechtigungsdialog zum ersten Mal angezeigt wurde. Wenn der Benutzer das Kontrollkästchen aktiviert hat, wird er nie mehr gefragt, und wenn die Berechtigung direkt abgelehnt wird, nachdem der Benutzer das Kontrollkästchen aktiviert hat, müssen Sie das Kontrollkästchen für das Berechtigungsdialogfeld aktivieren, bevor das Dialogfeld angezeigt wird result in onRequestPermissionsResult. Rufen Sie bei Bedarf die Methode checkPermission () auf.

public boolean mPermissionRationaleDialogShown = false;

public void checkPermission() {
    if (ContextCompat.checkSelfPermission(this, "PermissionName")
            != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, "PermissionName")) {
            showPermissionRequiredDialog();
        } else {
            askPermission();
        }
    } else {
       // Permission Granted
    }
}

public void askPermission() {
    ActivityCompat.requestPermissions(this,
            new String[]{"PermissionName"}, permissionRequestCode);
}

public void showPermissionRequiredDialog() {
    mPermissionRationaleDialogShown = true;
    // Dialog to show why permission is required
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == PERMISSION_REQUEST_CODE) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Permission Granted
        } else {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, "PermissionName")
                    && !mPermissionRationaleDialogShown) {
                // Permission dialog was shown for first time
            } else if (ActivityCompat.shouldShowRequestPermissionRationale(this, "PermissionName")
                    && mPermissionRationaleDialogShown){
                // User deny permission without Never ask again checked
            } else if (!ActivityCompat.shouldShowRequestPermissionRationale(this, PERMISSION_READ_EXTERNAL)
                    && mPermissionRationaleDialogShown) {
                // User has checked Never ask again during this permission request
            } else {
                // No permission dialog shown to user has user has previously checked Never ask again. Here we can show dialog to open setting screen to change permission
            }
        }
    } else {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}
1
Yogesh Pareek

Nachdem Sie alle Antworten hier und einen anderen Beitrag über das Internet ausprobiert haben. Ich erfuhr, dass ich eine sharedPreference isLocationPermissionDialogShown (default false) verwenden muss und alles wie erwartet funktioniert. 

  1. Wenn zum ersten Mal um Erlaubnis gefragt. In diesem Fall gibt shouldShowRequestPermissionRationalefalse und isLocationPermissionDialogShown auch false zurück.
  2. Beim zweiten Mal shouldShowRequestPermissionRationale wird true zurückgegeben und während des Dialogs wird isLocationPermissionDialogShown auf true gesetzt. und wenn wir die Bedingung überprüfen, werden beide true sein. 
  3. Jedes Mal bis Niemals erneut gefragt: shouldShowRequestPermissionRationale gibt true zurück und isLocationPermissionDialogShown gibt true zurück.
  4. Wenn Niemals erneut gefragt wird shouldShowRequestPermissionRationale gibt false zurück und isLocationPermissionDialogShown gibt true zurück. Welches ist, was wir brauchen.

Bitte überprüfen Sie das Funktionsbeispiel.

public class MainActivity extends AppCompatActivity {
    SharedPreferences sharedPreferences;
    String locationPermission;
    String prefLocationPermissionKey = "isLocationPermissionDialogShown";
    private final int PERMISSION_REQUEST_CODE_LOCATION = 1001;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        locationPermission = Manifest.permission.ACCESS_FINE_LOCATION;
        sharedPreferences = getSharedPreferences("configuration", MODE_PRIVATE);

        //check for Android version
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //Check for permission
            if (checkSelfPermission(locationPermission) != PackageManager.PERMISSION_GRANTED) {
                //check if clarification dialog should be shown.
                if (shouldShowRequestPermissionRationale(locationPermission)) {
                    showClarificationDialog(locationPermission, PERMISSION_REQUEST_CODE_LOCATION);
                } else  {
                    requestPermissions(new String[] { locationPermission}, PERMISSION_REQUEST_CODE_LOCATION);
                }
            } else {
                Log.d("nets-debug", "permission already grranted");
            }
        }

    }

    @Override
    @TargetApi(Build.VERSION_CODES.M)
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
            //for location permission
            if (requestCode == PERMISSION_REQUEST_CODE_LOCATION) {
                boolean isLocationPermissionDialogShown = sharedPreferences.getBoolean(prefLocationPermissionKey, false);

                if (!shouldShowRequestPermissionRationale(locationPermission) && isLocationPermissionDialogShown) {
                    // user selected Never Ask Again. do something
                    Log.d("nets-debug", "never ask again");
                } else {
                    // all other conditions like first time asked, previously denied etc are captured here and can be extended if required.
                    Log.d("nets-debug", "all other cases");
                }
            }

        }

    }

    @TargetApi(Build.VERSION_CODES.M)
    public void showClarificationDialog(final String permission, final int requestCode) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("Permission Required");
        builder.setMessage("Please grant Location permission to use all features of this app");
        builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                SharedPreferences.Editor editor = sharedPreferences.edit();
                editor.putBoolean(prefLocationPermissionKey, true);
                editor.apply();
                requestPermissions(new String[] {permission}, requestCode);
            }
        });
        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Toast.makeText(getApplicationContext(), "This permission required", Toast.LENGTH_LONG).show();
            }
        });
        builder.create().show();
    }

}

Hoffe das wird helfen.

1
Natwar Singh

SO ENDLICH IST MEINE ZEIT, EINE FRAGE VON COMMONSWARE ANTWORTEN


Geschäftsablauf: -

Wenn der Benutzer zum ersten Mal auf "Berechtigung verweigern" klickt, zeige ich einen Dialog, in dem die Notwendigkeit der Berechtigung erläutert wird. Wenn der Benutzer im Begründungsdialogfeld auf die Schaltfläche "Abbrechen" klickt, wird ein Toast mit der Meldung "Bitte geben Sie die Erlaubnis, den Standort zu erhalten" angezeigt.

Wenn der Benutzer nach dem Klicken auf Berechtigung verweigern (nicht erneut fragen) im Berechtigungsdialogfeld klickt, wird die Meldung "Bitte geben Sie die Standortberechtigung in den App-Einstellungen an" angezeigt. Beachten Sie, dass ich die Wörter "von App-Einstellungen" hinzugefügt habe, da der Benutzer das Kontrollkästchen "Nicht mehr fragen" aktiviert hat. 

3. Der Berechtigungsdialog wird ab jetzt nicht mehr angezeigt.) grundlegender Dialog wird nicht angezeigt.

Der Schlüssel hier ist also, dass, wenn sowohl der Berechtigungsdialog als auch der Grunddialog nicht angezeigt werden, der Benutzer das Kontrollkästchen "Nicht mehr fragen" aktiviert hat.

Der Code:-

        mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)){
                AlertDialogHelper.showDialogWithYesNoCallback(mContext, getString(R.string.confirm), getString(R.string.please_give_permission_to_get_location), new onItemClickReturnBoolean() {
                    @Override
                    public void onItemClick(Boolean status) {
                        if(status){
                            ActivityCompat.requestPermissions(SplashScreenActivity.this,permissions,AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE);
                        }
                        else{
                            ShowToast.showShortToast(SplashScreenActivity.this,getString(R.string.please_give_permission_to_get_location));
                            finish();
                        }
                    }
                });
            }
            else{
                ActivityCompat.requestPermissions(this,permissions,AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE);
            }
        }
        else{
            gettingLocationAfterPermissionGranted();
        }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode == AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE){
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                gettingLocationAfterPermissionGranted();
            }
            else{
                if(ActivityCompat.shouldShowRequestPermissionRationale(SplashScreenActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)){
                    ShowToast.showShortToast(this,getString(R.string.please_give_permission_to_get_location));
                }
                else{
                    ShowToast.showShortToast(this,getString(R.string.please_give_location_permission_from_app_settings));
                }
                finish();
            }
        }
    }

Überprüfen Sie dieses Repository: https://github.com/debChowdhury/PermissionHelperEasy


Easy peasy


0

hier - es gibt ein Flussdiagramm, das den Prozess recht gut erklärt. Außerdem wird erläutert, wann Sie shouldShowRequestPermissionRationale() aufrufen sollten und wann true zurückgegeben wird.

Grundsätzlich sollten Sie laut Android-Dokumentation immer um Erlaubnis fragen, wenn Sie nicht über diese verfügen (Android gibt automatisch DENIED zurück, wenn der Benutzer nie mehr gefragt hat) und Sie sollten eine kurze Meldung anzeigen, wenn der Benutzer bereits abgelehnt hat Sie waren einmal in der Vergangenheit, haben aber die Option "nie wieder fragen" markiert.

0
Ronnie