FileUriExposedException в Android - PullRequest
       11

FileUriExposedException в Android

0 голосов
/ 28 апреля 2018

Мне нужно открыть папку во внутренней памяти, которая содержит изображения.

Я использую следующий код.

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>

Manifest

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

ERROR

ФАТАЛЬНОЕ ИСКЛЮЧЕНИЕ: основной процесс: 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 );

И ошибка ушла.

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

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

Ответы [ 3 ]

0 голосов
/ 30 апреля 2018

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

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

Редактировать 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,"*/*");

Этот подход работает, если пользователь выбирает приложение File Manager из Intent Chooser и помечает его как приложение по умолчанию для обработки */*. Однако у него есть некоторые недостатки (спасибо @CommonsWare за то, что вывели некоторые из них):

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

4. Используя тип text/csv

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

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

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

Вывод:

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

0 голосов
/ 03 мая 2018

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

Этот код прекрасно работает в моем Samsung J7, чтобы открыть папку «Изображения» (и другие) из внутренней памяти с помощью приложения 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);

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

0 голосов
/ 28 апреля 2018

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

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