Update für Android N (die ursprüngliche Antwort unten verlassen und haben diesen neuen Ansatz bestätigt arbeitet in der Produktion):
Wie Sie in Ihrem Update erwähnt, viele Huawei Gerätemodelle (zB KIW-L24, ALE- L21, ALE-L02, PLK-L01 und eine Vielzahl anderer) brechen den Android-Vertrag für Anrufe auf ContextCompat#getExternalFilesDirs(String)
. Anstatt Context#getExternalFilesDir(String)
(dh den Standardeintrag) als erstes Objekt im Array zurückzugeben, geben sie stattdessen das erste Objekt als Pfad zur externen SD-Karte zurück, falls eine vorhanden ist.
Durch diese Reihenfolge Vertrag zu brechen, diese Huawei-Geräte mit externen SD-Karten werden mit einem IllegalArgumentException
auf Anrufe zu FileProvider#getUriForFile(Context, String, File)
für external-files-path
Wurzeln abstürzen. Es gibt zwar eine Vielzahl von Lösungen, die Sie verfolgen können, um mit diesem Problem umzugehen (z.
- Pre-N: Zurück
Uri#fromFile(File)
, die mit Android N wird nicht funktionieren und vor aufgrund FileUriExposedException
- eine benutzerdefinierte
FileProvider
Implementierung) zu schreiben, habe ich die einfachste Ansatz ist zu fangen dieses Problem und fand N: Kopieren Sie die Datei auf Ihre cache-path
(Anmerkung: dieser ANRs vorstellen kann, wenn auf dem UI-Thread getan) und dann FileProvider#getUriForFile(Context, String, File)
für die kopierte Datei zurück
-Code (dh die Fehler ganz zu vermeiden), dies zu erreichen kann gefunden werden unten:
public class ContentUriProvider {
private static final String HUAWEI_MANUFACTURER = "Huawei";
public static Uri getUriForFile(@NonNull Context context, @NonNull String authority, @NonNull File file) {
if (HUAWEI_MANUFACTURER.equalsIgnoreCase(Build.MANUFACTURER)) {
Log.w(ContentUriProvider.class.getSimpleName(), "Using a Huawei device Increased likelihood of failure...");
try {
return FileProvider.getUriForFile(context, authority, file);
} catch (IllegalArgumentException e) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Log.w(ContentUriProvider.class.getSimpleName(), "Returning Uri.fromFile to avoid Huawei 'external-files-path' bug for pre-N devices", e);
return Uri.fromFile(file);
} else {
Log.w(ContentUriProvider.class.getSimpleName(), "ANR Risk -- Copying the file the location cache to avoid Huawei 'external-files-path' bug for N+ devices", e);
// Note: Periodically clear this cache
final File cacheFolder = new File(context.getCacheDir(), HUAWEI_MANUFACTURER);
final File cacheLocation = new File(cacheFolder, file.getName());
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(file);
out = new FileOutputStream(cacheLocation); // appending output stream
IOUtils.copy(in, out);
Log.i(ContentUriProvider.class.getSimpleName(), "Completed Android N+ Huawei file copy. Attempting to return the cached file");
return FileProvider.getUriForFile(context, authority, cacheLocation);
} catch (IOException e1) {
Log.e(ContentUriProvider.class.getSimpleName(), "Failed to copy the Huawei file. Re-throwing exception", e1);
throw new IllegalArgumentException("Huawei devices are unsupported for Android N", e1);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
}
}
} else {
return FileProvider.getUriForFile(context, authority, file);
}
}
}
Zusammen mit dem file_provider_paths.xml
:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="public-files-path" path="." />
<cache-path name="private-cache-path" path="." />
</paths>
Sobald Sie eine Klasse wie folgt erstellt haben, ersetzen Sie Ihre Anrufe an:
FileProvider.getUriForFile(Context, String, File)
mit:
ContentUriProvider.getUriForFile(Context, String, File)
Ehrlich gesagt, Ich denke nicht, dass dies eine besonders anmutige Lösung ist, aber es erlaubt uns, dafür zu verwenden mally dokumentiert Android-Verhalten ohne etwas zu drastisch (z. Schreiben einer benutzerdefinierten FileProvider
Implementierung). Ich habe das in der Produktion getestet, also kann ich bestätigen, dass es diese Huawei Abstürze behebt. Für mich war das der beste Ansatz, da ich nicht zu viel Zeit damit verbringen wollte, das zu adressieren, was ganz offensichtlich ein Herstellerdefekt ist.
Update von vor Huawei-Geräten mit diesem Fehler zu Android N aktualisiert:
Dies wird nicht mit Android N arbeiten und oben aufgrund FileUriExposedException
, aber ich habe noch ein Huawei-Gerät mit diesem Fehl begegnen Konfiguration auf Android N.
public class ContentUriProvider {
private static final String HUAWEI_MANUFACTURER = "Huawei";
public static Uri getUriForFile(@NonNull Context context, @NonNull String authority, @NonNull File file) {
if (HUAWEI_MANUFACTURER.equalsIgnoreCase(Build.MANUFACTURER) && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Log.w(ContentUriProvider.class.getSimpleName(), "Using a Huawei device on pre-N. Increased likelihood of failure...");
try {
return FileProvider.getUriForFile(context, authority, file);
} catch (IllegalArgumentException e) {
Log.w(ContentUriProvider.class.getSimpleName(), "Returning Uri.fromFile to avoid Huawei 'external-files-path' bug", e);
return Uri.fromFile(file);
}
} else {
return FileProvider.getUriForFile(context, authority, file);
}
}
}
Wo/wie bekommen Sie diese 'Datei'? '/ storage/' sieht nicht korrekt aus. –
CommonsWare
Bitte teilen Sie mit, was getExternalStorageDirectory() auf diesem Gerät liefert. – greenapps
Ich erhalte die Datei mit 'Context.getExternalFileDir (null)'. Von den Protokollen, die ich auf diesen Geräten habe, kann es Speicher zurückbringen/sdcard1 /,/storage/3565-3131 /,/storage/73A8-8626 /,/storage/864A-F3ED ... –