8
votes

Android 9. + API 29: /storage/emulated/0/Pictures/myPic.png ouvert a échoué: EACCES (autorisation refusée)

J'essaie le code source d'une application de caméra très basique sur Android Studio 3.4.1 avec l'API Android Virtual Device (AVD) Nexus 7 (2012) 29. J'ai pris une photo avec la caméra dans l'émulateur et j'ai essayé de l'enregistrer sous / storage / emulated / 0 / Pictures / myPic.png, mais a obtenu une exception de /storage/emulated/0/Pictures/myPic.png open failed: EACCES (Permission Denied). J'ai essayé tous les conseils disponibles en ligne, par exemple:

  1. Dans AndroidManifest.xml, j'ai ajouté:
outStream = new FileOutputStream(file);

  1. Dans MainActivity.java, j'ai ajouté la vérification d'autorisation d'exécution suivante et le code de demande:
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        verifyStoragePermissions(this);


......


private void saveImageToFile(File file)
    {
        if (mCameraBitmap != null)
        {
            FileOutputStream outStream = null;

            verifyStoragePermissions(this);

            try
            {
                outStream = new FileOutputStream(file);

                ...

            }
            catch (Exception e)
            {
                Toast toastException = Toast.makeText(MainActivity.this,
                        "Exception: " + e.getMessage(),
                        Toast.LENGTH_SHORT);
                LinearLayout toastLayoutException = (LinearLayout) toastException.getView();
                TextView toastTVException = (TextView) toastLayoutException.getChildAt(0);
                toastTVException.setTextSize(30);
                toastException.show();
            }

...

  1. Je vérifie et demande ensuite l'autorisation à la fois dans onCreate et juste avant de vouloir enregistrer l'image comme suit:
public class MainActivity extends Activity {

    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    public static void verifyStoragePermissions(Activity activity) {
        int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

        boolean checkPermission = (permission == PackageManager.PERMISSION_GRANTED);

        Toast toastPermission = Toast.makeText(activity,
                "Is permission granted? " + checkPermission,
                Toast.LENGTH_SHORT);
        LinearLayout toastLayoutPermission = (LinearLayout) toastPermission.getView();
        TextView toastTVPermission = (TextView) toastLayoutPermission.getChildAt(0);
        toastTVPermission.setTextSize(30);
        toastPermission.show();


        if (permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                    activity,
                    PERMISSIONS_STORAGE,
                    REQUEST_EXTERNAL_STORAGE
            );
        }
    }

  1. J'ai également vérifié manuellement l'autorisation de stockage dans l'émulateur pour m'assurer que l'accès au stockage était autorisé.

Cependant, AUCUN des conseils ne fonctionne!

Le code a jeté une exception de

/storage/emulated/0/Pictures/myPic.png open a échoué: EACCES (Autorisation refusée)

quand il a atteint la ligne de

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Une idée pour résoudre ce problème davantage? Merci beaucoup.


0 commentaires

6 Réponses :


1
votes

J'ai finalement compris que le problème résidait dans l'API Android 29, une fois que je suis passé à l'API 28, plus aucun problème d'autorisation.


2 commentaires

Merci, cela a résolu le problème pour moi. Travaillait sur l'API 29 et peu importe ce que j'ai essayé, j'ai continué à avoir le même problème. La mise à niveau vers l'API 28 l'a corrigé


La rétrogradation retarde simplement le problème, ajoutez plutôt android: requestLegacyExternalStorage = "true" à votre manifeste Android, voir la réponse ci-dessus



15
votes

L'ajout d' android: requestLegacyExternalStorage = "true" au manifeste Android a fonctionné pour moi avec Android 29

<application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:requestLegacyExternalStorage="true" ...


0 commentaires

3
votes

J'ai également eu cette erreur dans mon projet.

Je l'ai corrigé en ajoutant

android:requestLegacyExternalStorage="true"

dans le fichier manifestes. (vois ici)


0 commentaires

4
votes

J'ai également essayé d'utiliser un appareil photo et d'enregistrer la photo sur ImageView et j'ai eu des problèmes avec les autorisations. J'ai changé l'API de 29 à 28 - je n'ai pas aidé, ajoutez

File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);

n'a pas aidé. J'ai changé la méthode que j'ai utilisée pour créer un fichier pour stocker l'image à partir de:

File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

à:

android:requestLegacyExternalStorage="true"

Et le problème est parti. BTW je ne sais pas pourquoi. Peut-être parce que le premier était obsolète.


0 commentaires

5
votes

Votre problème est dû à l'introduction du stockage scoped dans l'API 29. Vous avez trois solutions au problème (certaines ont déjà été mentionnées, mais j'ai pensé que cela aiderait à clarifier et à consolider):

  1. N'exécutez votre application que sur les appareils exécutant l'API 28 ou version antérieure.

  2. Ajoutez android:requestLegacyExternalStorage="true" à AndroidManifest.xml afin que votre application puisse s'exécuter sur l'API 29 et au-dessus:

    <application android: requestLegacyExternalStorage = "true" ...

  3. Modernisez votre application pour l'API 29+. Commencez par vous débarrasser des autorisations WRITE_EXTERNAL_STORAGE. Et remplacez l'appel à Environment.getExternalStoragePublicDirectory() getExternalFilesDir() par getExternalFilesDir() , qui enregistrera votre image sur un stockage externe mais dans un répertoire auquel votre application pourra accéder.

Vous trouverez ci-dessous une méthode pour enregistrer un Bitmap au format JPG à l'aide du MediaStore, qui permet à d'autres applications d'accéder à l'image:

private void saveImage(Bitmap bitmap) throws IOException {
    ContentValues contentValues = new ContentValues();
    contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "myImage.jpg");
    contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
    contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);

    ContentResolver resolver = getContentResolver();
    Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
    OutputStream imageOutStream = null;

    try {
        if (uri == null) {
            throw new IOException("Failed to insert MediaStore row");
        }

        imageOutStream = resolver.openOutputStream(uri);
        if (!bitmap.compress(Bitmap.CompressFormat.JPEG, 100, imageOutStream)) {
            throw new IOException("Failed to compress bitmap");
        }
    }
    finally {
        if (imageOutStream != null) {
            imageOutStream.close();
        }
    }
}


0 commentaires

0
votes

ajoutez android:requestLegacyExternalStorage="true" à votre manifeste Android

<manifest ... >  
<application android:requestLegacyExternalStorage="true" ... />
</manifest>

la raison de cela, vous pouvez lire à https://medium.com/@sriramaripirala/android-10-open-failed-eacces-permission-denied-da8b630a89df


0 commentaires