2013-12-17 4 views
14

Ich habe ein Widget mit neun-Patch-Bildhintergrund. Das Bild wurde in/sdcard/mydir/bgs gespeichert.Android - Inhalt kann nicht geöffnet werden: file: /// storage/emuliert/0

Wenn ich versuche, ein Bild mit setImageViewUri Methode zu laden, habe ich diesen Fehler:

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

..

dann

...

open failed: EACCES (Permission denied) 

Diese erscheint nur auf dem Startbildschirm und nur mit Nexus 10 und Nexus 7 (mit aktuellem Launcher 4.4 ist dieser Fehler nicht möglich existieren). Ich habe auch einige RemoteViews in meiner Anwendung und alles funktioniert korrekt.

Ich habe auch entweder READ_EXTERNAL_STORAGE, entweder WRITE_EXTERNAL_STORAGE in Manifest hinzugefügt.

Wie kann ich lösen?

UPDATE: Ich habe die Methode setImageViewUri untersucht und ich habe festgestellt, dass es den Pfad meiner Datei ändert.

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

Diese Methode mein Wert erhalten (/ sdcard/mydir/BGS) und Veränderungen, die sie in (Lagerung/emulierten/0/sdcard/mydir/BGS). Diese Datei existiert jedoch nicht über adb im System.

+0

Teilen Sie Ihren Code und auch Ihre vollständige Logcat Ausgabe veröffentlichen. –

Antwort

6

Es scheint setImageViewUri nicht mehr sicher ist, mit file: // URIs.

Warum?

Jellybean führte die READ_EXTERNAL_STORAGE Erlaubnis ein. Apps, die aus externem Speicher lesen möchten, müssen diese Berechtigung besitzen. Dies wurde nicht standardmäßig bis KitKat erzwungen.

Der Launcher besitzt diese Berechtigung nicht. Tatsächlich ist nicht garantiert, dass RemoteView, an das Sie anhängen, diese Berechtigung besitzt. Dies macht die Verwendung von setImageViewUri unsicher, da Sie nicht wissen, ob die Remote-Bildansicht überhaupt in der Lage ist, die angegebene URL zu lesen.

Was nun?

Option 1: Verwenden Sie setImageViewBitmap.

Sie haben sich aufgrund fehlgeschlagener Bindertransaktionen möglicherweise von dieser Option entfernt. Der Trick dabei ist, dass das Bild weniger als 1 MB groß ist. Das ist nicht so schwer wie es klingt. Sie können genau berechnen, wie groß Ihr Bild sein wird. Wenn Sie beispielsweise ein ARGB_8888-Image verwenden, benötigen Sie 4 Byte pro Pixel.Wir können die maximale Größe calulate von:

1 Mb = 1048576 bytes = 262144 pixels = 512 x 512 image

Natürlich können Sie mehr auspressen davon RGB_565 unter Verwendung der Pixel zu erhalten 2x.

Beachten Sie auch, dass Sie möglicherweise kein riesiges Bild benötigen, wenn Ihr Widget klein ist. Ihre appwidget kann durch die folgende über seine spezifische Optionen fragen:

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

Seien Sie sich bewusst sein, dass die zurückgegebenen Werte in dip sind nicht Pixel, so dass Sie sie benötigen, um konvertieren Sie Ihre Bitmap zu skalieren.

Option 2: Inhaltsanbieter

Verwenden Sie aus irgendeinem Grund Wenn Sie weiterhin die IPC Einschränkung nicht mögen, können Sie immer einen benutzerdefinierten Content-Provider bauen. Übergeben Sie dieses URI in setImageViewUri, und Sie sollten gut gehen.

Was ist mit dem Pfadschalter?

Der Pfadwechsel ist nicht das eigentliche Problem. Es scheint, dass es ein Problem ist, aber die Emulation funktioniert eigentlich gut. Versuchen Sie, eine Datei innerhalb //storage/emulated/0/sdcard/mydir/bgs zu erstellen, und die Datei wird problemlos erstellt.

Sie werden bemerken, dass während der Ausnahme eine FileNotFoundException die Nachricht Permission Denied ist.

10

Sie benötigen

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

in Ihrem Manifest.

+1

Ich habe es hinzugefügt. Entweder READ- und WRITE-Berechtigung. – CeccoCQ

0

Ich denke, dass Sie den SD-Kartenpfad manuell eingeben. Anstatt manuell SD Card Pfad eingeben, sollten Sie Speicherpfade wie diese:

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

Überprüfen Sie meine letzte Änderung. Vielen Dank. – CeccoCQ

14

Ab Lollipop hat Google eine neue Möglichkeit eingeführt, Apps ausdrücklich die Berechtigung zu erteilen, die sie auf Ihrem Gerät verwenden dürfen, und die Apps zu deaktivieren, denen Sie die App verweigern möchten. Wenn Sie feststellen, in Ihrem Android-Monitor zeigt das Protokoll

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

EACCESS permission denied die Ursache des berüchtigten FileNotFoundException Java ist.

Um dies zu lösen, nur lese Ihre App Erlaubnis und ermöglichen Speicher für Ihre App

enter image description here

+0

Also standardmäßig sind alle Berechtigungen deaktiviert ?? Der Benutzer muss bei jeder Installation einer App alles aktivieren? Ich habe das nie auf meinem Telefon (Version 6.0.1) getan ... – Matt

+0

Bitte tun Sie dies nicht auf einer freigegebenen App. Ihre Benutzer werden Ihnen nicht danken. Sie sollten stattdessen zur Laufzeit in Ihrer App eine Berechtigung anfordern. https://developer.android.com/training/permissions/request.html – Kuffs