Android permission to read sd card

Русские Блоги

Вопрос разрешения записи на внешнюю SD-карту Android

После недавнего обновления до Android 9.0 я обнаружил, что файловому менеджеру не удалось записать данные на внешнюю SD-карту. File.canWrite() Метод, найденный для возврата false , Обсудив отслеживание и позиционирование, я обнаружил, что это было связано с GoogleизменениеВызванный:

Изменения здесь были удалены WRITE_MEDIA_STORAGE Разрешения, связанные с разрешениями, привели к тому, что внешнее хранилище на SD-карте недоступно для записи.

Затронуто приложение подписи платформы

Эта модификация больше влияет на системные приложения. Для платформ до 9.0 я применил WRITE_MEDIA_STORAGE После разрешения платформы приложение, подписанное платформой, может быть передано java.io.File Интерфейс записан на внешнюю SD-карту. Но после этой модификации, если вы хотите записать на внешнюю SD-карту, вам нужно использовать ее как стороннее приложение. DocumentFile Интерфейс, вы можете прочитать документацию APIСтруктура доступа к хранилищу с участием Использовать доступ к каталогу 。

Порекомендуйте это из Googlebug Приложения платформы, такие как файловый менеджер, камера, галерея и даже MediaProvider, будут иметь внешнюю SD-карту, которую можно только читать и не записывать, то есть проблема сбоя записи, поскольку эти системные приложения не адаптированы. DocumentProvider Способ написания.

DocumentFile адаптационное решение

1. Запросить разрешение на запись на внешнюю SD-карту

Еще в Android 4.4 Android присоединился к структуре доступа к хранилищу. Доступ к внешней SD-карте поддерживается DocumentsUI (com.android.documentsui). После улучшения версии 5.0 и 7.0 в настоящее время существует два вида запросов на внешнюю SD Интерактивный метод разрешения на запись карты:

  • До Android 7.0 используйте ACTION_OPEN_DOCUMENT_TREE, чтобы перейти к интерфейсу выбора хранилища DocumentsUI, а затем пользователь вручную открыл внешнее хранилище и выбрал

  • Android 7.0 и выше, используйтеStorageVolume.createAccessIntent(null) Перейти к окну приглашения на написание разрешения. (Это окно приглашения также предоставляется DocumentsUI, но оно улучшило предыдущее взаимодействие, чтобы избежать громоздких пользовательских операций)

Проверьте свойства интерфейса разрешений, вы увидите, что окно запроса разрешений на самом деле com.android.documentsui/com.android.documentsui.ScopedAccessActivity

Другими словами, DocumentsUI специально сделал окно запроса разрешения, чтобы упростить процесс запроса разрешения.

ПокаStorageVolume.createAccessIntent(String directoryName) Может передаваться во многих типах медиа, включая музыку, изображения, фильмы, документы и т. Д., Если входящий параметр null , Это означает весь внешний раздел хранения.

Parameters
directoryName String : must be one of Environment.DIRECTORY_MUSIC , Environment.DIRECTORY_PODCASTS , Environment.DIRECTORY_RINGTONES , Environment.DIRECTORY_ALARMS , Environment.DIRECTORY_NOTIFICATIONS , Environment.DIRECTORY_PICTURES , Environment.DIRECTORY_MOVIES , Environment.DIRECTORY_DOWNLOADS , Environment.DIRECTORY_DCIM , or Environment.DIRECTORY_DOCUMENTS , or null to request access to the entire volume.
Returns
Intent intent to request access, or null if the requested directory is invalid for that volume.

Запрос на разрешение и обработка

Запрос разрешения должен быть инициирован в Деятельности или Фрагменте, и в то же время onActivityResult Захвачено в Uri ,Вот этот Uri Это может быть сохранено в локальном хранилище для легкого вызова. Запрошенный код инкапсулируется следующим образом:

Вот rootPath Корневой каталог внешней SD-карты, переданный в контексте, такой как /storage/0000-0000 Такой путь можно пройти context.getExternalFilesDirs(«external») Метод. DocumentsUtils Ниже приведен метод реализации класса инструмента.

