23

riguarda il nuovo modello di runtime permissions introduced in Android Marshmallow quando si richiede l'autorizzazione Manifest.permission.WRITE_EXTERNAL_STORAGE.Richiedere e autorizzare il permesso WRITE_EXTERNAL_STORAGE in fase di runtime non ha alcun effetto sulla sessione corrente

In breve, quello che sto vivendo è che se chiedo (e l'utente lo consente) Manifest.permission.WRITE_EXTERNAL_STORAGE il permesso, l'applicazione non sarà in grado di leggere e scrivere dalla directory di archiviazione esterna fino distruggo e riavviare l'applicazione .

Questo è quello che sto facendo/sperimentando:

mia app parte da uno stato in cui:

ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED 

Questo è, non ho i permessi per accedere a storage esterno.

Poi, chiedo il permesso di Manifest.permission.WRITE_EXTERNAL_STORAGE proprio come Google spiega

private void requestWriteExternalStoragePermission() { 
    // Should we show an explanation? 
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { 
     new AlertDialog.Builder(this) 
       .setTitle("Inform and request") 
       .setMessage("You need to enable permissions, bla bla bla") 
       .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { 
        @Override 
        public void onClick(DialogInterface dialog, int which) { 
         ActivityCompat.requestPermissions(MendeleyActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_PERMISSION_WRITE_EXTERNAL_STORAGE); 
        } 
       }) 
       .show(); 
    } else { 
     ActivityCompat.requestPermissions(MendeleyActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_PERMISSION_WRITE_EXTERNAL_STORAGE); 
    } 
} 

Una volta che l'utente consente il permesso, onRequestPermissionsResult viene invocata.

@Override 
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { 
    switch (requestCode) { 
     case RC_PERMISSION_WRITE_EXTERNAL_STORAGE: { 
      // If request is cancelled, the result arrays are empty. 
      if (grantResults.length > 0 && PackageManager.PERMISSION_GRANTED 
       // allowed 
      } else { 
       // denied 
      } 
      break; 
     } 
    } 
} 

Il allowed blocco viene eseguito, confermando che l'utente ha concesso i permessi.

Immediatamente dopo questo, se non distruggo e apro di nuovo l'app, non ho ancora nessun permesso di accesso all'archiviazione esterna. Più in particolare:

hasWriteExternalStoragePermission();     // returns true 
Environment.getExternalStorageDirectory().canRead(); // RETURNS FALSE!! 
Environment.getExternalStorageDirectory().canWrite(); // RETURNS FALSE!! 

Così, sembra che il tempo di esecuzione Android pensa che ho i permessi, ma il file system non ... Infatti, nel tentativo di accedere Environment.getExternalStorageDirectory() genera l'eccezione:

android.system.ErrnoException: open failed: EACCES (Permission denied) 
at libcore.io.Posix.open(Native Method) 
at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186) 
at libcore.io.IoBridge.open(IoBridge.java:438) 
at java.io.FileOutputStream.<init>(FileOutputStream.java:87)  
at java.io.FileOutputStream.<init>(FileOutputStream.java:72)  

Se ora distruggo l'app e la apri di nuovo, il comportamento diventa come dovrebbe, potendo leggere e scrivere nella cartella di archiviazione esterna.

Qualcuno sta vivendo questo?

Sto usando emulatore un funzionario con:

  • più recenti di Android 6.0 (API 23) API 23, Rev 1.
  • emulatore in esecuzione Intel x86 Atom immagine del sistema, API 23, Rev 1.

ho costruire l'applicazione con:

android { 
    compileSdkVersion 23 
    buildToolsVersion "22.0.1" 

    defaultConfig { 
     minSdkVersion 16 
     targetSdkVersion 23 
    } 
... 
} 

Se qualcuno lo conferma e io non sono l'unico su e immagino che avremo bisogno di aprire un bug, ma spero di fare qualcosa di sbagliato, poiché penso che una tale caratteristica di base sia improbabile che possa contenere errori nell'SDK.

+2

