Внешнее хранилище
Внешнее хранилище относится к хранилищу файлов, которое находится не во внутреннем хранилище и доступно не только для приложения, отвечающего за файл. Основной целью внешнего хранилища является предоставление места для размещения файлов, которые должны совместно использоваться приложениями или слишком велики для размещения во внутреннем хранилище.
Ранее внешним хранилищем назывался раздел диска на съемном носителе, таком как SD-карта (также известном как переносное устройство). Это различие уже неактуально, так как устройства Android существенно изменились и многие устройства Android больше не поддерживают съемные носители. Вместо этого некоторые устройства будут выделять часть внутренней ненезависимой памяти в Android, которая может выполнять ту же функцию, что и съемный носитель. Это называется эмулированным хранилищем и по-прежнему считается внешним. Кроме того, у некоторых устройств Android может быть несколько внешних разделов хранилища. Например, в планшете Android (помимо его внутреннего хранилища) может быть эмулированное хранилище и один или несколько слотов для SD-карты. Все эти разделы рассматриваются Android как внешнее хранилище.
На устройствах с несколькими пользователями у каждого пользователя будет выделенный каталог в основном разделе внешнего хранилища для внешнего хранилища. Приложения, в которых работает один пользователь, не будут иметь доступа к файлам другого пользователя на устройстве. Файлы для всех пользователей по-прежнему будут доступны всем для чтения и записи. Тем не менее, Android будет изолировать каждый профиль пользователя от других.
В Xamarin.Android чтение и запись в файлы практически идентична этим процессам в любых других приложениях .NET. Приложение Xamarin.Android определяет путь к файлу, который будет обработан, а затем использует стандартные идиомы .NET для доступа к файлам. Так как фактические пути к внутреннему и внешнему хранилищу могут отличаться на разных устройствах или в разных версиях Android, не рекомендуется жестко кодировать путь к файлам. Вместо этого Xamarin.Android предоставляет собственные API Android, которые помогут определить путь к файлам во внутреннем и внешнем хранилище.
В этом руководстве описываются основные понятия и API в Android, относящиеся к внешнему хранилищу.
Общедоступные и частные файлы во внешнем хранилище
Существует два разных типа файлов, которые приложение может хранить во внешнем хранилище:
Частные файлы — это файлы, относящиеся к приложению (но по-прежнему доступны для чтения и записи в мире). В Android предполагается, что частные файлы хранятся в определенном каталоге во внешнем хранилище. Несмотря на то, что файлы называются "частными", они по-прежнему видимы и доступны для других приложений на устройстве, Android не предоставляет им специальные меры защиты.
Общедоступные файлы — это файлы, которые не считаются конкретными для приложения и предназначены для свободного доступа.
Разница между этими файлами в основном концептуальная. Файлы являются частными, так как они считаются частью приложения, в то время как общедоступные файлы — это любые другие файлы, которые существуют во внешнем хранилище. Android предоставляет два разных API-интерфейса для разрешения путей к частным и общедоступным файлам, но в остальном для чтения и записи в эти файлы используются одни и те же интерфейсы API .NET. Это те же API-интерфейсы, которые рассматриваются в разделе о чтении и записи.
Частные внешние файлы
Частные внешние файлы считаются привязанными к приложению (аналогично внутренним файлам), но содержатся во внешнем хранилище по разным причинам (например, файлы слишком большие для внутреннего хранилища). Как и внутренние файлы, эти файлы будут удалены, если пользователь удалит приложение.
Основное расположение для частных внешних файлов определяется путем вызова метода Android.Content.Context.GetExternalFilesDir(string type)
. Этот метод возвращает объект Java.IO.File
, представляющий частный каталог во внешнем хранилище для приложения. Передача null
этому методу приведет к возвращению пути к каталогу хранилища пользователя для приложения. Например, для приложения с именем пакета com.companyname.app
корневой каталог частных внешних файлов будет таким:
/storage/emulated/0/Android/data/com.companyname.app/files/
Этот документ будет ссылаться на каталог хранилища для частных файлов во внешнем хранилище как PRIVATE_EXTERNAL_STORAGE.
Параметр для GetExternalFilesDir()
представляет собой строку, которая указывает каталог приложения. Этот каталог предназначен для стандартного расположения в логической организации файлов. Строковые значения доступны через константы класса Android.OS.Environment
:
Android.OS.Environment | Directory |
---|---|
DirectoryAlarms | PRIVATE_EXTERNAL_STORAGE/будильники |
DirectoryDcim | PRIVATE_EXTERNAL_STORAGE/DCIM |
DirectoryDownloads | PRIVATE_EXTERNAL_STORAGE/скачать |
DirectoryDocuments | PRIVATE_EXTERNAL_STORAGE/Документы |
DirectoryMovies | PRIVATE_EXTERNAL_STORAGE/Фильмы |
DirectoryMusic | PRIVATE_EXTERNAL_STORAGE/Музыка |
DirectoryNotifications | PRIVATE_EXTERNAL_STORAGE/уведомления |
DirectoryPodcasts | PRIVATE_EXTERNAL_STORAGE/Podcasts |
DirectoryRingtones | PRIVATE_EXTERNAL_STORAGE/Ringtones |
DirectoryPictures | PRIVATE_EXTERNAL_STORAGE/Рисунки |
Для устройств с несколькими разделами во внешнем хранилище каждый раздел будет содержать каталог, предназначенный для частных файлов. Метод Android.Content.Context.GetExternalFilesDirs(string type)
возвращает массив Java.IO.Files
. Каждый объект будет представлять частный каталог приложения для всех совместно используемых устройств с внешними хранилищами, где приложение может размещать принадлежащие ему файлы.
Внимание
Точный путь к частному каталогу внешнего хранилища может отличаться в зависимости от устройства и версии Android. По этой причине приложения не должны жестко задавать путь к этому каталогу. Вместо этого они должны использовать API-интерфейсы Xamarin.Android, например Android.Content.Context.GetExternalFilesDir()
.
Общедоступные внешние файлы
Общедоступные файлы — это файлы, которые существуют во внешнем хранилище и не хранятся в каталоге, который Android выделяет для частных файлов. Общедоступные файлы не удаляются при удалении приложения. Приложения Android должны получить разрешение, прежде чем они смогут считывать или записывать любые общедоступные файлы. Общедоступные файлы могут существовать везде во внешнем хранилище, но по соглашению в Android предусматривается, что общедоступные файлы будут существовать в каталоге, указанном свойством Android.OS.Environment.ExternalStorageDirectory
. Это свойство будет возвращать объект Java.IO.File
, который представляет основной каталог во внешнем хранилище. В качестве примера Android.OS.Environment.ExternalStorageDirectory
может ссылаться на следующий каталог:
/storage/emulated/0/
Этот документ будет ссылаться на каталог хранилища для общедоступных файлов во внешнем хранилище как PUBLIC_EXTERNAL_STORAGE.
Android также поддерживает концепцию каталогов приложений на PUBLIC_EXTERNAL_STORAGE. Эти каталоги в точности совпадают с каталогами приложений для PRIVATE_EXTERNAL_STORAGE
и описаны в таблице в предыдущем разделе. Метод Android.OS.Environment.GetExternalStoragePublicDirectory(string directoryType)
возвращает объект Java.IO.File
, который соответствует общедоступному каталогу приложения. Параметр directoryType
является обязательным и не может иметь значение null
.
Например, вызов Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDocuments).AbsolutePath
вернет строку, которая будет выглядеть так:
/storage/emulated/0/Documents
Внимание
Точный путь к общедоступному каталогу во внешнем хранилище может отличаться в зависимости от устройства и версии Android. По этой причине приложения не должны жестко задавать путь к этому каталогу. Вместо этого они должны использовать API-интерфейсы Xamarin.Android, например Android.OS.Environment.ExternalStorageDirectory
.
Работа с внешним хранилищем
Как только приложение Xamarin.Android получит полный путь к файлу, оно должно использовать любой из стандартных API-интерфейсов .NET для создания, чтения, записи или удаления файлов. Это увеличивает объем кроссплатформенного кода для приложения. Тем не менее, прежде чем пытаться получить доступ к файлу, для приложения Xamarin.Android необходимо убедиться, что к этому файлу можно осуществлять доступ.
- Проверьте внешнее хранилище. В зависимости от характера внешнего хранилища возможно, что оно не может быть подключено и доступно приложению. Все приложения должны проверять состояние внешнего хранилища, прежде чем пытаться его использовать.
- Проверка разрешений среды выполнения. Приложение Android должно запрашивать разрешение от пользователя, чтобы получить доступ к внешнему хранилищу. Это означает, что запрос на разрешение во время выполнения должен быть сделан до осуществления любого доступа к файлу. Руководство Разрешения в Xamarin.Android содержит более подробные сведения о разрешениях Android.
Каждая из этих двух задач будет описана ниже.
Проверка доступности внешнего хранилища
Первым действием перед записью во внешнее хранилище является проверка его доступности для чтения или записи. Свойство Android.OS.Environment.ExternalStorageState
содержит строку для определения состояния внешнего хранилища. Это свойство будет возвращать строку, которая представляет состояние. Эта таблица представляет собой список значений ExternalStorageState
, которые могут быть возвращены Environment.ExternalStorageState
:
ExternalStorageState | Description |
---|---|
MediaBadRemoval | Носитель внезапно удален без отключения надлежащим образом. |
MediaChecking | Носитель присутствует, но проходит проверку диска. |
MediaEjecting | Носитель пребывает в процессе отключения и извлечения. |
MediaMounted | Носитель подключен, в нем можно выполнять операции чтения и записи. |
MediaMountedReadOnly | Носитель подключен, но в нем можно выполнять только операции чтения. |
MediaNofs | Носитель присутствует, но не содержит файловой системы, подходящей для Android. |
MediaRemoved | Носитель отсутствует. |
MediaShared | Носитель присутствует, но не подключен. Его использует через USB-порт другое устройство. |
MediaUnknown | Состояние носителя не распознано Android. |
MediaUnmountable | Носитель присутствует, но его не удалось подключить к Android. |
MediaUnmounted | Носитель присутствует, но отключен. |
Большинству приложений Android нужно будет только проверить, подключено ли внешнее хранилище. В следующем фрагменте кода показано, как проверить, подключено внешнее хранилище только для чтения или для чтения и записи:
bool isReadonly = Environment.MediaMountedReadOnly.Equals(Environment.ExternalStorageState);
bool isWriteable = Environment.MediaMounted.Equals(Environment.ExternalStorageState);
Разрешения внешнего хранилища
Android рассматривает доступ к внешнему хранилищу как опасное разрешение, поэтому обычно запрашивает у пользователя предоставление разрешения на доступ к ресурсу. Пользователь может отозвать это разрешение в любое время. Это означает, что запрос на разрешение во время выполнения должен быть сделан до осуществления любого доступа к файлу. Приложениям автоматически предоставляются разрешения на чтение и запись собственных частных файлов. Приложения могут считывать и записывать частные файлы, принадлежащие другим приложениям, после получения разрешения от пользователя.
Все приложения Android должны объявить одно из двух разрешений для внешнего хранилища в AndroidManifest.xml. Чтобы определить разрешения, один из следующих двух элементов uses-permission
должен быть добавлен в AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Примечание.
Если пользователь предоставил разрешение WRITE_EXTERNAL_STORAGE
, то также неявно предоставляется и READ_EXTERNAL_STORAGE
. Нет необходимости запрашивать оба разрешения в AndroidManifest.xml.
Разрешения также можно добавить на вкладке Манифест Android в разделе свойств решения:
В общем, все опасные разрешения подлежат одобрению пользователем. Разрешения для внешнего хранилища являются аномалией в том смысле, что есть исключения из этого правила в зависимости от версии Android, на которой работает приложение:
Дополнительные сведения о запросах на разрешения во время выполнения см. в руководстве Разрешения в Xamarin.Android. LocalFiles monodroid-sample также демонстрирует один из способов проверки разрешений во время выполнения.
Предоставление и отмена разрешений с помощью adb
Во время разработки приложения Android может потребоваться предоставить и отменить разрешения для проверки различных рабочих процессов, связанных с проверкой разрешений во время выполнения. Для этого можно использовать командную строку и adb. В следующих фрагментах командной строки показано, как предоставлять или отменять разрешения с помощью adb для приложения Android, имя пакета которого — com.companyname.app:
$ adb shell pm grant com.companyname.app android.permission.WRITE_EXTERNAL_STORAGE
$ adb shell pm revoke com.companyname.app android.permission.WRITE_EXTERNAL_STORAGE
Удаление файлов
Любой из стандартных API-интерфейсов C# можно использовать для удаления файла из внешнего хранилища, например System.IO.File.Delete
. Для этого также можно использовать API-интерфейсы Java за счет переносимости кода. Например:
System.IO.File.Delete("/storage/emulated/0/Android/data/com.companyname.app/files/count.txt");