Demander et autoriser la permission de stockage externe en écriture à l'exécution n'a aucun effet sur la session en cours

ceci concerne le nouveau modèle de permissions runtime introduites dans Android Marshmallow quand on demande Manifest.permission.WRITE_EXTERNAL_STORAGE permission.

En bref, ce que j'éprouve, c'est que si je demande (et l'utilisateur) Manifest.permission.WRITE_EXTERNAL_STORAGE l'autorisation, l'application ne sera pas en mesure de lire et d'écrire à partir de l'appareil de stockage externe répertoire jusqu'à ce que je détruise et redémarre l'application.

C'est ce que je fais/expérience:

mon application part d'un l'état où:

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

C'est, je n'ai pas les autorisations d'accès de stockage externe.

alors, je demande la permission de manifester.autorisation.WRITE_EXTERNAL_STORAGE tout comme Google explique

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

une fois que l'Utilisateur autorise la permission,onRequestPermissionsResult est appelé.

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

allowed le bloc est exécuté, confirmant que l'Utilisateur a accordé les permissions.

après cela, si Je ne détruis pas et ouvrez l'application à nouveau, je n'ai toujours pas la permission d'accès au stockage externe. Plus précisément:

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

il semble donc que L'exécution Android pense que j'ai des permissions, mais pas le système de fichiers... En effet, en essayant d'accéder à Environment.getExternalStorageDirectory() lance l'exception:

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) 

Si j'ai maintenant détruire l'application et l'ouvrir à nouveau, le comportement devient comme il se doit, être capable de lire et d'écrire dans le stockage externe dossier.

Est ce que quelqu'un l'expérience de cette?

j'utilise un émulateur officiel avec:

  • dernière version D'Android 6.0 (API 23) API 23, Rev 1.
  • émulateur tournant Intel x86 Atom System Image, API 23, Rev 1.

je construis l'application avec:

android {
    compileSdkVersion 23
    buildToolsVersion "22.0.1"

    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 23
    }
...
}

si quelqu'un le confirme et que je ne suis pas le seul, je suppose que nous aurons besoin d'ouvrir un bug, mais j'espère que je fais quelque chose de mal, car je pense qu'une telle fonctionnalité de base est peu susceptible d'être boguée dans le SDK.

24
demandé sur GaRRaPeTa 2015-10-05 14:35:38

2 réponses

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

à partir du niveau 19 de L'API, Cette permission n'est pas nécessaire pour lire/écrire des fichiers dans vos répertoires spécifiques à l'application retournés par getExternalFilesDir(String) et getExternalCacheDir().

"Runtime permission requesting" commence au niveau de L'API 23, évidemment au-dessus de 19, donc la permission n'est plus nécessaire, sauf si vous êtes accéder aux données à l'extérieur du dossier pointé par getExternalFilesDir(). Donc, je crois que c'est un bug de l'émulateur.

sur les cibles inférieures en dessous du niveau 19, qui ne supportent pas la demande de permission à l'exécution, il suffit de caler la permission dans le manifeste et ça marchera.

7
répondu crazii 2015-10-22 04:02:54

j'ai eu le même problème. Il s'avère que ça semble être un plus gros problème. Changer la permission d'écrire sur le stockage externe change le GID pour ce processus (du côté linux). Afin de changer l'ID du processus doit être redémarré. La prochaine fois que vous ouvrez l'application, le nouvel ID groupe est défini et la permission est accordée.

pour faire court, j'ai bien peur ce n'est pas un bug dans l'émulateur, mais en fait un gros problème avec Linux et Android.

je "résolu" en demandant la permission de la première fois que l'application est exécutée et le redémarre lorsque l'autorisation est donnée comme ceci:

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

Vous pouvez essayer de créer un service courant en arrière-plan (ayant un autre identifiant de processus) et lui donner la permission. De cette façon, vous auriez seulement besoin de redémarrer le service et non l'application complète. Du côté négatif, cela pourrait faire plus de travail pour vous.

Espérons que cette aide.

--- modifier ---

l'utilisateur M66B (https://stackoverflow.com/a/32473449/1565635) a trouvé une liste des gids liés. Vous trouverez plus d'informations ici: https://android.googlesource.com/platform/frameworks/base/+/master/data/etc/platform.xml

5
répondu Tobias Reich 2017-05-23 11:47:27