отображается за пределами приложения через ClipData.Item.getUri

104

Я пытаюсь исправить проблему после добавления новой функции в файловую систему Android, но получаю следующую ошибку:

android.os.FileUriExposedException: file:///storage/emulated/0/MyApp/Camera_20180105_172234.jpg exposed beyond app through ClipData.Item.getUri()

Так что я надеюсь, что кто-нибудь поможет мне это исправить :)

Благодарность

private Uri getTempUri() {
    // Create an image file name
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
    String dt = sdf.format(new Date());
    imageFile = null;
    imageFile = new File(Environment.getExternalStorageDirectory()
            + "/MyApp/", "Camera_" + dt + ".jpg");
    AppLog.Log(
            TAG,
            "New Camera Image Path:- "
                    + Environment.getExternalStorageDirectory()
                    + "/MyApp/" + "Camera_" + dt + ".jpg");
    File file = new File(Environment.getExternalStorageDirectory() + "/MyApp");
    if (!file.exists()) {
        file.mkdir();
    }
    imagePath = Environment.getExternalStorageDirectory() + "/MyApp/"
            + "Camera_" + dt + ".jpg";
    imageUri = Uri.fromFile(imageFile);
    return imageUri;
}
JonathanNet
источник

Ответы:

177

Для sdk 24 и выше, если вам нужно получить Uri файла за пределами вашего хранилища приложения, у вас есть эта ошибка.
Решения @ eranda.del позволяют вам изменить политику, чтобы разрешить это, и это работает нормально.

Однако, если вы хотите следовать руководству Google без изменения политики API вашего приложения, вам необходимо использовать FileProvider.

Сначала, чтобы получить URI файла, вам нужно использовать метод FileProvider.getUriForFile ():

Uri imageUri = FileProvider.getUriForFile(
            MainActivity.this,
            "com.example.homefolder.example.provider", //(use your app signature + ".provider" )
            imageFile);

Затем вам нужно настроить своего провайдера в манифесте Android:

<application>
  ...
     <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.example.homefolder.example.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <!-- ressource file to create -->
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths">  
        </meta-data>
    </provider>
</application>

(В разделе «Авторитет» используйте то же значение, что и второй аргумент метода getUriForFile () (подпись приложения + «.provider»))

И, наконец, вам нужно создать файл ресурсов: "file_paths". Этот файл необходимо создать в каталоге res / 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>
Брендон
источник
83
«Облегчить жизнь разработчикам» - это девиз каждого нового API, верно, Google?
Кирилл Кармазин
14
Решение, предоставленное Брендоном, является правильным, но оно не готово для копирования и вставки, вам нужно проверить, соответствует ли оно вашим потребностям, например. <external-path ...используется, когда вам нужен Environment.getExternalStorageDirectory (). и используйте, <files-path ...если вам нужен Context.getFilesDir (). Вам лучше сначала проверить официальную документацию: developer.android.com/reference/android/support/v4/content/…
Кирилл Кармазин
10
Напоминаем, что если вы используете androidx (новое пространство имен поддержки), вы можете найти здесь ( developer.android.com/reference/androidx/core/content/… ) соответствующую документацию.
Rodrirokr
23
Обратите внимание, что в androidxнем:android:name="androidx.core.content.FileProvider"
smörkex
151

Добавьте следующий блок кода перед запуском камеры или просмотра файлов

    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    StrictMode.setVmPolicy(builder.build());

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

eranda.del
источник
25
Это неправильный способ решить эту проблему, это в основном удалит политики строгого режима. и проигнорирует предупреждение системы безопасности
Ахсан Захир
У этого есть свои плюсы и минусы. Для получения дополнительной информации обратитесь к следующему
адресу
Это работает, если есть какие-то
Ханан
Код решил для меня исключение. Однако верхний комментарий здесь говорит о том, что код не является правильным способом решения этой проблемы. Кто-нибудь знает, какой тогда будет правильный метод?
Shn_Android_Dev
Google ненавидит программистов.
Жубер Васконселос,
0

Нет обязательной конфигурации поставщика в AndroidManifest, только разрешение на камеру и хранилище. Используйте следующий код для запуска камеры:

final int REQUEST_ACTION_CAMERA = 9;
void openCamra() {
Intent cameraImgIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

cameraImgIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID +".provider",
                new File("your_file_name_with_dir")));
startActivityForResult(cameraImgIntent, REQUEST_ACTION_CAMERA);
}

После захвата изображения вы можете найти его в:

"your_file_name_with_dir"
Хемрадж Патель
источник
Лучше объяснить конфигурацию провайдера в AndroidManifest, чем указывать другой код.
fury.slay
0

добавить код в

onCreate(Budle savedInstancesState){
    if (Build.VERSION.SDK_INT >= 24) {
        try {
            Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
            m.invoke(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
коде
источник