Android

FileUriExposedException in Android [duplicate]

Исключение 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);

Похоже, нам нужно декомпилировать файловый менеджер каждого производителя, чтобы узнать, как его правильно вызывать. :( И это слишком много работы. Хорошо... Я предположил, что есть какое-то общее решение для этого.

java android android-intent