Исключение FileUriExposedException в Android [дубликат]
Мне нужно открыть папку во внутреннем хранилище, содержащую изображения.
Я использую следующий код.
Java
File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyPhotos");
Intent intent = new Intent(Intent.ACTION_VIEW);
String path =folder.getPath();
Uri myImagesdir = Uri.parse("file://" + path );
intent.setDataAndType(myImagesdir,"*/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
ПУТИ
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="images" path="Pictures" />
<external-path name="external_files" path="."/>
<external-path name="files_root" path="Android/data/${applicationId}"/> </paths>
Манифест
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
xml/file_paths
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="images" path="Pictures" />
<external-path name="external_files" path="."/>
<external-path name="files_root" path="Android/data/${applicationId}"/>
</paths>
ОШИБКА
ФАТАЛЬНОЕ ИСКЛЮЧЕНИЕ: основной процесс: android.apps.bnb.company.myphotos, PID: 22482 Исключение android.os.FileUriExposedException: файл: ///хранилище / эмулировано / 0 / Изображения / MyPhotos, выставленные за пределы приложения через Intent.getData()
Есть ли другой способ открыть папку во внутреннем хранилище? Спасибо!
ОБНОВЛЕНИЕ # 1
Используя эту статью https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/en Я заменил
Uri myImagesdir = Uri.parse("file://" + path );
с
Uri myImagesdir = Uri.parse("content://" + path );
И ошибка исчезла.
В любом случае я должен выбрать always app, чтобы открыть эту папку.
Возможно ли использовать приложение "Мои файлы" по умолчанию для открытия определенной папки?
Переведено автоматически
Ответ 1
Возможно ли использовать приложение "Мои файлы" по умолчанию для открытия определенной папки?
Да и нет. Не гарантируется на 100%, что это будет работать на всех устройствах.
Правка 1:
Ниже приведен один из способов, с помощью которого это можно сделать. Я тестировал на нескольких эмуляторах (под управлением Android N и Android O) и загружает проводник файлов по умолчанию.:
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri dirUri = FileProvider.getUriForFile(this,getApplicationContext().getPackageName() + ".com.example.myapplication",Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//intent.setDataAndtType(); I will change this value in the alternatives below
}
AndroidManifest.xml
<provider
android:name=".GenericFileProvider"
android:authorities="${applicationId}.com.example.myapplication"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
GenericFileProvider.java
public class GenericFileProvider extends FileProvider {
}
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Описанный выше подход не работает на крупных игроках, таких как samsung
Альтернативы
1. Использование типа DocumentsContract.Document.MIME_TYPE_DIR
intent.setDataAndType(dirUri,DocumentsContract.Document.MIME_TYPE_DIR);
Этот подход работает на нескольких эмуляторах и ограниченном наборе устройств. Он не работает с крупными игроками, такими как Samsung или Huawei.
2. Использование типа resource/folder
intent.setDataAndType(dirUri,"resource/folder");
Этот подход работает, только если пользователь установил приложение ES file Explorer.
Если вы решите использовать , вам нужно проверить, доступно ли какое-либо намерение для обработки этого с помощью:
PackageManager PackageManager = getActivity().getPackageManager();
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent);
} else {
// either display error or take necessary action
}
3. Использование типа */*
intent.setDataAndType(dirUri,"*/*");
Этот подход работает, если пользователь выбирает приложение файлового менеджера из средства выбора намерений и помечает его как приложение по умолчанию для обработки */*
. Однако у него есть некоторые недостатки (спасибо @CommonsWare за то, что он раскрыл некоторые из них):
- Этот тип загрузит все приложения на устройстве и позволит пользователю выбрать одно из них для завершения действия.
- Если нет проводника файлов и пользователь выбирает другие приложения для загрузки вашего намерения, то другое приложение выйдет из строя или просто покажет черный экран. Например. Вы используете Gallery или какое-либо другое приложение для его запуска, а не file explorer, тогда приложение Gallery либо выйдет из строя, либо покажет черный экран.
- Даже если есть проводник, но пользователь решает использовать другие приложения, другие приложения могут выйти из строя
4. Использование типа text/csv
intent.setDataAndType(uri, "text/csv")
Это ограничит количество приложений, которые будут отображаться пользователю, но при */*
использовании будут применены те же ограничения. Будут отображаться приложения, которые могут обрабатывать csv
, и если пользователь выберет это, приложения завершат работу.
Здесь доступны некоторые реализации для конкретного устройства, как упомянуто @ Academy of Programmer, для которых требуется определить назначение файлового менеджера по умолчанию и необходимость дополнительных функций.
Заключение:
Для его достижения не доступен стандартный тип, поскольку на данный момент нет стандарта, которому следуют файловые менеджеры для поддержки определенного типа. Возможно, в будущем Google предложит какой-нибудь подход. Лучшей альтернативой было бы реализовать свой собственный файловый менеджер, как это делают Dropbox или Google Drive. Доступно несколько библиотек, которые предоставляют эту функцию.
Ответ 2
Приведенный ниже код используется мной для открытия изображения из хранилища :
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
File path = new File(Environment.getExternalStorageDirectory() + "/" + "ParentDirectory" + "/" + "ChildDirectory");
File filepath = new File(path + "/" + yourImageName.png);
Uri uri = Uri.fromFile(filepath);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/jpeg");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Отредактированный ответ :
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
File path = new File(Environment.getExternalStorageDirectory() + "/" + "ParentDirectory" + "/" + "ChildDirectory");
Uri uri = Uri.fromFile(path);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/jpeg");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Ответ 3
Я нашел решение здесь можем ли мы открыть папку загрузки через. намерение?
Этот код идеально работает в моем Samsung J7, чтобы открыть папку Pictures (и другие) из внутренней памяти с помощью приложения Samsung по умолчанию "Мои файлы".
File path = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES);
Uri uri = Uri.fromFile(path);
Intent intent = getPackageManager().getLaunchIntentForPackage("com.sec.android.app.myfiles");
intent.setAction("samsung.myfiles.intent.action.LAUNCH_MY_FILES");
intent.putExtra("samsung.myfiles.intent.extra.START_PATH", path.getAbsolutePath());
startActivity(intent);
Похоже, нам нужно декомпилировать файловый менеджер каждого производителя, чтобы узнать, как его правильно вызывать. :( И это слишком много работы. Хорошо... Я предположил, что есть какое-то общее решение для этого.