Zusammenfassung
Sie können Lese- / Schreibzugriff auf externe SD-Karten auf den verschiedenen API-Ebenen ( API23 + zur Laufzeit ) gewähren .
Da KitKat, sind Berechtigungen nicht erforderlich , wenn Sie app-spezifische Verzeichnisse verwenden, erforderlich anders.
Universeller Weg:
Die Geschichte besagt, dass es keine universelle Möglichkeit gibt, auf eine externe SD-Karte zu schreiben, sondern dass ...
Diese Tatsache wird durch diese Beispiele für externe Speicherkonfigurationen für Geräte demonstriert .
API-basierter Weg:
Vor KitKat versuchen zu verwenden Doomsknight Methode 1, Methode 2 anders.
Fordern Sie Berechtigungen im Manifest (Api <23) und zur Laufzeit (Api> = 23) an.
Empfohlener Weg:
ContextCompat.getExternalFilesDirs löst den Zugriffsfehler, wenn Sie keine Dateien freigeben müssen.
Die sichere Möglichkeit zur Freigabe besteht darin, einen Inhaltsanbieter oder das neue Storage Access Framework zu verwenden .
Datenschutzbewusster Weg:
Ab Android Q Beta 4 werden Apps, die auf Android 9 (API-Stufe 28) oder niedriger abzielen, standardmäßig nicht geändert.
Apps, die standardmäßig auf Android Q abzielen (oder sich dafür entscheiden), erhalten eine gefilterte Ansicht in den externen Speicher.
1. Erste Antwort.
Universelle Möglichkeit, auf eine externe SD-Karte unter Android zu schreiben
Aufgrund ständiger Änderungen gibt es unter Android keine universelle Möglichkeit , auf eine externe SD-Karte zu schreiben :
Pre-KitKat: Die offizielle Android-Plattform unterstützt SD-Karten bis auf Ausnahmen überhaupt nicht.
KitKat: Einführung von APIs, mit denen Apps auf Dateien in app-spezifischen Verzeichnissen auf SD-Karten zugreifen können.
Lollipop: APIs hinzugefügt, mit denen Apps den Zugriff auf Ordner anderer Anbieter anfordern können.
Nougat: Bereitstellung einer vereinfachten API für den Zugriff auf allgemeine externe Speicherverzeichnisse.
... Änderung des Datenschutzes für Android Q: Speicher mit App- und Medienbereich
Was ist der bessere Weg, um Lese- / Schreibzugriff auf externe SD-Karten auf verschiedenen API-Ebenen zu gewähren?
Basierend auf der Antwort von Doomsknight und meiner sowie den Blog-Posts von Dave Smith und Mark Murphy: 1 , 2 , 3 :
2. Aktualisierte Antwort.
Update 1 . Ich habe Methode 1 aus Doomknights Antwort ausprobiert, ohne Erfolg:
Wie Sie sehen, überprüfe ich zur Laufzeit, ob Berechtigungen vorhanden sind, bevor ich versuche, auf SD zu schreiben ...
Ich würde anwendungsspezifische Verzeichnisse verwenden , um das Problem Ihrer aktualisierten Frage zu vermeiden und ContextCompat.getExternalFilesDirs()
die Dokumentation von getExternalFilesDir als Referenz zu verwenden.
Verbessern Sie die Heuristik , um zu bestimmen, was Wechselmedien darstellt, basierend auf den verschiedenen API-Ebenen wieandroid.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT
... Aber ich bekomme einen Zugriffsfehler, der auf zwei verschiedenen Geräten versucht wurde: HTC10 und Shield K1.
Denken Sie daran, dass Android 6.0 tragbare Speichergeräte unterstützt und Apps von Drittanbietern das Storage Access Framework durchlaufen müssen . Ihre Geräte HTC10 und Shield K1 sind wahrscheinlich API 23.
In Ihrem Protokoll wird eine Berechtigung angezeigt, der der Zugriff auf Ausnahmen verweigert wurde/mnt/media_rw
, wie dieser Fix für API 19+:
<permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
<group gid="sdcard_r" />
<group gid="sdcard_rw" />
<group gid="media_rw" />
</permission>
Ich habe es nie versucht, damit ich keinen Code freigeben kann, aber ich würde den for
Versuch vermeiden , in alle zurückgegebenen Verzeichnisse zu schreiben, und nach dem besten verfügbaren Speicherverzeichnis suchen , in das basierend auf dem verbleibenden Speicherplatz geschrieben werden kann .
Vielleicht ist die Alternative von Gizm0 zu Ihrer getStorageDirectories()
Methode ein guter Ausgangspunkt.
ContextCompat.getExternalFilesDirs
Behebt das Problem, wenn Sie keinen Zugriff auf andere Ordner benötigen .
3. Android 1.0 .. Pre-KitKat.
Versuchen Sie vor KitKat, Doomsknight-Methode 1 zu verwenden, oder lesen Sie diese Antwort von Gnathonic.
public static HashSet<String> getExternalMounts() {
final HashSet<String> out = new HashSet<String>();
String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
String s = "";
try {
final Process process = new ProcessBuilder().command("mount")
.redirectErrorStream(true).start();
process.waitFor();
final InputStream is = process.getInputStream();
final byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {
s = s + new String(buffer);
}
is.close();
} catch (final Exception e) {
e.printStackTrace();
}
final String[] lines = s.split("\n");
for (String line : lines) {
if (!line.toLowerCase(Locale.US).contains("asec")) {
if (line.matches(reg)) {
String[] parts = line.split(" ");
for (String part : parts) {
if (part.startsWith("/"))
if (!part.toLowerCase(Locale.US).contains("vold"))
out.add(part);
}
}
}
}
return out;
}
Fügen Sie den nächsten Code zu Ihrem hinzu AndroidManifest.xml
und lesen Sie Zugriff auf externen Speicher erhalten
Der Zugriff auf externen Speicher wird durch verschiedene Android-Berechtigungen geschützt.
Ab Android 1.0 ist der Schreibzugriff mit der WRITE_EXTERNAL_STORAGE
Berechtigung geschützt .
Ab Android 4.1 ist der Lesezugriff mit der READ_EXTERNAL_STORAGE
Berechtigung geschützt .
Um ... Dateien auf den externen Speicher zu schreiben, muss Ihre App ... Systemberechtigungen erwerben:
<manifest ...>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
Wenn Sie beides benötigen, müssen Sie nur die WRITE_EXTERNAL_STORAGE
Erlaubnis anfordern .
Lesen Sie die Erklärung von Mark Murphy und empfehlen Sie die Beiträge von Dianne Hackborn und Dave Smith
- Bis Android 4.4 gab es in Android keine offizielle Unterstützung für Wechselmedien. Ab KitKat taucht in der FMW-API das Konzept des „primären“ und „sekundären“ externen Speichers auf.
- Frühere Apps verlassen sich lediglich auf die MediaStore-Indizierung, werden mit der Hardware geliefert oder untersuchen Einhängepunkte und wenden einige Heuristiken an, um festzustellen, was Wechselmedien darstellt.
Ignorieren Sie die nächste Notiz aufgrund von Fehlern, aber versuchen Sie Folgendes zu verwenden ContextCompat.getExternalFilesDirs()
:
- Seit Android 4.2 haben Gerätehersteller Google aufgefordert, Wechselmedien aus Sicherheitsgründen zu sperren (Mehrbenutzerunterstützung), und in 4.4 wurden neue Tests hinzugefügt.
- Da KitKat
getExternalFilesDirs()
und andere Methoden hinzugefügt wurden, um einen verwendbaren Pfad für alle verfügbaren Speichervolumes zurückzugeben (Das erste zurückgegebene Element ist das primäre Volume).
- Die folgende Tabelle zeigt, was ein Entwickler möglicherweise versucht und wie KitKat reagiert:
Hinweis: Ab Android 4.4 sind diese Berechtigungen nicht erforderlich, wenn Sie nur Dateien lesen oder schreiben, die für Ihre App privat sind. Weitere Informationen finden Sie unter Speichern von Dateien, die app-privat sind .
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
</manifest>
Lesen Sie auch die Erklärung von Paolo Rovelli und versuchen Sie, Jeff Sharkeys Lösung seit KitKat zu verwenden:
In KitKat gibt es jetzt eine öffentliche API für die Interaktion mit diesen sekundären gemeinsam genutzten Speichergeräten.
Die Methoden new Context.getExternalFilesDirs()
und
Context.getExternalCacheDirs()
können mehrere Pfade zurückgeben, einschließlich primärer und sekundärer Geräte.
Sie können sie dann durchlaufen und überprüfen Environment.getStorageState()
und
File.getFreeSpace()
den besten Speicherort für Ihre Dateien ermitteln.
Diese Methoden sind auch ContextCompat
in der support-v4-Bibliothek verfügbar .
Ab Android 4.4 werden Eigentümer, Gruppe und Modi von Dateien auf externen Speichergeräten jetzt basierend auf der Verzeichnisstruktur synthetisiert. Auf diese Weise können Apps ihre paketspezifischen Verzeichnisse auf einem externen Speicher verwalten, ohne dass sie über die allgemeine
WRITE_EXTERNAL_STORAGE
Berechtigung verfügen müssen. Beispielsweise kann die App mit dem Paketnamen com.example.foo
jetzt Android/data/com.example.foo/
ohne Berechtigungen frei auf externe Speichergeräte zugreifen
. Diese synthetisierten Berechtigungen werden erreicht, indem Raw-Speichergeräte in einen FUSE-Daemon eingeschlossen werden.
Mit KitKat sind Ihre Chancen auf eine "Komplettlösung" ohne Rooting so gut wie null:
Das Android-Projekt hat es hier definitiv vermasselt. Keine Apps erhalten vollen Zugriff auf externe SD-Karten:
- Dateimanager: Sie können sie nicht zum Verwalten Ihrer externen SD-Karte verwenden. In den meisten Bereichen können sie nur lesen, aber nicht schreiben.
- Medien-Apps: Sie können Ihre Mediensammlung nicht mehr neu markieren / organisieren, da diese Apps nicht darauf schreiben können.
- Office-Apps: ziemlich gleich
Die einzige Ort , 3 rd Party - Anwendungen sind zu schreiben auf Ihrer externe Karte erlaubt sind „ ihre eigenen Verzeichnisse“ (dh
/sdcard/Android/data/<package_name_of_the_app>
).
Die einzigen Möglichkeiten, dies wirklich zu beheben, erfordern entweder den Hersteller (einige von ihnen haben es behoben, z. B. Huawei mit ihrem Kitkat-Update für das P6) - oder root ... (Izzys Erklärung wird hier fortgesetzt)
5. Android 5.0 führte Änderungen und die DocumentFile- Hilfsklasse ein.
getStorageState
In API 19 hinzugefügt, in API 21 veraltet,
verwendengetExternalStorageState(File)
Hier ist ein großartiges Tutorial für die Interaktion mit dem Storage Access Framework in KitKat.
Die Interaktion mit den neuen APIs in Lollipop ist sehr ähnlich (Jeff Sharkeys Erklärung) .
Fordern Sie zur Laufzeit Berechtigungen ab API-Stufe 23+ an und lesen Sie Anfordern von Berechtigungen zur Laufzeit
Ab Android 6.0 (API-Stufe 23) erteilen Benutzer Apps Berechtigungen, während die App ausgeführt wird, nicht, wenn sie die App installieren ... oder die App aktualisieren ... Benutzer können die Berechtigungen widerrufen.
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
Android 6.0 führt ein neues Laufzeitberechtigungsmodell ein , bei dem Apps bei Bedarf zur Laufzeit Funktionen anfordern. Da das neue Modell die READ/WRITE_EXTERNAL_STORAGE
Berechtigungen enthält, muss die Plattform dynamisch Speicherzugriff gewähren, ohne bereits ausgeführte Apps zu beenden oder neu zu starten. Dazu werden drei unterschiedliche Ansichten aller bereitgestellten Speichergeräte beibehalten:
- / mnt / runtime / default wird Apps ohne spezielle Speicherberechtigungen angezeigt ...
- / mnt / runtime / read wird Apps mit READ_EXTERNAL_STORAGE angezeigt
- / mnt / runtime / write wird Apps mit WRITE_EXTERNAL_STORAGE angezeigt
7. Android 7.0 bietet eine vereinfachte API für den Zugriff auf externe Speicherverzeichnisse.
Zugriff auf Bereichsverzeichnisse
In Android 7.0 können Apps mithilfe neuer APIs den Zugriff auf bestimmte externe Speicherverzeichnisse anfordern
, einschließlich Verzeichnisse auf Wechselmedien wie SD-Karten ...
Weitere Informationen finden Sie in der Schulung zum Scoped Directory Access .
Lesen Sie die Beiträge von Mark Murphy: Seien Sie vorsichtig mit dem Zugriff auf das Bereichsverzeichnis . Es wurde in Android Q veraltet :
Beachten Sie, dass der in 7.0 hinzugefügte Verzeichniszugriff mit Gültigkeitsbereich in Android Q veraltet ist.
Insbesondere ist die createAccessIntent()
Methode in StorageVolume veraltet.
Sie fügten ein hinzu createOpenDocumentTreeIntent()
, das als Alternative verwendet werden kann.
8. Android 8.0 Oreo .. Änderungen an Android Q Beta.
Ab Android O können Anbieter
von benutzerdefinierten Dokumenten mit dem Storage Access Framework durchsuchbare Dateideskriptoren für Dateien erstellen, die sich in einer entfernten Datenquelle befinden ...
Berechtigungen ,
vor dem Android O , wenn eine App angefordert wurde eine Genehmigung zur Laufzeit und die Erlaubnis erteilt, das System auch die App des Rest der Berechtigungen nicht ordnungsgemäß gewährt, die zur gleichen Berechtigungsgruppe gehörten, und die in dem Manifest registriert wurden.
Bei Apps für Android O wurde dieses Verhalten korrigiert. Der App werden nur die Berechtigungen erteilt, die sie ausdrücklich angefordert hat. Sobald der Benutzer der App jedoch eine Berechtigung erteilt, werden alle nachfolgenden Berechtigungsanforderungen in dieser Berechtigungsgruppe automatisch erteilt.
Zum Beispiel READ_EXTERNAL_STORAGE
und WRITE_EXTERNAL_STORAGE
...
Update: Eine frühere Beta-Version von Android Q hat die Berechtigungen READ_EXTERNAL_STORAGE
und vorübergehend durch WRITE_EXTERNAL_STORAGE
detailliertere, medienspezifische Berechtigungen ersetzt.
Hinweis: Google hat Rollen in Beta 1 eingeführt und diese vor Beta 2 aus der Dokumentation entfernt ...
Hinweis: Die Berechtigungen für Mediensammlungen, die in früheren Betaversionen READ_MEDIA_IMAGES
- READ_MEDIA_AUDIO
, und READ_MEDIA_VIDEO
- eingeführt wurden, sind jetzt veraltet . Mehr Info:
Q Beta 4 (endgültige APIs) von Mark Murphy: Der Tod des externen Speichers: Das Ende der Saga (?)
"Der Tod ist universeller als das Leben. Jeder stirbt, aber nicht jeder lebt." - Andrew Sachs
9. Verwandte Fragen und empfohlene Antworten.
Wie kann ich einen externen SD-Kartenpfad für Android 4.0+ erhalten?
mkdir () funktioniert im internen Flash-Speicher, aber nicht auf der SD-Karte?
Unterschied zwischen getExternalFilesDir und getExternalStorageDirectory ()
Warum funktioniert getExternalFilesDirs () auf einigen Geräten nicht?
Verwendung der neuen SD-Kartenzugriffs-API für Android 5.0 (Lollipop)
Schreiben auf eine externe SD-Karte in Android 5.0 und höher
Schreibberechtigung für Android SD-Karten mit SAF (Storage Access Framework)
SAFFAQ: Die häufig gestellten Fragen zum Storage Access Framework
10. Verwandte Fehler und Probleme.
Fehler: Unter Android 6 können Sie bei Verwendung von getExternalFilesDirs keine neuen Dateien in den Ergebnissen erstellen
Das Schreiben in das von getExternalCacheDir () auf Lollipop zurückgegebene Verzeichnis schlägt ohne Schreibberechtigung fehl