среди них DocumentsUtils.checkWritableRootPath() Этот метод используется для проверки, есть ли у корневого каталога SD-карты разрешение на запись, если нет, перейдите к запросу на разрешение; DocumentsUtils.saveTreeUri() Способ сохранить возвращенный Uri Информация хранится локально для последующего запроса.

2. Пакет операций с файлами DocumentFile

Поскольку предыдущее приложение использовалось java.io.File Интерфейс работает с внешними файлами SD-карты, и ожидается минимальное количество изменений кода, тогда наилучшим способом является File Сделайте упаковку снова.

До Android 9.0 системные приложения могут передаваться по умолчанию java.io.File Интерфейс записывается на внешнюю SD-карту, но если это стороннее приложение открытого рынка, оно не может быть записано после 4.4, и некоторые производители настраивают версию Android 9.0. Внешнюю SD-карту также можно записывать напрямую без интерфейса DocumentFile, интерфейса DocumentFile ни java.io.File эффективный.

Поэтому лучше всего сначала проверить, есть ли разрешение на запись в файл, если есть разрешение на запись, напрямую использовать операцию интерфейса «Файл», если нет разрешения, а затем проверить, находится ли файл на внешней SD-карте, если файл находится на SD-карте, используйте операцию интерфейса DocumentFile. ,

Упакованные инструменты DocumentsUtils Описание метода,Не совместимы Указывает, что операция DocumentFile не инкапсулирована:

Источник

Data and file storage overview

Android uses a file system that’s similar to disk-based file systems on other platforms. The system provides several options for you to save your app data:

  • App-specific storage: Store files that are meant for your app’s use only, either in dedicated directories within an internal storage volume or different dedicated directories within external storage. Use the directories within internal storage to save sensitive information that other apps shouldn’t access.
  • Shared storage: Store files that your app intends to share with other apps, including media, documents, and other files.
  • Preferences: Store private, primitive data in key-value pairs.
  • Databases: Store structured data in a private database using the Room persistence library.

The characteristics of these options are summarized in the following table:

Type of content Access method Permissions needed Can other apps access? Files removed on app uninstall?
App-specific files Files meant for your app’s use only From internal storage, getFilesDir() or getCacheDir()

From external storage, getExternalFilesDir() or getExternalCacheDir()

Never needed for internal storage

Not needed for external storage when your app is used on devices that run Android 4.4 (API level 19) or higher

No Yes
Media Shareable media files (images, audio files, videos) MediaStore API READ_EXTERNAL_STORAGE when accessing other apps’ files on Android 11 (API level 30) or higher

READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE when accessing other apps’ files on Android 10 (API level 29)

Permissions are required for all files on Android 9 (API level 28) or lower

Yes, though the other app needs the READ_EXTERNAL_STORAGE permission No
Documents and other files Other types of shareable content, including downloaded files Storage Access Framework None Yes, through the system file picker No
App preferences Key-value pairs Jetpack Preferences library None No Yes
Database Structured data Room persistence library None No Yes

The solution you choose depends on your specific needs:

How much space does your data require? Internal storage has limited space for app-specific data. Use other types of storage if you need to save a substantial amount of data. How reliable does data access need to be? If your app’s basic functionality requires certain data, such as when your app is starting up, place the data within internal storage directory or a database. App-specific files that are stored in external storage aren’t always accessible because some devices allow users to remove a physical device that corresponds to external storage. What kind of data do you need to store? If you have data that’s only meaningful for your app, use app-specific storage. For shareable media content, use shared storage so that other apps can access the content. For structured data, use either preferences (for key-value data) or a database (for data that contains more than 2 columns). Should the data be private to your app? When storing sensitive data—data that shouldn’t be accessible from any other app—use internal storage, preferences, or a database. Internal storage has the added benefit of the data being hidden from users.

Categories of storage locations

Android provides two types of physical storage locations: internal storage and external storage. On most devices, internal storage is smaller than external storage. However, internal storage is always available on all devices, making it a more reliable place to put data on which your app depends.

Removable volumes, such as an SD card, appear in the file system as part of external storage. Android represents these devices using a path, such as /sdcard .

Apps themselves are stored within internal storage by default. If your APK size is very large, however, you can indicate a preference within your app’s manifest file to install your app on external storage instead:

Permissions and access to external storage

