Android support file provider paths

FileProvider

java.lang.Object
android.content.ContentProvider
android.support.v4.content.FileProvider

Class Overview

FileProvider is a special subclass of ContentProvider that facilitates secure sharing of files associated with an app by creating a content:// Uri for a file instead of a file:/// Uri .

A content URI allows you to grant read and write access using temporary access permissions. When you create an Intent containing a content URI, in order to send the content URI to a client app, you can also call Intent.setFlags() to add permissions. These permissions are available to the client app for as long as the stack for a receiving Activity is active. For an Intent going to a Service , the permissions are available as long as the Service is running.

In comparison, to control access to a file:/// Uri you have to modify the file system permissions of the underlying file. The permissions you provide become available to any app, and remain in effect until you change them. This level of access is fundamentally insecure.

The increased level of file access security offered by a content URI makes FileProvider a key part of Android’s security infrastructure.

This overview of FileProvider includes the following topics:

Defining a FileProvider

Since the default functionality of FileProvider includes content URI generation for files, you don’t need to define a subclass in code. Instead, you can include a FileProvider in your app by specifying it entirely in XML. To specify the FileProvider component itself, add a

element to your app manifest. Set the android:name attribute to android.support.v4.content.FileProvider . Set the android:authorities attribute to a URI authority based on a domain you control; for example, if you control the domain mydomain.com you should use the authority com.mydomain.fileprovider . Set the android:exported attribute to false ; the FileProvider does not need to be public. Set the android:grantUriPermissions attribute to true , to allow you to grant temporary access to files. For example:

If you want to override any of the default behavior of FileProvider methods, extend the FileProvider class and use the fully-qualified class name in the android:name attribute of the

Specifying Available Files

element. For example, the following paths element tells FileProvider that you intend to request content URIs for the images/ subdirectory of your private file area.

element must contain one or more of the following child elements:

Represents files in the files/ subdirectory of your app’s internal storage area. This subdirectory is the same as the value returned by Context.getFilesDir() . Represents files in the root of your app’s external storage area. The path Context.getExternalFilesDir() returns the files/ subdirectory of this this root. Represents files in the cache subdirectory of your app’s internal storage area. The root path of this subdirectory is the same as the value returned by getCacheDir() .

These child elements all use the same attributes:

name=»name» A URI path segment. To enforce security, this value hides the name of the subdirectory you’re sharing. The subdirectory name for this value is contained in the path attribute. path=»path» The subdirectory you’re sharing. While the name attribute is a URI path segment, the path value is an actual subdirectory name. Notice that the value refers to a subdirectory, not an individual file or files. You can’t share a single file by its file name, nor can you specify a subset of files using wildcards.

Читайте также:  Когда выйдет андроид 4 для всех

You must specify a child element of

for each directory that contains files for which you want content URIs. For example, these XML elements specify two directories:

element and its children in an XML file in your project. For example, you can add them to a new file called res/xml/file_paths.xml . To link this file to the FileProvider, add a element as a child of the

element that defines the FileProvider. Set the element’s «android:name» attribute to android.support.FILE_PROVIDER_PATHS . Set the element’s «android:resource» attribute to @xml/file_paths (notice that you don’t specify the .xml extension). For example:

Generating the Content URI for a File

To share a file with another app using a content URI, your app has to generate the content URI. To generate the content URI, create a new File for the file, then pass the File to getUriForFile() . You can send the content URI returned by getUriForFile() to another app in an Intent . The client app that receives the content URI can open the file and access its contents by calling ContentResolver.openFileDescriptor to get a ParcelFileDescriptor .

For example, suppose your app is offering files to other apps with a FileProvider that has the authority com.mydomain.fileprovider . To get a content URI for the file default_image.jpg in the images/ subdirectory of your internal storage add the following code: As a result of the previous snippet, getUriForFile() returns the content URI content://com.mydomain.fileprovider/my_images/default_image.jpg .

Granting Temporary Permissions to a URI

Permissions granted in an Intent remain in effect while the stack of the receiving Activity is active. When the stack finishes, the permissions are automatically removed. Permissions granted to one Activity in a client app are automatically extended to other components of that app.

Serving a Content URI to Another App

