web-dev-qa-db-fra.com

Android - Impossible d'ouvrir le contenu: fichier: /// stockage / émulé / 0

J'ai un widget avec un fond d'image à neuf patchs. L'image a été enregistrée dans/sdcard/mydir/bgs.

Lorsque j'essaie de charger une image avec la méthode setImageViewUri, j'ai cette erreur:

Unable to open content: file:///storage/emulated/0/sdcard/mydir/bgs

..

puis

...

open failed: EACCES (Permission denied)

Cela n'apparaît que sur l'écran d'accueil et uniquement avec Nexus 10 et Nexus 7 (avec le dernier lanceur 4.4, ce bug n'existe pas). J'ai également quelques RemoteViews sur mon application et tout fonctionne correctement.

J'ai également ajouté au manifeste soit READ_EXTERNAL_STORAGE, soit WRITE_EXTERNAL_STORAGE.

Comment puis-je résoudre?

MISE À JOUR: J'ai inspecté la méthode setImageViewUri et j'ai constaté qu'elle modifiait le chemin de mon fichier.

if (value != null) {
            // Resolve any filesystem path before sending remotely
            value = value.getCanonicalUri();
            if (StrictMode.vmFileUriExposureEnabled()) {
                value.checkFileUriExposed("RemoteViews.setUri()");
            }
        }

Cette méthode reçoit ma valeur (/ sdcard/mydir/bgs) et la transforme en (stockage/émulé/0/sdcard/mydir/bgs). Mais ce fichier n'existe pas dans le système via adb.

15
CeccoCQ

Il semble que setImageViewUri ne soit plus sûr à utiliser avec file: // uris.

Pourquoi?

Jellybean a présenté le READ_EXTERNAL_STORAGE autorisation. Les applications qui souhaitent lire à partir du stockage externe doivent détenir cette autorisation. Ce n'était pas appliqué par défaut jusqu'à KitKat.

Le lanceur ne détient pas cette autorisation. En fait, vous n'êtes pas assuré que les RemoteView auxquels vous attachez détiennent cette autorisation. Cela rend l'utilisation de setImageViewUri dangereuse, car vous ne savez pas si la vue d'image distante pourra même lire l'uri donné.

Et maintenant?

Option 1: utilisez setImageViewBitmap.

Vous avez peut-être abandonné cette option en raison de l'échec des transactions de classeur. L'astuce est de s'assurer que votre image est inférieure à 1 Mo. Ce n'est pas aussi difficile qu'il y paraît. Vous pouvez calculer exactement la taille de votre image. Par exemple, si vous utilisez une image ARGB_8888, cela signifie que vous aurez besoin de 4 octets par pixel. Nous pouvons calculer la taille maximale en:

1 Mo = 1048576 octets = 262144 pixels = 512 x 512 image

Bien sûr, vous pouvez en tirer plus en utilisant RGB_565 pour obtenir 2x les pixels.

Notez également que vous n'avez peut-être pas besoin d'une image énorme si votre widget est petit. Votre application peut poser des questions sur ses options spécifiques de la manière suivante:

Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetIds[i]);

int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);

int maxWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
int maxHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);

Sachez simplement que les valeurs renvoyées sont en dip et non en pixels, vous devrez donc les convertir pour mettre à l'échelle votre bitmap.

Option 2: utilisez un fournisseur de contenu

Si pour une raison quelconque, vous n'aimez toujours pas la restriction IPC, vous pouvez toujours créer un fournisseur de contenu personnalisé. Transmettez cet uri dans setImageViewUri, et vous devriez être prêt à partir.

Qu'en est-il du commutateur de chemin?

Le changement de chemin n'est pas le vrai problème. Il semble que ce soit un problème, mais l'émulation fonctionne bien. Essayez de créer un fichier dans //storage/emulated/0/sdcard/mydir/bgs et le fichier se créera très bien.

Vous remarquerez que bien que l'exception soit une FileNotFoundException, le message est Autorisation refusée.

6
Grimmace

À partir de Lollipop, Google a introduit une nouvelle façon de donner explicitement aux applications l'autorisation que vous souhaitez qu'elles utilisent sur votre appareil et de désactiver celles que vous souhaitez refuser. Si vous remarquez, dans votre Android, le journal affiche

Java.io.FileNotFoundException: /storage/emulated/0/advert.mp4: open failed: EACCES (Permission denied)

EACCESS permission denied est la cause de l'infâme FileNotFoundException de Java.

Pour résoudre ce problème, accédez simplement à votre autorisation d'application et activez le stockage pour votre application

enter image description here

17
toniton

Vous avez besoin

<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE" />

dans votre manifeste.

12
Kuffs

Je pense que vous entrez manuellement le chemin de la carte SD. Au lieu d'entrer manuellement le chemin de la carte SD, vous devriez obtenir un chemin de stockage comme celui-ci:

File extStore = Environment.getExternalStorageDirectory();
String mPath = extStore.getAbsolutePath() + "/mydir/bgs";
0
Vipul Purohit