On earlier versions of Android, apps needed to declare the READ_EXTERNAL_STORAGE permission to access any file outside the app-specific directories on external storage. Also, apps needed to declare the WRITE_EXTERNAL_STORAGE permission to write to any file outside the app-specific directory.

More recent versions of Android rely more on a file’s purpose than its location for determining an app’s ability to access, and write to, a given file. In particular, if your app targets Android 11 (API level 30) or higher, the WRITE_EXTERNAL_STORAGE permission doesn’t have any effect on your app’s access to storage. This purpose-based storage model improves user privacy because apps are given access only to the areas of the device’s file system that they actually use.

Android 11 introduces the MANAGE_EXTERNAL_STORAGE permission, which provides write access to files outside the app-specific directory and MediaStore . To learn more about this permission, and why most apps don’t need to declare it to fulfill their use cases, see the guide on how to manage all files on a storage device.

Scoped storage

To give users more control over their files and to limit file clutter, apps that target Android 10 (API level 29) and higher are given scoped access into external storage, or scoped storage, by default. Such apps have access only to the app-specific directory on external storage, as well as specific types of media that the app has created.

Use scoped storage unless your app needs access to a file that’s stored outside of an app-specific directory and outside of a directory that the MediaStore APIs can access. If you store app-specific files on external storage, you can make it easier to adopt scoped storage by placing these files in an app-specific directory on external storage. That way, your app maintains access to these files when scoped storage is enabled.

To prepare your app for scoped storage, view the storage use cases and best practices guide. If your app has another use case that isn’t covered by scoped storage, file a feature request. You can temporarily opt-out of using scoped storage.

View files on a device

To view the files stored on a device, use Android Studio’s Device File Explorer.

Additional resources

For more information about data storage, consult the following resources.

Videos

Content and code samples on this page are subject to the licenses described in the Content License. Java is a registered trademark of Oracle and/or its affiliates.

Источник

Android permission to read sd card

Android использует файловую систему, которая аналогична дисковым файловым системам на других платформах. Эта лекция описывает, как работать с файловой системой Android для чтения и записи файлов с помощью File API (перевод документации [1]).

Объект File подходит для чтения или записи больших объемов данных в порядке от начала до конца, без пропусков. Например, это хорошо подходит для файлов картинок или для различных обменов данными через сеть. Здесь будет показано, как выполнять базовые файловые операции в Вашем приложении. Подразумевается, что Вы знакомы с файловой системой Linux и стандартной системой ввода/вывода файлов в (standard file input/output API) в java.io.

[Выбор между внутренним и внешним хранилищем (Internal Storage, External Storage)]

Все устройства Android имеют две области хранения файлов (file storage area): «internal» и «external» storage. Эти имена появились на первых стадиях развития Android, когда большинство устройств поставлялись со встроенной энергонезависимой памятью FLASH (internal storage) плюс извлекаемый носитель памяти, такой как micro SD card (external storage). Некоторые устройства делили постоянную область хранения (permanent storage space) на разделы «internal» и «external», так что даже без наличия внешнего извлекаемого хранилища (removable storage medium) всегда имеется 2 пространства хранения, и поведение API всегда одинаково — независимо от того, есть в наличии внешнее хранилище или нет. Следующие списки подводят общую черту под фактическими различиями каждого пространства хранения.

Internal storage (внутреннее, неизвлекаемое хранилище): External storage (внешнее, извлекаемое хранилище):
• Оно всегда доступно.
• Файлы, которые сохранены здесь, по умолчанию доступны только Вашего приложения.
• Не требуется запрашивать разрешения на доступ к internal storage для Вашего приложения.
• Когда пользователь деинсталлирует Ваше приложение, то система также удалит все файлы приложения с internal storage.

Вывод: internal storage лучше подходит, когда ни другие пользователи, ни другие приложения не могли получить доступа к Вашим файлам.

• Оно не всегда доступно, потому что пользователь может монтировать external storage как USB MSD storage (Android работает как флешка, подключенная к компьютеру), и в некоторых случаях может просто извлечь external storage из устройства.
• External storage доступно на чтение для всех, так что файлы, сохраненные туда, могут прочитаны без Вашего контроля над процессом.
• Приложению требуется получить разрешение на доступ к external storage в файле манифеста.
• Когда пользователь деинсталлирует Ваше приложение, система удалит файлы Вашего приложения из external storage только если Вы сохранили их в директории из getExternalFilesDir() .