"Qualcuno sta vivendo questo?" - Non lo sono, ma non l'ho provato su un emulatore. Ho usato l'hardware. – CommonsWare

+0

Quindi è probabile che sia solo sull'emulatore ... Aggiornerò una volta ricevuto l'aggiornamento di Android M. – GaRRaPeTa

+1

https://code.google.com/p/android-developer-preview/issues/detail?id=2982 – greywolf82

risposta

7

http://developer.android.com/reference/android/Manifest.permission.html#WRITE_EXTERNAL_STORAGE:

A partire dal livello di API 19, questa autorizzazione non è necessario per leggere/scrivere file nelle directory specifiche dell'applicazione restituiti da getExternalFilesDir (String) e getExternalCacheDir().

"permesso Runtime chiedendo" inizia a livello di API 23, ovviamente al di sopra 19, in modo che il consenso non è richiesto più, a meno che non si sta accedendo ai dati al di fuori della cartella puntato da getExternalFilesDir(). Quindi credo che questo sia un bug dell'emulatore.

Su obiettivi inferiori al livello 19, che non supportano il permesso di richiesta in fase di esecuzione, è sufficiente calibrare l'autorizzazione in manifest e funzionerà.

+0

Questa è solo la metà della verità. Sfortunatamente alcuni dispositivi su Lollipop richiedono ancora le autorizzazioni specifiche, quindi dovresti evitare di rimuovere l'autorizzazione al livello API 19 o superiore (l'ho fatto e ora devo reintrodurlo). Vedi http://stackoverflow.com/questions/27016647/why-do-i-need-the-write-external-storage-permission-with-getexternalcachedir-o?sgp=2 – sven

+0

@sven true.Ma secondo il documento, lo considero ancora un bug, anche se sto richiedendo il permesso di archiviazione in pratica. – crazii

+0

@crazil: 100% d'accordo. Basta solo tenerlo presente per evitare che altri sviluppatori rimuovano il permesso solo per riconoscere che dovranno aggiungerlo di nuovo ... – sven

4

Ho avuto lo stesso problema. Risulta che questo sembra essere un problema più grande. Cambiando il permesso di scrivere nella memoria esterna cambia il GID per questo processo (sul lato linux). Per modificare l'ID è necessario riavviare il processo. La prossima volta che apri l'app, viene impostato il nuovo groupID e l'autorizzazione è concessa.

Per farla breve, ho paura questo non è un bug nell'emulatore ma in realtà un problema più grande con Linux e Android.

I "risolto" questo chiedendo il permesso la prima volta che si esegue l'applicazione e riavviandolo quando il permesso è dato in questo modo:

PackageManager packageManager = getPackageManager(); 
        Intent intent = packageManager.getLaunchIntentForPackage(getPackageName()); 
        ComponentName componentName = intent.getComponent(); 
        Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName); 
        startActivity(mainIntent); 
        System.exit(0); 

si può tentare di creare un servizio in esecuzione in background (avendo un altro id di processo) e dandogli il permesso. In questo modo dovrai solo riavviare il servizio e non l'app completa. Dal lato negativo questo potrebbe rendere più lavoro per voi.

Spero che questo aiuti.

--- EDIT ---

L'utente M66B (https://stackoverflow.com/a/32473449/1565635) hanno trovato un elenco dei relativi gid. Ulteriori informazioni possono essere trovate qui: https://android.googlesource.com/platform/frameworks/base/+/master/data/etc/platform.xml

+0

Sì, credo che questo funzioni e dovrebbe essere accettato risposta – user755499

+0

Felice di sentirlo! :) –

+1

Fornire un progetto di esempio che dimostri questo problema. Quindi, considera [archiviare un problema] (http://b.android.com). Non vedo alcun problema legato a questo problema e non ho mai visto questo comportamento in un numero ragionevole di app. Se il problema è limitato a 'canRead()'/'canWrite()', posso vedere che forse c'è un problema. Ma, in realtà, per leggere e scrivere, non è necessario riavviare il processo per avere l'autorizzazione concessa. – CommonsWare

Problemi correlati