Android: Как получить контент: // URI для файла во внешнем хранилище PUBLIC-каталог

Я следил за этим учебным пособием Google, чтобы начать собирать изображение с new Intent(MediaStore.ACTION_IMAGE_CAPTURE) . В учебнике рекомендуется использовать getExternalStoragePublicDirectory каталог с getExternalStoragePublicDirectory который getExternalStoragePublicDirectory для моего приложения. Но вместо этого их пример использует getExternalFilesDir . Затем, чтобы передать URI файла в намерение с помощью MediaStore.EXTRA_OUTPUT мне нужно получить URI контента, потому что я хочу настроить таргетинг на Android N. Перед тем, как таргетинг NI будет просто передавать файл: // URI и все, кроме Google, было бы счастливо , Теперь на NI началось получение FileUriExposedException которое кажется не очень благоприятным .

Поэтому, учитывая, что у меня есть такой файл …

 private File createImageFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyAppFolder"); if (!storageDir.exists() && !storageDir.mkdir()) Log.w(TAG, "Couldn't create photo folder: " + storageDir.getAbsolutePath()); File image = new File(storageDir, timeStamp + ".jpg"); mCurrentPhotoPath = image.getAbsolutePath(); return image; } 

… могу ли я использовать встроенный провайдер для каталога общедоступных изображений для получения URI контента? Если да, то как?

Я пробовал что-то вроде

 takePictureIntent.putExtra( MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(this, MediaStore.AUTHORITY, createImageFile())); 

Но он просто бросает

IllegalArgumentException: отсутствующие метаданные android.support.FILE_PROVIDER_PATHS

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

Solutions Collecting From Web of "Android: Как получить контент: // URI для файла во внешнем хранилище PUBLIC-каталог"

TL: DR <external-path name="MyAppFolder" path="." /> <external-path name="MyAppFolder" path="." /> Работает, но безопасно ли это?

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

Как упоминалось в @CommonsWare, вам нужно будет заменить MediaStore.AUTHORITY из вашего примера на "com.example.fileprovider" , который является полномочием, который вы определите в своем манифесте так …

В <application> в AndroidManifest введите следующее:

 <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> 

Исключение, которое вы получаете, связано с тем, что <meta-data> который ссылается на файл xml со всеми путями, FileProvider вашего FileProvider . Но именно в этом файле я боролся с собой.

К концу учебного пособия, которое вы связали, в конце раздела « Сохранить полноразмерную фотографию » пример Google для этого file_paths.xml :

 <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" /> </paths> 

"my_images" будет заменен на "MyAppFolder" в вашем примере. В этом учебнике Google утверждает, что

Компонент пути соответствует пути, возвращаемому getExternalFilesDir () при вызове с помощью среды.DIRECTORY_PICTURES. Убедитесь, что вы заменили com.example.package.name фактическим именем пакета вашего приложения.

… и набрав это, я понял, что это НЕ относится к публичному каталогу Pictures, который мы и я ищем. Это объясняет, почему использование этого пути создает это исключение:

Java.lang.IllegalArgumentException: Не удалось найти настроенный корень, содержащий /storage/emulated/0/Pictures/MyAppFolder/{filename}.jpg

Я оставлю это здесь для будущей справки и перейду к ответу на ваш большой вопрос: какой путь вы можете указать, чтобы другие приложения могли взаимодействовать с файлом в общедоступном каталоге «Картинки», созданном вашим приложением, ориентированным на API-уровень 24+?

Как сказал @CommonsWare, «детали вашего желаемого подкаталога меняются по устройству», поэтому вы не можете объявить путь к общедоступному каталогу Pictures, но я нашел способ, который работает.

<external-path name="MyAppFolder" path="." /> <external-path name="MyAppFolder" path="." /> Позволит вашему FileProvider предоставлять URI контента другим приложениям (например, Camera), которые затем могут читать и записывать в файл, который он разрешает.

Если есть какие-то опасности или недостатки, я бы хотел их услышать.

Вот что я использую в своем приложении для общего каталога Pictures.

  1. Создайте файл следующим образом:

     File theFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "YOUR_APP_NAME" + File.separator + "YOUR_FILE_NAME"); 
  2. Укажите следующий путь в метаданных поставщика файлов:

     <paths> <external-path name="secure_name" path="Pictures/YOUR_APP_NAME" /> </paths> 

«Secure_name» используется, чтобы скрыть имя подкаталога ( «YOUR_APP_NAME» в этом случае), которое вы используете по соображениям безопасности.

«Картинки» соответствуют Environment.DIRECTORY_PICTURES .

  1. Получите Uri для отправки с Intent :

     final Uri theUri = FileProvider.getUriForFile(activity, getString(R.string.fileprovider_authorities), theFile); theIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); theIntent.putExtra(MediaStore.EXTRA_OUTPUT, theUri);