Die Berechtigung WRITE_SETTINGS kann nicht abgerufen werden

83

Wenn ich unter Android M Preview 3 eine Ziel-API von 23 habe, kann ich anscheinend nicht die Berechtigung Manifest.permission.WRITE_SETTTINGS erwerben.

 requestPermissions(new String[]{Manifest.permission.WRITE_SETTINGS},
              101);

Die Berechtigung anfordern ruft nicht den Dialog auf, den ich erwarten würde, aber wenn ich den folgenden Aufruf ohne diese Berechtigung tätige,

 RingtoneManager.setActualDefaultRingtoneUri(activity, RingtoneManager.TYPE_RINGTONE, ringUri);

Der Anruf wird nur, weil ich nicht die Erlaubnis habe.

Ich bin mir nicht sicher, wohin ich von hier aus gehen soll. Gibt es eine neue Klingelton-API für 23? Oder hat diese Berechtigungsänderung es Nicht-System-Apps nur unmöglich gemacht, den Klingelton zu ändern?

Justin
quelle

Antworten:

132

Verwendung WRITE_SETTINGSbasierend auf den Dokumenten:

  1. Haben Sie das <uses-permission>Element im Manifest wie gewohnt.

  2. RufenSettings.System.canWrite() Sie an, um zu sehen, ob Sie berechtigt sind, Einstellungen zu schreiben.

  3. Wenn dies canWrite()zurückkehrt false, starten Sie die ACTION_MANAGE_WRITE_SETTINGSAktivität, damit der Benutzer dort zustimmen kann, damit Ihre App tatsächlich in die Einstellungen schreiben kann.

Mit anderen Worten, das Schreiben in Einstellungen ist jetzt ein Double-Opt-In (Installation vereinbaren, separat in den Einstellungen vereinbaren, um dies zuzulassen), ähnlich wie Geräte-Administrator-APIs, Eingabehilfen usw.

Beachten Sie auch, dass ich diese noch nicht ausprobiert habe - dies basiert auf Untersuchungen, die ich gestern an Änderungen an Android 6.0 durchgeführt habe .

CommonsWare
quelle
Danke Mark! Lief wie am Schnürchen. developer.android.com/preview/features/runtime-permissions.html muss aktualisiert werden, wenn wir mehrere neue Möglichkeiten zum Anfordern von Berechtigungen haben möchten. (Ich hatte Ihren Blog bereits vor dem Posten gelesen, aber diese Informationen offensichtlich nicht gespeichert, als ich sie brauchte)
Justin
Das hat tatsächlich funktioniert. Für den Endbenutzer ist dies jedoch ein schlechter Ansatz. Gibt es Anzeichen dafür, dass Google dieses Verhalten ändert?
Fhl
2
@Fhl: Ich weiß nicht, warum sie diesen Weg gegangen sind, anstatt den regulären dangerousAnsatz für Laufzeitberechtigungen, den sie mit anderen Dingen in Android 6.0 gewählt haben. Ich werde überrascht sein, wenn sich dies bald ändert.
CommonsWare
2
Sie können Ihre App in der Absicht wie intent.setData(Uri.parse("package:" + Context.getPackageName()));
folgt
8
Eine andere zu beachtende Sache ist, dass es einen Fehler in Android zu geben scheint, der eine zuvor installierte App verursacht, bei der der Benutzer im oben beschriebenen Dialog Schreibberechtigungen erteilt hat, wobei der Kippschalter in die aktivierte Position gebracht wird, canWrite jedoch false zurückgibt. Damit die canWrite () -Methode true zurückgibt, muss der Benutzer den Schalter aus- und wieder einschalten ... Ich sehe dies in der Entwicklung, aber hoffentlich wird es nicht etwas sein, was Kunden sehen.
Matt Wolfe
45

Neben der Antwort von CommonsWare und dem Kommentar von Ogix gibt es hier einen Dummy-Code:

private boolean checkSystemWritePermission() {
    boolean retVal = true;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        retVal = Settings.System.canWrite(this);
        Log.d(TAG, "Can Write Settings: " + retVal);
        if(retVal){
            Toast.makeText(this, "Write allowed :-)", Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(this, "Write not allowed :-(", Toast.LENGTH_LONG).show();
            FragmentManager fm = getFragmentManager();
            PopupWritePermission dialogFragment = new PopupWritePermission();
            dialogFragment.show(fm, getString(R.string.popup_writesettings_title));
        }
    }
    return retVal;
}

Das Fragment PopupwritePermission gibt dann ein Fenster an, in dem die Situation erklärt wird. Ein Klick auf die Schaltfläche OK öffnet das Android-Systemmenü, in dem die Berechtigung erteilt werden kann:

private void openAndroidPermissionsMenu() {
    Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
    intent.setData(Uri.parse("package:" + getActivity().getPackageName()));
    startActivity(intent);
}
KP.dev
quelle
40