Вывод: external storage лучшее место для файлов, которые не требуют ограничений на доступ и для файлов, которые Вы хотите сделать общими с другими приложениями, или если Вы хотите, чтобы пользователь мог получить доступ к файлам с помощью компьютера.

Совет: несмотря на то, что приложения по умолчанию устанавливаются в internal storage, Вы можете указать атрибут android:installLocation в файле манифеста, после чего Ваше приложение может быть установлено и на external storage. Пользователи ценят эту опцию, когда размер APK очень велик, и размер external storage space больше, чем internal storage. Дополнительную информацию см. в документации App Install Location [2].

[Получение разрешения для приложения на доступ к External Storage]

Чтобы иметь возможность записи в external storage, Вы должны запросить в файле манифеста разрешение WRITE_EXTERNAL_STORAGE :

Внимание: в настоящее время приложения имеют возможность чтения external storage без специального на то разрешения. Однако это изменится в будущих релизах системы Android. Если Ваше приложение требует чтения external storage (но не записывает в него), то Вам нужно декларировать разрешение READ_EXTERNAL_STORAGE . Чтобы обеспечить будущую работу Вашего приложения так, как это ожидалось, Вы должны декларировать это разрешение уже сейчас, до того как изменения вступят в реальную силу.

Но если Ваше приложение использует разрешение WRITE_EXTERNAL_STORAGE, то это неявно дает ему также разрешение использовать и чтение external storage.

Вам не нужно получать никаких разрешений на сохранение файлов в internal storage. Ваше приложение всегда имеет разрешение на чтение и запись файлов в свой внутренний каталог на internal storage.

[Сохранение файла в Internal Storage]

Когда сохраняется файл в internal storage, Вы можете запросить подходящую директорию для объекта файла File вызовом одного из двух методов:

getFilesDir() возвращает объект File, представляющий внутренний каталог Вашего приложения.
getCacheDir() возвращает объект File, представляющий внутренний каталог временных файлов кэша Вашего приложения. Обязательно удаляйте оттуда каждый файл, когда он больше не нужен, и реализуйте разумный предел размера для объема памяти, который используете в любой момент времени, такой как предел в 1 мегабайт. Если система Android обнаружит, что на внутреннем хранилище недостаточно места, то она может удалить Ваши файлы кэша без предупреждения.

Чтобы создать новый файл в одной из этих директорий, Вы можете использовать конструктор File(), передав ему File, предоставленный одним из этих методов, которые укажут каталог на internal storage. Пример:

Альтернативно Вы можете вызвать openFileOutput(), чтобы получить FileOutputStream, который записывает файл в Вашей внутренней директории. Например, здесь показано, как записать некий текст в файл:

Или, если Вам нужно кэшировать некоторые файлы, Вы должны вместо этого использовать createTempFile() . Например, следующий метод вытаскивает имя файла из URL и создает файл с таким именем во внутренней директории для кэша Вашего приложения:

Примечание: каталог internal storage Вашего приложения указывается на основе имени пакета приложения в специальном месте файловой системы Android. Технически другое приложение может прочитать Ваши внутренние файлы, если Вы установите файловый режим с разрешенным чтением. Однако для этого другое приложение должно также знать имя пакета Вашего приложения и имена используемых Вашим приложением файлов. Другие приложения не могут просматривать Ваши внутренние директории, и не могут получить доступ на чтение или запись, за исключением случая, когда Вы явно установите файл как читаемый и/или записываемый. Таким образом, пока Вы используете MODE_PRIVATE для Ваших файлов на internal storage, то они никогда не будут доступны для других приложений.

[Сохранение файла в External Storage]

Поскольку external storage иногда может быть недоступно (когда пользователь смонтировал его как внешний USB-носитель на PC, или когда вытащил карту SD из телефона), то перед доступом к тому Вы должны всегда проверить, что он есть в наличии. Вы можете запросить состояние external storage вызовом getExternalStorageState() . Если возвращенное состояние External Storage равно MEDIA_MOUNTED , то Вы можете читать и записывать на него свои файлы. Например, следующие методы полезны для определения доступности устройства хранения:

Несмотря на то, что external storage может быть модифицировано пользователем и другими приложениями, есть две категории файлов, которые могут быть сохранены здесь:

Публичные файлы (Public files) — это файлы, которые должны быть свободно доступны для других приложений и пользователя. Когда пользователь деинсталлирует Ваше приложение, эти файлы должны остаться доступными для пользователя. Например, такими файлами могут быть фотографии, созданные другими приложениями или другие файлы, загруженные через сеть.

Частные файлы (Private files) — это файлы, полные права на которые принадлежат Вашему приложению, и которые должны быть удалены при деинсталляции Вашего приложения пользователем. Несмотря на то, что эти файлы технически доступны для пользователя и других приложений, поскольку они находятся на внешнем извлекаемом хранилище (external storage), эти файлы не имеют в реальности особого значения для пользователя вне Вашего приложения. Когда пользователь деинсталлирует Ваше приложение, система удалит все файлы в Вашем частном каталоге на внешнем хранилище. Примером таких файлов могут быть дополнительные ресурсы, загруженные Вашим приложением или временные медиафайлы.

Если Вы хотите сохранить public-файлы на external storage, используйте метод getExternalStoragePublicDirectory() для получения экземпляра File , предоставляющего подходящую директорию на external storage. Метод принимает аргумент, указывающий тип файла, который Вы хотите сохранить, так чтобы типы файла были логически организованы с другими public-файлами, такими как DIRECTORY_MUSIC или DIRECTORY_PICTURES . Пример:

Если Вы хотите сохранить файлы, которые являются частными (private) для Вашего приложения, Вы можете получить подходящую директорию вызовом метода getExternalFilesDir() и передачей ему имени, указывающего тип директории, который Вам нужен. Каждая директория, созданная таким способом, будет добавлена к родительской директории, в которой инкапсулированы все файлы внешнего хранилища Вашего приложения, которые система удалит, когда пользователь деинсталлирует Ваше приложение. Например, вот метод, которым Вы можете создать директорию индивидуального фотоальбома:

Если ни одно из предварительно определенных имен поддиректорий не подходит для Ваших файлов, то Вы можете вместо этого вызвать getExternalFilesDir() и передать null. Это возвратит корневую частную директорию для Вашего приложения на external storage.

Помните, что getExternalFilesDir() создает директорию внутри директории, которая будет удалена при деинсталляции Вашего приложения. Если файлы, которые Вы сохраняете, должны оставаться доступными после того, как пользователь деинсталлирует Ваше приложение — как например если Ваше приложение работает с фотокамерой, и пользователь хотел бы сохранить сделанные фотографии — Вы должны вместо этого использовать getExternalStoragePublicDirectory() .

Независимо от того, используете ли Вы для публичных файлов getExternalStoragePublicDirectory() или getExternalFilesDir() для частных файлов приложения, важно иметь в виду, что Вы используете имена директорий, предоставленные константами API наподобие DIRECTORY_PICTURES . Эти имена директорий гарантируют, что система будет правильно рассматривать эти файлы. Например файлы, сохраненные в DIRECTORY_RINGTONES , будут рассортированы медиасканером системы как рингтоны вместо музыки.

[Опрос количества свободного места]

Если Вы знаете заранее, сколько файлов сохраняете, то можете без получения ошибок IOException узнать, сколько места осталось путем вызова getFreeSpace() или getTotalSpace() . Эти методы предоставляют соответственно текущее доступное пространство и общее пространство на томе хранения. Эта информация также полезна, чтобы избежать переполнения тома хранения свыше определенного порога.

Однако система не гарантирует, что Вы можете записать столько байт, сколько показывает вызов getFreeSpace(). Если возвращенное количество всего на несколько мегабайт больше, чем Вам нужно сохранить, или если файловая система уже заполнена меньше, чем на 90%, то вероятно сохранение будет безопасным. Иначе возможно, что записать данные в хранилище не получится.

Внимание: Вам не обязательно проверять количество свободного места перед сохранения файла. Вместо этого Вы можете попробовать записать файл сразу же, и затем перехватить исключение IOException, если оно произойдет. Вы возможно, должны так поступить, когда не знаете, сколько места Вам нужно. Например, если Вы меняете способ кодирования файла перед его сохранением, преобразовывая картинку PNG в JPEG, то Вы не будете знать размер файла заранее.