There are a variety of ways to serve the content URI for a file to a client app. One common way is for the client app to start your app by calling startActivityResult() , which sends an Intent to your app to start an Activity in your app. In response, your app can immediately return a content URI to the client app or present a user interface that allows the user to pick a file. In the latter case, once the user picks the file your app can return its content URI. In both cases, your app returns the content URI in an Intent sent via setResult() .

You can also put the content URI in a ClipData object and then add the object to an Intent you send to a client app. To do this, call Intent.setClipData() . When you use this approach, you can add multiple ClipData objects to the Intent , each with its own content URI. When you call Intent.setFlags() on the Intent to set temporary access permissions, the same permissions are applied to all of the content URIs.

Note: The Intent.setClipData() method is only available in platform version 16 (Android 4.1) and later. If you want to maintain compatibility with previous versions, you should send one content URI at a time in the Intent . Set the action to ACTION_SEND and put the URI in data by calling setData() .

Читайте также:  Ошибка андроид process acore произошла как исправить android lenovo

More Information

To learn more about FileProvider, see the Android training class Sharing Files Securely with URIs.

Источник

Делимся файлами в Android с помощью FileProvider

Несколько недель назад мне было поручено открыть внутренний PDF-файл в любом приложении для чтения PDF на Android устройстве. Я думал, что это будет просто, но все оказалось сложнее. Документация Google по FileProvider оказалась запутанной и не имела конкретных примеров. Тем не менее, я знал, что должен использовать ContentProvider для решения этой проблемы.

Как один из примеров использования FileProvider, вы можете посмотреть следующий урок.

Что такое FileProvider?

ContentProvider — это компонент Android, который инкапсулирует данные и предоставляет их другим приложениям. Это необходимо в случае, если вам нужно обмениваться данными между несколькими приложениями. Например, данные контактов совместно используются другими приложениями, используя ContactsProvider, который является подклассом ContentProvider.

FileProvider — это подкласс ContentProvider. Хотя ContentProvider — это компонент, который позволяет вам безопасно делиться любыми данными, FileProvider используется специально для совместного использования внутренних файлов приложения. Класс FileProvider является частью библиотеки поддержки v4, поэтому обязательно включите ее в свой проект.

Чтобы заставить FileProvider работать, нужно выполнить следующие три действия:

  • Определить FileProvider в файле AndroidManifest.xml;
  • Создать XML-файл, содержащий все пути, которые FileProvider будет использовать совместно с другими приложениями;
  • Связать действительный URI в Intent и активировать его.

Определение FileProvider

Чтобы определить FileProvider внутри AndroidManifest.xml, вам необходимо ознакомиться с этими атрибутами и элементами:

  • android:authorities
  • android:exported
  • android:grantUriPermissions
  • android:name
  • субэлемент

Если всё это вам уже знакомо, ваше изучение FileProvider пройдёт немного легче, иначе я подготовил подробное описание каждого атрибута и его цели.

android:authorities

Вы должны определить хотя бы одно уникальное полномочие. Система Android хранит список всех поставщиков, и она отличает их по полномочиям. Полномочие определяет FileProvider точно так же, как ID приложения определяет приложение для Android.

В общем, Android-система использует определенную схему URI для ContentProviders. Схема определяется как content:///

, поэтому система будет знать, какой ContentProvider запрашивается, сопоставляя полномочия URI с полномочиями ContentProvider.

android:exported

Этим атрибутом можно легко злоупотребить, потому что его имя вводит в заблуждение. Чтобы понять смысл этого атрибута, подумайте о своем FileProvider как о комнате с запертыми дверями. Если вы установите значение true, вы в основном откроете свои двери для всех. Все будет работать как вы и программировали, но вы только что создали огромную проблему безопасности, так как каждое другое приложение сможет использовать ваш FileProvider без получения разрешения.

Это должно научить вас никогда не программировать по наитию и всегда быть в курсе побочных эффектов вашего кода. Кроме того, всегда определяйте этот атрибут, потому что значение по умолчанию для SDK 16 и ниже true.

android:grantUriPermissions

Если мы продолжим думать о FileProvider как о запертой комнате, то этот атрибут используется для предоставления временного одноразового ключа для внешнего приложения. Этот атрибут позволяет безопасно обмениваться внутренним хранилищем вашего приложения. Все, что вам нужно сделать, это добавить FLAG_GRANT_READ_URI_PERMISSION или FLAG_GRANT_WRITE_URI_PERMISSION в намерение, которое активирует компонент для открытия внутреннего файла вашего приложения. Чтобы использовать эти флаги, установите для них значение true.