Die vorherigen Antworten sind großartig, ich habe nur wenig Ergänzung, um auch das Ergebnis für die Erlaubnis zu erhalten.

 public static void youDesirePermissionCode(Activity context){
        boolean permission;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            permission = Settings.System.canWrite(context);
        } else {
            permission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED;
        }
        if (permission) {
            //do your code
        }  else {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
                intent.setData(Uri.parse("package:" + context.getPackageName()));
                context.startActivityForResult(intent, MainActivity.CODE_WRITE_SETTINGS_PERMISSION);
            } else {
                ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.WRITE_SETTINGS}, MainActivity.CODE_WRITE_SETTINGS_PERMISSION);
            }
        }
    }

Und dann in der Activity:

@SuppressLint("NewApi")
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == MainActivity.CODE_WRITE_SETTINGS_PERMISSION && Settings.System.canWrite(this)){
            Log.d("TAG", "MainActivity.CODE_WRITE_SETTINGS_PERMISSION success");
            //do your code
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == MainActivity.CODE_WRITE_SETTINGS_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //do your code
        }
    }
Yshahak
quelle
Ich habe Ihren Code eingefügt und er funktioniert einwandfrei, auch wenn die Berechtigung erteilt wurde. Der benutzerdefinierte Klingelton wird jedoch nicht zugewiesen, und die Berechtigung "Write_Setting" wird weiterhin verweigert.
Zia Ur Rahman
4
ActivityCompat.requestPermissions (Kontext, neuer String [] {Manifest.permission.WRITE_SETTINGS}, ....); kann nicht verwendet werden. Es ist eine besondere Erlaubnis. Wir können diese Erlaubnis nur mit der in der Dokumentation angegebenen Absicht anfordern. Ebenfalls vor Marshmello wird die Erlaubnis zur Installationszeit dauerhaft erteilt
Anonym
2
@yshahak was ist deine Variable MainActivity.CODE_WRITE_SETTINGS_PERMISSION?
Bruno Bieri
@ BrunoBieri ja du hast recht, das habe ich weggelassen. Ich werde meine Antwort so bearbeiten, dass sie ausführlich ist.
Yshahak
Also was ist MainActivity.CODE_WRITE_SETTINGS_PERMISSION?
Klammern
12

Dies ist ein vollständiges Beispiel:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (Settings.System.canWrite(context) {
        // Do stuff here
    }
    else {
        Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
        intent.setData(Uri.parse("package:" + getActivity().getPackageName()));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}
Daniel Raouf
quelle
intent.setData (Uri.parse ("package:" + getActivity (). getPackageName ()));
Ole K
7

Ab Android Marshmellow müssen Sie Laufzeitberechtigungen verwenden, die auf mehr Sicherheit abzielen, oder Berechtigungen verwenden, wenn hier eine Dokumentation erforderlich ist

Die Dokumentation zu den Schreibeinstellungen finden Sie hier

Im Manifest hinzufügen

<uses-permission android:name="android.permission.WRITE_SETTINGS" />

In deiner Klasse

private boolean checkSystemWritePermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if(Settings.System.canWrite(context))
            return true;
        else 
            openAndroidPermissionsMenu();
    }
    return false;
}

private void openAndroidPermissionsMenu() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
        intent.setData(Uri.parse("package:" + context.getPackageName()));
        context.startActivity(intent);
    }
}

Und benutze es so

try {
       if (checkSystemWritePermission()) {
            RingtoneManager.setActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE, newUri);
            Toast.makeText(context, "Set as ringtoon successfully ", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context, "Allow modify system settings ==> ON ", Toast.LENGTH_LONG).show();
            }
        } catch (Exception e) {
            Log.i("ringtoon",e.toString());
            Toast.makeText(context, "unable to set as Ringtoon ", Toast.LENGTH_SHORT).show();
        }
Abhishek Garg
quelle
5

Die Erlaubnis android.permission.WRITE_SETTINGSist jetzt in der Gruppe signature|appop|pre23|preinstalledwie android.permission.CHANGE_NETWORK_STATEundandroid.permission.SYSTEM_ALERT_WINDOW

Dies bedeutet, dass Sie es auf SDK 22 und darunter erhalten. In einer neueren Version müssen Sie ein App-Betreiber sein.

passsy
quelle
4

Ich habe unten wie verwendet ..

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        boolean retVal = true;
        retVal = Settings.System.canWrite(this);
        if (retVal == false) {
            if (!Settings.System.canWrite(getApplicationContext())) {

                Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
                Toast.makeText(getApplicationContext(), "Please, allow system settings for automatic logout ", Toast.LENGTH_LONG).show();
                startActivityForResult(intent, 200);
            }
        }else {
            Toast.makeText(getApplicationContext(), "You are not allowed to wright ", Toast.LENGTH_LONG).show();
        }
    }

Offensichtliche Erlaubnis

<uses-permission  android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions" />
Enamul Haque
quelle
2

Erwähnen Sie die folgende Erlaubnis in AndroidManifest.xml

In Aktivität unten verwenden, wenn sonst zum Ändern der Einstellung.

if(Settings.System.canWrite(this)){
    // change setting here
}
else{
    //Migrate to Setting write permission screen. 
    Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
    intent.setData(Uri.parse("package:" + mContext.getPackageName()));
    startActivity(intent);
}
Sourabh Tejraj
quelle
Bitte benutzen Sie diese Erlaubnis. <Verwendet-Erlaubnis android: name = "android.permission.WRITE_SETTINGS" />
Sourabh Tejraj