Исключение 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.приложения.БНБ.компания.myphotos, PID: Двадцать две тысячи четыреста восемьдесят два андроид.ОС.FileUriExposedException: файл: / / / хранение / эмулируется / 0 / фотографии/MyPhotos подвергаются за пределами приложения через намерение.getData ()

есть ли другой способ открыть папку во внутреннем хранилище? Спасибо!

обновление #1

использование этой arcticle 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 );

и ошибка ушедший.

в любом случае я должен выбрать всегда приложение, чтобы открыть эту папку.

есть ли возможность использовать приложение "Мои файлы" по умолчанию для открытия определенной папки?

3 ответов


есть ли возможность использовать приложение "Мои файлы" по умолчанию для открытия определенной папки?

Да И Нет. Его не 100% гарантировано, что он будет работать на всех устройствах.

Edit 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.

если вы решили использовать, то вы должны проверить, если какой-либо намерение доступно для обработки его с помощью:

диспетчер пакетов диспетчера пакетов = getActivity().getPackageManager();

if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent);
} else {
   // either display error or take necessary action
}

3. Использование типа */*

intent.setDataAndType(dirUri,"*/*");

этот подход работает, если пользователь выбирает приложение файлового менеджера из выбора намерения и отмечает его как приложение по умолчанию для обработки */*. Однако у него есть некоторые недостатки (Благодаря @CommonsWare для выведения некоторых из них):

  • этот тип загрузит все приложения на устройстве и позволит пользователю выбрать один из них для завершения действие.
  • если нет проводника файлов и пользователь выбирает другие приложения для загрузки вашего намерения, то другое приложение рухнет или просто покажет черный экран. Например. Вы используете галерею или другое приложение, чтобы запустить его, а не проводник, то Галерея приложение будет либо сбой или показать черный экран.
  • даже если есть проводник, но пользователь решает использовать другие приложения, другие приложения могут сбой

4. Использование типа text/csv

intent.setDataAndType(uri, "text/csv")

это ограничит количество приложений, которые будут отображаться пользователю, но те же ограничения, когда используется. Приложения, которые могут обрабатывать csv будет отображаться, и если пользователь выберет его, то приложения будут сбой.

есть некоторые устройства конкретных реализаций доступны здесь как отметил @Academy of Programmer что требует определения намерения файлового менеджера по умолчанию и дополнительная потребность им.

вывод:

нет стандартного типа для его достижения, поскольку на данный момент нет стандарта, за которым следуют файловые менеджеры для поддержки определенного типа. В будущем, возможно, Google придумает какой-то подход. Лучшей альтернативой было бы реализовать свой собственный файловый менеджер, как это делает Dropbox или Google Drive. Существует несколько библиотек, которые предоставляют эту функцию.


приведенный ниже код используется мной для открытия изображения из хранилища:

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);

Я нашел решение здесь можем ли мы открыть папку загрузки через. умысла?

этот код отлично работает в моем 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);

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