Не вдається отримати дозвіл WRITE_SETTINGS


85

Коли у мене є цільовий API 23 на Android M Preview 3, я не можу отримати дозвіл Manifest.permission.WRITE_SETTTINGS.

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

Запит дозволу не відкриває діалогове вікно, яке я очікував би, але якщо я здійсню наступний виклик без цього дозволу,

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

Дзвінок буде за винятком того, що я не маю дозволу.

Я не впевнений, куди звідси йти. Чи є новий API дзвінка для 23? Або цей дозвіл просто змінив мелодію дзвінка для будь-яких несистемних програм?

Відповіді:


134

Для використання WRITE_SETTINGS, виходячи з документів:

  1. Розмістіть <uses-permission>елемент у маніфесті як звичайний.

  2. Зателефонуйте,Settings.System.canWrite() щоб перевірити, чи ви маєте право виписувати налаштування.

  3. Якщо canWrite()повертається false, запуск на ACTION_MANAGE_WRITE_SETTINGSактивність , так що користувач може домовитися там , щоб ваше додаток насправді писати настройки.

Іншими словами, запис у налаштування тепер є подвійним вибором (погодьтеся встановити, погодьтеся окремо в налаштуваннях, щоб дозволити), подібним до API адміністратора пристрою, служб доступності тощо

Також зауважте, що я ще не пробував використовувати їх - це базується на дослідженні, яке я зробив учора щодо змін в Android 6.0 .


Дякую Марк! Працював як оберіг. developer.android.com/preview/features/runtime-permissions.html потребує певного оновлення, якщо ми будемо мати кілька нових способів запитувати дозволи. (Я вже читав ваш блог до публікації, але, очевидно, не зберігав цю інформацію, коли мені це було потрібно)
Джастін,

Це справді спрацювало. Але для кінцевого користувача це поганий підхід. Будь-які ознаки, що Google змінює цю поведінку?
Fhl,

2
@Fhl: Я не знаю, чому вони пішли цим шляхом, а не dangerousпідходом до звичайного дозволу на виконання, який вони застосовували з іншими речами в Android 6.0. Я буду здивований, якщо це скоро зміниться.
CommonsWare

2
Ви можете вказати свій додаток у такому намірі:intent.setData(Uri.parse("package:" + Context.getPackageName()));
Олегас Гончарова,

8
Інша річ, на яку слід звернути увагу, - це те, що в Android, здається, є помилка, яка спричиняє програму, яка раніше була встановлена, де користувач надав дозволи на запис у діалоговому вікні, описаному вище, де тумблер буде встановлено у ввімкнене положення, але canWrite повертає false. Для того, щоб метод canWrite () повернув true, користувач повинен вимкнути та знову увімкнути ... Я бачу це у розробці, але, сподіваюся, це не буде те, що бачать клієнти.
Matt Wolfe

45

На додаток до відповіді від CommonsWare та коментаря від Ogix, тут є кілька фіктивних кодів:

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 дає вікно, де пояснюється ситуація. Натискання кнопки OK відкриває меню системи Android, де можна надати дозвіл:

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

40

Попередні відповіді чудові, у мене є лише невелике доповнення для того, щоб також отримати результат для запиту дозволу.

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

А потім у 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
        }
    }

Я розмістив ваш код, і він працює нормально, навіть наданий дозвіл, але користувацький сигнал дзвінка все-таки не призначається, і все-таки проблема із забороною дозволу Write_Setting заборонена.
Zia Ur Rahman

4
ActivityCompat.requestPermissions (контекст, новий рядок [] {Manifest.permission.WRITE_SETTINGS}, ....); не можна використовувати. Це спеціальний дозвіл. Ми можемо запитувати цей дозвіл лише з наміром, як зазначено в документації. Також до Marshmello дозвіл надається постійно під час встановлення
Анонім

2
@yshahak яка ваша змінна MainActivity.CODE_WRITE_SETTINGS_PERMISSION?
Бруно Бієрі

@BrunoBieri так ти правильно, я це пропустив. Я відредагую свою відповідь, щоб вона була багатослівною.
yshahak

То що MainActivity.CODE_WRITE_SETTINGS_PERMISSION?
Брекети

12

Це повний приклад:

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

intent.setData (Uri.parse ("пакет:" + getActivity (). getPackageName ()));
Ole K

7

Починаючи з android Marshmellow, вам потрібно використовувати дозволи на виконання, які спрямовані на більшу безпеку, або використовувати дозвіл, коли тут потрібно документація

а для Налаштування записів документація тут

У маніфесті додати

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

У вашому класі

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

І використовувати його так

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

5

Дозвіл android.permission.WRITE_SETTINGSтепер у групі, signature|appop|pre23|preinstalledяк android.permission.CHANGE_NETWORK_STATEіandroid.permission.SYSTEM_ALERT_WINDOW

Це означає, що ви отримаєте його на SDK 22 і нижче. У новішій версії ви повинні бути оператором програми.


4

Я використовував нижче, як ..

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

Маніфест дозволу

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

2

Згадайте нижче дозвіл у AndroidManifest.xml

У розділі "Діяльність" використовуйте нижче, якщо не для зміни налаштування.

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

Будь ласка, використовуйте цей дозвіл. <
koristi

1

Kotlin Version in Simple Steps

Виконайте такі дії:

1. Додайте елемент використання дозволу до manifest.xmlзвичайного:

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

2. Там, де ви хочете змінити налаштування, перевірте доступ для запису:

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

3. Також додайте ці рядки коду на випадок запиту дозволу:

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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.