может также иметь субэлементы . Единственное различие заключается в том, что с помощью атрибута вы можете поделиться чем-либо внутри внутреннего хранилища вашего приложения, в то время как субэлементы позволяют вам выбрать конкретное подмножество данных для совместного использования. Чтобы вместо этого использовать субэлементы, установите значение false.

Читайте также:  Android bundle get all

субэлемент

Этот субэлемент должен быть определен при использовании FileProvider. Вы должны определить путь к XML-файлу, который содержит все пути данных, которые ваш FileProvider может использовать с внешними приложениями.

XML-файл должен иметь элемент

в качестве его корня. Элемент

должен иметь как минимум один дочерний элемент, который может быть следующим:

  • — внутреннее хранилище приложения, Context#getFilesDir()
  • — кэш внутреннего хранилища приложения, Context#getCacheDir()
  • — публичное внешнее хранилище, Environment.getExternalStorageDirectory()
  • — внешнее хранилище приложения, Context#getExternalFilesDir(null)
  • — кэш внешнего хранилища приложения, Context#getExternalCacheDir()

Возможно, вы заметили, что они различаются в зависимости от каталога приложения, которое они определяют.

Каждый элемент должен иметь атрибуты path и name. Атрибут path определяет подкаталог, который вы хотите использовать, и он не поддерживает подстановочные знаки. Атрибут name используется по соображениям безопасности, и он заменит ваше имя подкаталога на его значение.

android:name

С помощью этого атрибута мы устанавливаем это значение для android.support.v4.content.FileProvider.

После того, как вы определили FileProvider в своем AndroidManifest.xml, вы, наконец, готовы его использовать. Чтобы поделиться файлом, вам нужно создать намерение и предоставить ему действительный URI. URI генерируется с использованием класса FileProvider.

Реализация кода

androidmanifest.xml

Обратите внимание, что я использую идентификатор приложения для полномочий. Это связано с тем, что у меня есть несколько разновидностей в проекте, и они могут быть установлены на устройстве одновременно. Система Android не позволит вам устанавливать несколько приложений с одним и тем же FileProvider, поэтому каждая разновидность должна иметь уникальные полномочия.

file_provider_paths.xml

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

Использование вашего FileProvider

Как только вы поймете, как это работает, реализация вашего собственного FileProvider станет действительно простой.

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

Делимся файлами в Android с помощью FileProvider : 9 комментариев

android:name=»android.support.v4.content.FileProvider»
почему в моем провайдере подсвечивается красным v4.content.FileProvider

В androidx это androidx.core.content.FileProvider

String uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID, file);

возвращаемый тип данных Uri, а не String
Uri uri = FileProvider…

Спасибо.
Я читал StackOverflow и документацию, но так до конца и не понял. Здесь автор написал все очень просто и понятно. Я споткнулся на files-path, а здесь это объяснено.

Не получается через fileProvider сделать фотографию. Т.е. нужно что бы приложенье зппустило камеру передав в него ссылку на доступный фаил. Не понимаю как сделать. Не могли бы вы показать пример как работать с камерой черех fileprovider. Заранее благодарю

Я сейчас над тем же бъюсь и никак не могу реализовать подобное. Я тоже хочу чтобы камера открывалась, сохраняла во внутреннее хранилище фото и всё…
Камера открылась, а код на линии с FileProvider.getUriForFile() умирает((

У меня вопрос.
Должен ли я использовать FileProvider если хочу передать только 1 изображение с Intent’oм, ?

которые вроде бы уже поддерживает возможность передачи потока байт ()
intent.putExtra(Intent.EXTRA_STREAM, uriOfImage);
и нужно только указать путь к этой картинке

Подробнее:
я разрабатываю приложение.
Хочу, чтобы по клику на одной из кнопок открывалось стандартное окно с выбором метода отправки (на e-mail, watsup, … ) и ОТПРАВЛЯЛСЯ ФАЙЛ С ИЗОБРАЖЕНИЕМ, которое лежит в ресурсах приложения в папке Drawable.

Источник

Оцените статью