Nie można uzyskać uprawnienia WRITE_SETTINGS

85

Kiedy mam docelowy interfejs API 23 w systemie Android M Preview 3, nie mogę uzyskać uprawnienia Manifest.permission.WRITE_SETTTINGS.

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

Prośba o pozwolenie nie powoduje wyświetlenia okna dialogowego, którego oczekiwałbym, ale jeśli wykonam następujące wywołanie bez tego pozwolenia,

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

Zadzwonię, chyba że nie mam pozwolenia.

Nie wiem, dokąd się stąd udać. Czy istnieje nowy interfejs API dzwonków dla 23? A może ta zmiana uprawnień uniemożliwiła zmianę dzwonka żadnym aplikacjom niesystemowym?

Justin
źródło

Odpowiedzi:

134

Aby użyć WRITE_SETTINGS, na podstawie dokumentów:

  1. Miej <uses-permission>element w manifeście jak zwykle.

  2. Zadzwoń,Settings.System.canWrite() aby sprawdzić, czy możesz zapisać ustawienia.

  3. Jeśli canWrite()powróci false, rozpocznie się w ACTION_MANAGE_WRITE_SETTINGSdziałalność , dzięki czemu użytkownik może zgodzić się tam, aby umożliwić aplikację faktycznie zapisu ustawień.

Innymi słowy, zapisywanie ustawień jest teraz podwójną opcją (zgadzasz się na instalację, zgadzasz się osobno w Ustawieniach, aby zezwolić), podobnie jak interfejsy API administratora urządzenia, usługi ułatwień dostępu itp.

Zauważ też, że nie próbowałem jeszcze ich używać - jest to oparte na badaniach, które przeprowadziłem wczoraj na temat zmian w Androidzie 6.0 .

CommonsWare
źródło
Dzięki Mark! Działał jak urok. developer.android.com/preview/features/runtime-permissions.html wymaga aktualizacji, jeśli będziemy mieć wiele nowych sposobów uzyskiwania uprawnień. (Przeczytałem już twojego bloga przed wysłaniem, ale oczywiście nie zachowałem tej informacji, kiedy jej potrzebowałem)
Justin
To rzeczywiście zadziałało. Ale dla użytkownika końcowego jest to złe podejście. Jakieś oznaki, że Google zmienia to zachowanie?
Fhl
2
@Fhl: Nie wiem, dlaczego poszli tą drogą zamiast zwykłego dangerouspodejścia do uprawnień w czasie wykonywania, z innymi rzeczami w Androidzie 6.0. Zdziwię się, jeśli to się zmieni w najbliższym czasie.
CommonsWare
2
możesz określić swoją aplikację w takim celu:intent.setData(Uri.parse("package:" + Context.getPackageName()));
Olegas Gončarovas
8
Inną rzeczą wartą uwagi jest to, że wydaje się, że w systemie Android jest błąd, który powoduje, że aplikacja, która została wcześniej zainstalowana, w której użytkownik nadał uprawnienia do zapisu w oknie dialogowym opisanym powyżej, w którym przełącznik zostanie umieszczony w pozycji włączonej, ale canWrite zwraca wartość false. Aby metoda canWrite () zwróciła wartość true, użytkownik musi wyłączyć i włączyć ponownie… Widzę to w fazie rozwoju, ale mam nadzieję, że klienci nie zobaczą tego.
Matt Wolfe,
45

Oprócz odpowiedzi z CommonsWare i komentarza Ogix, oto trochę fałszywego kodu:

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

Fragment PopupwritePermission następnie wyświetla okno, w którym wyjaśniono sytuację. Kliknięcie przycisku OK spowoduje otwarcie menu systemu Android, w którym można udzielić pozwolenia:

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

Poprzednie odpowiedzi są świetne, mam tylko niewielki dodatek do uzyskania wyniku również za prośbą o pozwolenie.

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

A potem w 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
źródło
Umieściłem twój kod i działa dobrze, nawet przyznane pozwolenie, ale nadal niestandardowy dzwonek nie jest przypisywany i nadal ma odmowę uprawnienia Write_Setting.
Zia Ur Rahman
4
ActivityCompat.requestPermissions (kontekst, nowy ciąg [] {Manifest.permission.WRITE_SETTINGS}, ....); nie może być użyty. To specjalne pozwolenie. Możemy poprosić o to pozwolenie tylko z zamiarem określonym w dokumentacji. Również przed Marshmello zezwolenie jest udzielane na stałe w czasie instalacji
Anonimowy
2
@yshahak jaka jest twoja zmienna MainActivity.CODE_WRITE_SETTINGS_PERMISSION?
Bruno Bieri
@BrunoBieri tak, masz rację, pominąłem to. Zmienię odpowiedź, aby była pełna.
yshahak
Więc o co chodzi MainActivity.CODE_WRITE_SETTINGS_PERMISSION?
Przedziały
12

Oto kompletny przykład:

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
źródło
intent.setData (Uri.parse ("pakiet:" + getActivity (). getPackageName ()));
Ole K
7

Począwszy od Androida Marshmellow, musisz używać uprawnień uruchomieniowych, które mają na celu większe bezpieczeństwo, lub używać uprawnień, gdy jest to potrzebne, tutaj jest dokumentacja

a dokumentacja ustawień zapisu jest tutaj

W manifeście dodaj

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

W Twojej klasie

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

I używaj tego w ten sposób

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
źródło
5

Uprawnienie android.permission.WRITE_SETTINGSjest teraz w grupie signature|appop|pre23|preinstalledjak android.permission.CHANGE_NETWORK_STATEiandroid.permission.SYSTEM_ALERT_WINDOW

Oznacza to, że otrzymujesz go na SDK 22 i niższych. W nowszej wersji musisz być operatorem aplikacji.

passsy
źródło
4

Użyłem poniżej jak ...

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

Wyraźne pozwolenie

<uses-permission  android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions" />
Enamul Haque
źródło
2

Wspomnij poniżej uprawnienia w AndroidManifest.xml

W aktywności użyj poniżej, jeśli inaczej, do zmiany ustawienia.

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
źródło
Skorzystaj z tego uprawnienia. <uses-Permissions android: name = "android.permission.WRITE_SETTINGS" />
Sourabh Tejraj,
1

Kotlin Version in Simple Steps

Wykonaj następujące kroki:

1. Dodaj element użytkowania uprawnienia w manifest.xmlnormalnie:

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

2. Tam, gdzie chcesz zmienić ustawienia, sprawdź uprawnienia do zapisu:

if (context.canWriteSettings) {
    // change the settings here ...
} else {
    startManageWriteSettingsPermission()
}

3. Dodaj również te linie kodu w przypadku prośby o pozwolenie:

private fun startManageWriteSettingsPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Intent(
            Settings.ACTION_MANAGE_WRITE_SETTINGS,
            Uri.parse("package:${context.packageName}")
        ).let {
            startActivityForResult(it, REQUEST_CODE_WRITE_SETTINGS_PERMISSION)
        }
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    when (requestCode) {
        REQUEST_CODE_WRITE_SETTINGS_PERMISSION -> {
            if (context.canWriteSettings) {
                // change the settings here ...
            } else {
                Toast.makeText(context, "Write settings permission is not granted!", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

val Context.canWriteSettings: Boolean
    get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.System.canWrite(this)

companion object {
    private const val REQUEST_CODE_WRITE_SETTINGS_PERMISSION = 5
}
aminografia
źródło