[Удаление файла]

Вы всегда должны удалять файлы, которые Вам больше не нужны. Самый прямой способ удаления файла состоит в том, чтобы иметь этот файл открытым и вызвать delete() для самого себя.

Если файл сохранен на internal storage, Вы можете также запросить Context, чтобы найти и удалить файл вызовом deleteFile():

Внимание: когда пользователь деинсталлирует Ваше приложение, система Android удалит следующее:

• Все файлы, сохраненные Вашим приложением на internal storage.
• Все файлы, сохраненные Вашим приложением с использованием getExternalFilesDir().

Однако Вы должны регулярно удалять все кэшируемые файлы, создаваемые с getCacheDir(), и также регулярно удалять файлы, которые Вам больше не нужны.

[Пример записи файла на sdcard0]

Предположим, что необходимо записать какой-нибудь тестовый файл (с именем myFile.txt) в папку myFolder на внешний носитель, который виден в системе Android как sdcard0. Т. е. полный путь должен выглядеть примерно так:

Базовый путь до External Storage

Проблема тут состоит в том, чтобы узнать часть пути basePath, поскольку на разных системах Android этот путь будет разным, в зависимости от версии и внутреннего аппаратного устройства. В моем телефоне Samsung Galaxy Note этот basePath = /storage/sdcard0 , но это еще не значит, что на Вашем телефона этот путь будет именно таким. Чтобы получить basePath, используйте вызов функции getExternalStorageDirectory :

Проверка доступности носителя данных в External Storage

Вторая проблема состоит в доступности на запись носителя данных. Дело в том, что записать на носитель можно не всегда, например если он смонтирован как флешка USB (когда Ваш телефон подключен к компьютеру в режиме Mass Storage Device, USB MSD). Проверить доступность носителя можно следующей функцией:

Разрешение доступа к носителю данных в файле манифеста

Как уже упоминалось, необходимо в файле манифеста запросить разрешение WRITE_EXTERNAL_STORAGE . Вот пример такого файла манифеста:

Функция, которая сохраняет файл, принимая полный путь до файла filePath и сохраняемый текст FileContent:

Вызов функции SaveFile, который выполняет задачу сохранения файла в External-носителе:

[Пример записи файла на extSdCard]

Получение полного корневого пути до извлекаемой карты SD не так прост, как до External Storage, поскольку в API Android для этого почему-то не предусмотрены специальные простые функции. Приходится получать путь окольными путями, через имена системных папок. Вот код функции, которая получает путь до извлекаемой карты SD:

Вызов функции SaveFile, который выполняет задачу сохранения файла на извлекаемой карте SD:

[Сохранение бинарного файла (массива byte[])]

В предыдущих примерах мы рассматривали класс OutputStreamWriter , который позволяет записать строку String или массив символов char[]. Но как быть, если нужно записать массив байт byte[]? Для этого подойдет класс DataOutputStream . Пример:

Примеры вызовов getAbsolutePath:

Вызов Результат вызова
Environment.getRootDirectory.getAbsolutePath() /system
Environment.getExternalStorageDirectory().getAbsolutePath() /storage/sdcard0
Environment.getExternalStoragePublicDirectory(null).getAbsolutePath() завершится с ошибкой
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS).getAbsolutePath() /storage/sdcard0/Alarms

[Ссылки]

1. Saving Files site:developer.android.com .
2. App Install Location site:developer.android.com .

Комментарии

В новых Android доступ на запись надо оформлять не в Манифесте. Вот что пишут: «Android added new permission model for Android 6.0 (Marshmallow). What Are Runtime Permissions? With Android 6.0 Marshmallow, Google introduced a new permission model that allows users to better understand why an application may be requesting specific permissions. Rather than the user blindly accepting all permissions at install time, the user is now prompted to accept permissions as they become necessary during application use.

microsin: ИМХО, это предупреждение чисто информационное, ничего не поменялось, разве что название. Раньше было все то же самое — перед установкой приложения Android показывает пользователю, какие действия будут разрешены приложению. Если пользователь согласен, то он подтверждает действие и установка продолжится, если нет — приложение не установится.

Источник

Читайте также:  Whatsapp для андроид rus
Оцените статью