Impossibile ottenere l'autorizzazione WRITE_SETTINGS


85

Quando ho un'API di destinazione di 23 su Android M Preview 3, non riesco ad acquisire l'autorizzazione Manifest.permission.WRITE_SETTTINGS.

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

La richiesta di autorizzazione non fa apparire la finestra di dialogo che mi sarei aspettato, ma se effettuo la seguente chiamata senza questa autorizzazione,

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

La chiamata sarà tranne perché non ho il permesso.

Non sono sicuro di dove andare da qui. Esiste una nuova API per suonerie per 23? O questa modifica dell'autorizzazione ha reso impossibile per le app non di sistema cambiare la suoneria?

Risposte:


134

Da utilizzare WRITE_SETTINGS, in base ai documenti:

  1. Avere l' <uses-permission>elemento nel file manifest normalmente.

  2. ChiamaSettings.System.canWrite() per vedere se sei idoneo a scrivere le impostazioni.

  3. Se canWrite()ritorna false, avvia l' ACTION_MANAGE_WRITE_SETTINGSattività in modo che l'utente possa accettare di consentire alla tua app di scrivere effettivamente nelle impostazioni.

In altre parole, la scrittura nelle impostazioni è ora un doppio opt-in (accetta di installare, accetta separatamente in Impostazioni per consentire), simile alle API di amministrazione del dispositivo, ai servizi di accessibilità, ecc.

Si noti inoltre che non ho ancora provato a utilizzarli: questo si basa sulla ricerca che ho fatto ieri sulle modifiche di Android 6.0 .


Grazie Mark! Ha funzionato come un fascino. developer.android.com/preview/features/runtime-permissions.html necessita di alcuni aggiornamenti se avremo più nuovi modi per richiedere le autorizzazioni. (Avevo già letto il tuo blog prima di postare, ma ovviamente non ho conservato quell'informazione quando ne avevo bisogno)
Justin

Questo ha funzionato, davvero. Ma per l'utente finale questo è un cattivo approccio. Qualche segno che Google abbia cambiato questo comportamento?
Fhl

2
@Fhl: non so perché hanno seguito questa strada invece del normale dangerousapproccio di autorizzazione di runtime che hanno seguito con altre cose in Android 6.0. Sarò sorpreso se questo cambierà presto.
CommonsWare

2
puoi specificare la tua app nell'intento in questo modo:intent.setData(Uri.parse("package:" + Context.getPackageName()));
Olegas Gončarovas

8
Un'altra cosa da notare è che sembra esserci un bug in Android che causa un'app precedentemente installata in cui l'utente ha fornito i permessi di scrittura nella finestra di dialogo sopra descritta, dove l'interruttore a levetta verrà messo nella posizione abilitata ma canWrite restituisce false .. Per fare in modo che il metodo canWrite () restituisca true, l'utente deve disattivare e riattivare l'interruttore ... Lo vedo in fase di sviluppo ma si spera che non sia qualcosa che i clienti vedono.
Matt Wolfe

45

Oltre alla risposta di CommonsWare e al commento di Ogix, ecco del codice fittizio:

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

Il Fragment PopupwritePermission fornisce quindi una finestra in cui viene spiegata la situazione. Un clic sul pulsante OK aprirà il menu di sistema Android in cui è possibile concedere l'autorizzazione:

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

40

Le risposte precedenti sono ottime, ho solo una piccola aggiunta per ottenere anche il risultato per la richiesta di autorizzazione.

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

E poi nel 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
        }
    }

Ho inserito il tuo codice e funziona bene, anche l'autorizzazione concessa, ma la suoneria personalizzata non è ancora assegnata e ho ancora l'autorizzazione Write_Setting negata.
Zia Ur Rahman

4
ActivityCompat.requestPermissions (context, new String [] {Manifest.permission.WRITE_SETTINGS}, ....); non può essere usato. È un permesso speciale. Possiamo solo richiedere questa autorizzazione con un intento come detto nella documentazione. Anche prima di Marshmello l'autorizzazione viene concessa in modo permanente al momento dell'installazione
Anonimo

2
@yshahak qual è la tua variabile MainActivity.CODE_WRITE_SETTINGS_PERMISSION?
Bruno Bieri

@BrunoBieri si hai ragione, l'ho omesso. Modificherò la mia risposta in modo che sia dettagliata.
yshahak

Allora cosa MainActivity.CODE_WRITE_SETTINGS_PERMISSION?
Brackets

13

Questo è un esempio completo:

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 ("package:" + getActivity (). getPackageName ()));
Ole K

8

A partire da Android Marshmellow, è necessario utilizzare le autorizzazioni di runtime che mirano a una maggiore sicurezza o utilizzare l'autorizzazione quando necessario, ecco la documentazione

e per la documentazione sulle impostazioni di scrittura è disponibile qui

In manifest aggiungi

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

Nella tua classe

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

E usalo in questo modo

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

L'autorizzazione android.permission.WRITE_SETTINGSè ora nel gruppo signature|appop|pre23|preinstalledcome android.permission.CHANGE_NETWORK_STATEeandroid.permission.SYSTEM_ALERT_WINDOW

Ciò significa che lo ottieni su SDK 22 e inferiori. Nella versione più recente devi essere un operatore dell'app.


4

Ho usato muggito come ..

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

Autorizzazione manifest

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

2

Menzione sotto l'autorizzazione in AndroidManifest.xml

In Attività utilizzare di seguito se altro per modificare l'impostazione.

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

Si prega di utilizzare questa autorizzazione. <uses-permission android: name = "android.permission.WRITE_SETTINGS" />
Sourabh Tejraj,

1

Kotlin Version in Simple Steps

Segui questi passi:

1. Aggiungi l'elemento di utilizzo dell'autorizzazione manifest.xmlnormalmente:

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

2. Nel punto in cui desideri modificare le impostazioni, controlla l'accesso in scrittura:

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

3. Aggiungi anche queste righe di codice in caso di richiesta di autorizzazione:

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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.