Die App stürzt ab, wenn ich versuche, eine Datei zu öffnen. Es funktioniert unter Android Nougat, aber unter Android Nougat stürzt es ab. Es stürzt nur ab, wenn ich versuche, eine Datei von der SD-Karte zu öffnen, nicht von der Systempartition. Ein Berechtigungsproblem?
Beispielcode:
File file = new File("/storage/emulated/0/test.txt");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "text/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); // Crashes on this line
Log:
android.os.FileUriExposedException: Datei: ///storage/emulated/0/test.txt über Intent.getData () hinaus über die App hinaus verfügbar gemacht
Bearbeiten:
Bei der Ausrichtung auf Android Nougat sind file://
URIs nicht mehr zulässig. Wir sollten content://
stattdessen URIs verwenden. Meine App muss jedoch Dateien in Stammverzeichnissen öffnen. Irgendwelche Ideen?
android
android-file
android-7.0-nougat
Thomas Vos
quelle
quelle
Antworten:
Wenn ja
targetSdkVersion >= 24
, müssen wirFileProvider
class verwenden, um Zugriff auf die bestimmte Datei oder den Ordner zu gewähren, damit diese für andere Apps zugänglich sind. Wir erstellen eine eigene Klasse, die erbtFileProvider
, um sicherzustellen, dass unser FileProvider nicht mit FileProviders in Konflikt steht, die in importierten Abhängigkeiten deklariert sind, wie hier beschrieben .Schritte zum Ersetzen des
file://
URI durch dencontent://
URI:Fügen Sie eine erweiterte Klasse hinzu
FileProvider
Fügen Sie einen FileProvider
<provider>
Tag inAndroidManifest.xml
unter -<application>
Tag. Geben Sie eine eindeutige Berechtigung für dasandroid:authorities
Attribut an, um Konflikte, importierte Abhängigkeiten${applicationId}.provider
und andere häufig verwendete Berechtigungen zu vermeiden .provider_paths.xml
Datei imres/xml
Ordner. Möglicherweise wird ein Ordner zum Erstellen benötigt, wenn er nicht vorhanden ist. Der Inhalt der Datei wird unten angezeigt. Es wird beschrieben, dass wir den Zugriff auf den externen Speicher im Stammordner(path=".")
mit dem Namen external_files freigeben möchten .Der letzte Schritt besteht darin, die folgende Codezeile in zu ändern
zu
Bearbeiten: Wenn Sie beabsichtigen, das System zum Öffnen Ihrer Datei zu veranlassen, müssen Sie möglicherweise die folgende Codezeile hinzufügen:
Bitte beachten Sie, dass der vollständige Code und die Lösung hier erläutert wurden.
quelle
(Build.VERSION.SDK_INT > M)
Zustand ist also nutzlos.FileProvider
sollte nur erweitert werden, wenn Sie eines der Standardverhalten überschreiben möchten, andernfalls verwendenandroid:name="android.support.v4.content.FileProvider"
. Siehe developer.android.com/reference/android/support/v4/content/…Neben der Lösung mit
FileProvider
gibt es noch eine andere Möglichkeit, dies zu umgehen. Einfach gesagtin
Application.onCreate()
. Auf diese Weise ignoriert die VM dieURI
Dateibelichtung.Methode
Aktiviert die Überprüfung der Dateibelichtung. Dies ist auch das Standardverhalten, wenn keine VmPolicy eingerichtet wird.
Ich bin auf ein Problem gestoßen, dass
content://
URI
einige Apps es einfach nicht verstehen können , wenn ich etwas zum Senden verwende. Ein Downgrade dertarget SDK
Version ist nicht zulässig. In diesem Fall ist meine Lösung nützlich.Aktualisieren:
Wie im Kommentar erwähnt, ist StrictMode ein Diagnosetool und sollte für dieses Problem nicht verwendet werden. Als ich diese Antwort vor einem Jahr gepostet habe, können viele Apps nur Datei-Uris empfangen. Sie stürzen gerade ab, als ich versuchte, ihnen eine FileProvider-URL zu senden. Dies ist jetzt in den meisten Apps behoben, daher sollten wir uns für die FileProvider-Lösung entscheiden.
quelle
VmPolicy
.StrictMode.enableDefaults();
, das ich nur in meinen Entwicklungs-Builds ausführe, verhindert, dass dieser Absturz auftritt. Daher habe ich jetzt eine Produktionsanwendung, die abstürzt, aber in der Entwicklung nicht abstürzt. Wenn Sie hier ein Diagnosetool aktivieren, wird ein ernstes Problem verborgen. Vielen Dank an @hqzxzwb, dass Sie mir dabei geholfen haben, dies zu entmystifizieren.Wenn
targetSdkVersion
höher als 24 , wird FileProvider verwendet, um den Zugriff zu gewähren.Erstellen Sie eine XML-Datei (Pfad: res \ xml) provider_paths.xml
Fügen Sie einen Provider in AndroidManifest.xml hinzu
Wenn Sie Androidx verwenden , sollte der FileProvider-Pfad wie folgt lauten:
und ersetzen
zu
Bearbeiten: Während Sie den URI mit einem
Intent
hinzufügen, stellen Sie sicher, dass Sie die folgende Zeile hinzufügen:und du bist gut zu gehen. Ich hoffe es hilft.
quelle
Wenn Ihre App auf API 24+ abzielt und Sie weiterhin file: // intents verwenden möchten / müssen, können Sie die Laufzeitprüfung auf hackige Weise deaktivieren:
Methode
StrictMode.disableDeathOnFileUriExposure
ist versteckt und dokumentiert als:Das Problem ist, dass meine App nicht lahm ist, sondern nicht durch die Verwendung von content: // Intents verkrüppelt werden möchte, die von vielen Apps da draußen nicht verstanden werden. Zum Beispiel bietet das Öffnen einer MP3-Datei mit dem Schema content: // viel weniger Apps als beim Öffnen derselben über das Schema file: //. Ich möchte nicht für Googles Designfehler bezahlen, indem ich die Funktionalität meiner App einschränke.
Google möchte, dass Entwickler das Inhaltsschema verwenden, aber das System ist nicht darauf vorbereitet. Jahrelang wurden Apps entwickelt, um Dateien zu verwenden, die nicht "Inhalt" sind. Dateien können bearbeitet und zurückgespeichert werden, während Dateien, die über das Inhaltsschema bereitgestellt werden, nicht (können) Sie?).
quelle
ContentResolver
hat beidesopenInputStream()
undopenOutputStream()
. Eine weniger hackige Methode besteht darin , die VM-Regeln einfach selbst zu konfigurieren und diefile
Uri
Regel nicht zu aktivieren .Wenn Sie mindestens
targetSdkVersion
24 Jahre alt sind , können Sie auf Android 7.0+ Geräten keinefile:
Uri
WerteIntents
verwenden .Sie haben folgende Möglichkeiten:
Lassen Sie Ihre
targetSdkVersion
auf 23 oder niedriger fallen, oderLegen Sie Ihre Inhalte auf internen Speicher, dann verwenden
FileProvider
, um es selektiv zu anderen Anwendungen zur Verfügung zu stellenZum Beispiel:
(aus diesem Beispielprojekt )
quelle
/system
Partition verwende? Jede App sollte in der Lage sein, auf diese Partition ohne Root zuzugreifen./system
. Abgesehen davon denke ich, dass Sie diese Ausnahme immer noch bekommen werden. Ich vermute, dass sie nur das Schema überprüfen und nicht versuchen festzustellen, ob die Datei wirklich weltlesbar ist. Es wirdFileProvider
Ihnen jedoch nicht helfen, da Sie es nicht lehren können, von zu dienen/system
. Sie können eine benutzerdefinierte Strategie für mich erstellenStreamProvider
oder Ihre eigene Strategie erstellenContentProvider
, um das Problem zu umgehen./data
,/system
), wegen dieser "guten Veränderung".Zuerst müssen Sie Ihrem AndroidManifest einen Anbieter hinzufügen
Erstellen Sie jetzt eine Datei im XML-Ressourcenordner (wenn Sie Android Studio verwenden, können Sie Alt + Eingabetaste drücken, nachdem Sie file_paths markiert und die Option zum Erstellen einer XML-Ressourcenoption ausgewählt haben.)
Geben Sie als Nächstes in die Datei file_paths ein
Dieses Beispiel ist für einen externen Pfad, den Sie hier referieren können Weitere Optionen . Auf diese Weise können Sie Dateien freigeben, die sich in diesem Ordner und seinem Unterordner befinden.
Jetzt müssen Sie nur noch die Absicht wie folgt erstellen:
BEARBEITEN : Ich habe den Stammordner der SD-Karte in den Dateipfaden hinzugefügt. Ich habe diesen Code getestet und er funktioniert.
quelle
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
Außerdem empfehle ich jedem, der nach Antworten sucht, zuerst FileProvider durchzulesen und zu verstehen, was Sie hier mit Dateiberechtigungen in Android N und höher tun. Es gibt Optionen für internen Speicher gegenüber externem Speicher sowie für regulären Dateipfad im Vergleich zu Cache-Pfaden.java.lang.IllegalArgumentException: Failed to find configured root ...
und das einzige, was funktionierte, war<files-path path="." name="files_root" />
die XML-Datei anstelle von<external-path ...
. Meine Datei wurde im internen Speicher gespeichert.Die Antwort von @palash k ist korrekt und funktioniert für interne Speicherdateien. In meinem Fall möchte ich jedoch auch Dateien aus dem externen Speicher öffnen. Meine App stürzte ab, wenn Dateien aus dem externen Speicher wie SD-Karte und USB geöffnet wurden. Ich kann das Problem jedoch durch Ändern lösen provider_paths.xml aus der akzeptierten Antwort
Ändern Sie die Datei provider_paths.xml wie unten
und in der Java-Klasse (Keine Änderung als akzeptierte Antwort, nur eine kleine Änderung)
Dies hilft mir, den Absturz für Dateien aus externen Speichern zu beheben. Ich hoffe, dies hilft jemandem, der das gleiche Problem wie ich hat :)
quelle
<root-path
bitte gefunden? Es funktioniert.<external-path path="Android/data/${applicationId}/" name="files_root" />
hatte keine Auswirkung auf geöffnete Dateien aus dem externen Speicher.Android/data/${applicationId}/
in SD-Karte.Meine Lösung bestand darin, den Dateipfad als Zeichenfolge 'Uri.parse' zu verwenden, anstatt Uri.fromFile () zu verwenden.
Scheint, dass fromFile () einen Dateizeiger verwendet, der vermutlich unsicher ist, wenn Speicheradressen für alle Apps verfügbar sind. Ein Dateipfad-String hat jedoch niemanden verletzt, sodass er funktioniert, ohne FileUriExposedException auszulösen.
Getestet auf API-Level 9 bis 27! Öffnet erfolgreich die Textdatei zur Bearbeitung in einer anderen App. Benötigt weder FileProvider noch die Android Support Library.
quelle
Fügen Sie einfach den folgenden Code in die Aktivität onCreate () ein.
Die URI-Exposition wird ignoriert
quelle
Fügen Sie einfach den folgenden Code in die Aktivität ein
onCreate()
.Die URI-Exposition wird ignoriert.
Viel Spaß beim Codieren :-)
quelle
Die Verwendung des fileProviders ist der richtige Weg. Sie können jedoch diese einfache Problemumgehung verwenden:
ersetzen:
durch
quelle
Ich habe die oben angegebene Antwort von Palash verwendet, aber sie war etwas unvollständig. Ich musste eine solche Erlaubnis erteilen
quelle
Fügen Sie einfach den folgenden Code in die Aktivität onCreate () ein.
Die URI-Exposition wird ignoriert
quelle
Fügen Sie diese beiden Zeilen in onCreate hinzu
Freigabemethode
quelle
Hier meine Lösung:
in Manifest.xml
in res / xml / provider_paths.xml
In meinem Fragment habe ich den nächsten Code:
Das ist alles was du brauchst.
Auch muss nicht erstellt werden
Ich teste auf Android 5.0, 6.0 und Android 9.0 und es funktioniert erfolgreich.
quelle
Fügen Sie zum Herunterladen von PDF vom Server den folgenden Code in Ihre Serviceklasse ein. Hoffe das ist hilfreich für dich.
Und ja, vergessen Sie nicht, Ihrem Manifest Berechtigungen und Anbieter hinzuzufügen.
quelle
@xml/provider_paths
?Ich weiß nicht warum, ich habe alles genauso gemacht wie Pkosta ( https://stackoverflow.com/a/38858040 ), aber immer wieder Fehler erhalten:
java.lang.SecurityException: Permission Denial: opening provider redacted from ProcessRecord{redacted} (redacted) that is not exported from uid redacted
Ich habe Stunden mit diesem Thema verschwendet. Der Täter? Kotlin.
intent
wurde tatsächlich eingestellt,getIntent().addFlags
anstatt auf meinem neu deklarierten playIntent zu arbeiten.quelle
Ich habe diese Methode so eingestellt, dass der Imageuri-Pfad leicht in den Inhalt gelangt.
quelle
Hier gibt es 3 Hauptschritte, wie unten erwähnt
Schritt 1: Manifesteintrag
Schritt 2: Erstellen Sie die XML-Datei res / xml / provider_paths.xml
Schritt 3: Codeänderungen
quelle
Ich weiß, dass dies eine ziemlich alte Frage ist, aber diese Antwort ist für zukünftige Zuschauer. Ich bin also auf ein ähnliches Problem gestoßen und habe nach Recherchen eine Alternative zu diesem Ansatz gefunden.
Ihre Absicht hier für zB: Um Ihr Bild von Ihrem Weg in Kotlin zu sehen
Hauptfunktion unten
Ebenso können Sie anstelle eines Bildes jedes andere Dateiformat wie PDF verwenden, und in meinem Fall hat es einwandfrei funktioniert
quelle
Ich habe fast einen Tag damit verbracht herauszufinden, warum ich diese Ausnahme bekam. Nach vielen Kämpfen funktionierte diese Konfiguration perfekt ( Kotlin ):
AndroidManifest.xml
file_paths.xml
Absicht selbst
Ich erkläre den gesamten Prozess hier .
quelle
https://stackoverflow.com/a/38858040/395097 Diese Antwort ist vollständig.
Diese Antwort ist für - Sie haben bereits eine App, deren Ziel unter 24 lag, und jetzt aktualisieren Sie auf targetSDKVersion> = 24.
In Android N wird nur die Datei uri geändert, die für Apps von Drittanbietern verfügbar ist. (Nicht so, wie wir es vorher benutzt haben). Ändern Sie also nur die Stellen, an denen Sie den Pfad mit der Drittanbieter-App teilen (in meinem Fall Kamera).
In unserer App haben wir uri an die Kamera-App gesendet. An diesem Ort erwarten wir, dass die Kamera-App das aufgenommene Bild speichert.
Jetzt haben wir 2 verschiedene URLs für dieselbe Datei. # 1 wird mit der Kamera-App geteilt. Wenn die Absicht der Kamera erfolgreich ist, können wir von # 2 aus auf das Bild zugreifen.
Hoffe das hilft.
quelle
Xamarin.Android
Hinweis: Der Pfad xml / provider_paths.xml (.axml) konnte nicht aufgelöst werden, selbst nachdem der XML- Ordner unter Ressourcen erstellt wurde (möglicherweise kann er an einem vorhandenen Speicherort wie Werte abgelegt werden , habe es nicht versucht), daher habe ich darauf zurückgegriffen das was jetzt funktioniert. Tests haben gezeigt, dass es nur einmal pro Anwendungslauf aufgerufen werden muss (was sinnvoll ist, da es den Betriebszustand der Host-VM ändert).
Hinweis: XML muss groß geschrieben werden, also Resources / Xml / provider_paths.xml
quelle
Die Antwort von @Pkosta ist eine Möglichkeit, dies zu tun.
Neben der Verwendung
FileProvider
können Sie die Datei auch inMediaStore
(insbesondere für Bild- und Videodateien) einfügen , da auf Dateien im MediaStore für jede App zugegriffen werden kann:Sie können beispielsweise eine Videodatei wie folgt in MediaStore einfügen:
contentUri
ist wiecontent://media/external/video/media/183473
, die direkt übergeben werden kann anIntent.putExtra
:Dies funktioniert für mich und erspart den Aufwand bei der Verwendung
FileProvider
.quelle
Lassen Sie es einfach die URI-Belichtung ignorieren ... Fügen Sie sie nach dem Erstellen hinzu
quelle
Versuchen Sie diese Lösung
STELLEN SIE DIESE ERLAUBNISSE IN MANIFEST
Absicht, Bilder aufzunehmen
ERHALTEN SIE EIN ERFASSTES BILD IN ONAKTIVITÄTSERGEBNIS
Methode zum Abrufen der Bild-URI
quelle
In meinem Fall habe ich die Ausnahme durch Ersetzen
SetDataAndType
durch just beseitigtSetData
.quelle