Поскольку getExternalStoragePublicDirectory устарел в Android Q, рекомендуется использовать другие средства. тогда как мы можем указать, что мы хотим хранить сгенерированные фотографии из приложения камеры в папке DCIM или в пользовательской подпапке в DCIM?
В документации указано, что следующие 3 варианта являются новыми предпочтительными альтернативами:
Вариант 1 исключен, так как это будет означать, что фотографии будут удалены, если приложение будет удалено.
Вариант 3 также не подходит, так как пользователь должен выбрать местоположение через файловый менеджер SAF.
У нас остается вариант 2, MediaStore; но на момент этого вопроса нет документации о том, как использовать его в качестве замены для getExternalStoragePublicDirectory в Android Q.
Основываясь на документах, используйте DCIM/... для RELATIVE_PATH, где ... — это любой ваш пользовательский подкаталог. Итак, вы бы закончили с чем-то вроде этого:
val resolver = context.contentResolver
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "CuteKitten001")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/PerracoLabs")
}
val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
resolver.openOutputStream(uri).use {
// TODO something with the stream
}
Обратите внимание, что, поскольку RELATIVE_PATH является новым для уровня API 29, вам нужно будет использовать этот подход на более новых устройствах и использовать getExternalStoragePublicDirectory() на старых.
Что, если бы я хотел получить корневой путь для выполнения других операций, а не только для вставки фотографии. например у меня было Environment.getExternalStorageDirectory() + "/myFolder". теперь, что я должен сделать, чтобы получить этот путь с MediaStore как String/File/Uri?
@S.R: у вас нет доступа файловой системы к произвольным местам во внешнем хранилище на Android Q (по умолчанию) и Android R (для всех приложений). Таким образом, вы должны сосредоточиться на выполнении других операций, используя подход, не требующий доступа к файловой системе. Или придерживайтесь getExternalFilesDir() на Context.
последний вопрос! Безопасно ли использовать getParentFile на getExternalFilesDir()4 раза на всех устройствах, чтобы получить то, что я ищу?
@S.R: Нет. Во-первых, как я уже писал, у вас нет доступа к файловой системе к произвольным местам во внешнем хранилище на Android Q (по умолчанию) и Android R (для всех приложений). У вас не будет доступа к местоположению, к которому вы пытаетесь получить доступ. Кроме того, нет необходимости, чтобы ваш алгоритм работал на каком-либо конкретном устройстве.
Добавьте свою статью: commonsware.com/blog/2019/04/22/….
Интересно, действительно ли нет возможности реализовать это один раз. Это работает, но я понял это намного раньше. Я не обязательно хочу продолжать использовать getExternalStoragePublicDirectory(), а также новый подход. Теперь у меня есть несколько if/else, чтобы определить версию Android, выкинув кодовую базу, чтобы сделать это как по-новому, так и по-старому.
Этот новый подход не позволяет вам получить доступ к ранее созданным файлам, не так ли? Например, если я сделал приложение для камеры, которое помещает файлы в указанную вами папку, а затем удалил и переустановил свое приложение, я больше не смогу получить к ним доступ, не так ли? Я думаю, что разрешение на хранение было заменено другими разрешениями, более ограниченными, нет (может быть, может обрабатывать только медиафайлы)? Кроме того, есть ли список всех возможных типов файлов, которые разрешено создавать? Это только медиафайлы или любой файл (например, PDF, ZIP, APK,...)?
@androiddeveloper: «если я сделаю приложение для камеры, которое помещает файлы в указанную вами папку, а затем удалю и переустановлю свое приложение, я больше не смогу получить к ним доступ, не так ли?» -- правильный. С точки зрения Android файлы из предыдущей установки вашего приложения ничем не отличаются от файлов из какого-то другого произвольного приложения. «Я думаю, что разрешение на хранение было заменено другими разрешениями, которые более ограничены, нет (возможно, могут обрабатывать только медиафайлы)?» -- они избавились от них в бета-версии 3.
@androiddeveloper: «есть ли список всех возможных типов файлов, которые разрешено создавать?» -- Не то, чтобы я знаю. «Это только медиафайлы или любой файл (например, PDF, ZIP, APK,...)?» -- Я думаю, что вы ограничены медиафайлами с точки зрения использования MediaStore.
@CommonsWare Они сильно изменили свои решения в бета-версиях Q. Очень трудно следить и знать, что происходит на самом деле. То есть сейчас только SAF для доступа к файлам? И MediaStore, чтобы получить глобальные, предназначенные только для медиафайлов (которые я не знаю, что может быть «медиа», за исключением, может быть, некоторых общих файлов изображений, видео и аудио)? На самом деле довольно грустно, что ПК, подключенный к устройству, может легко показать вам все файлы и с путями (хотя и не настоящими путями), а на самом устройстве мы должны использовать SAF...
@androiddeveloper: «Теперь для доступа к файлам есть только SAF?» -- АФАИК, да. «И MediaStore, чтобы получить глобальные, которые предназначены только для медиафайлов (которые я не знаю, что может быть «медиа», за исключением, может быть, некоторых общих файлов изображений, видео и аудио)?» -- АФАИК, да.
@CommonsWare Не могли бы вы указать мне самую последнюю документацию о MediaStore? Я считаю плохим решением то, что Google даже не объясняет, что такое «медиа». Я должен написать им об этом. Я искал во многих местах и все еще не мог найти. Я заметил, что вы написали как минимум 10 статей о разрешении на хранение. Я предполагаю, что вы заработаете больше, когда Q действительно выйдет из строя. Я надеюсь, что будет способ преодолеть ограничения на пути к файлам. Это требуется для многих библиотек, в том числе для самой платформы Android (например, для разбора файлов APK и DB).
@androiddeveloper: я уверен, что вы уже читали developer.android.com/preview/privacy/scoped-storage и developer.android.com/preview/…. Я ничего не знаю в стандартной документации об изменениях Android Q по этим темам.
@CommonsWare Спасибо. Я думаю, что глядя на документы, которые вы показали, это означает, что «медиа» означает «Фотографии, которые хранятся в MediaStore.Images.», «Видео, которые хранятся в MediaStore.Video.», «Музыкальные файлы, которые хранятся в MediaStore.Audio." . Достигнув каждого из них, кажется, что все дело в миметипе: audio/*, video/*, image/*. Что приложения медиаплеера (видео, аудио и изображения) запрашивают у ОС на Q, если это не разрешение на хранение? Что видит пользователь? Интересно, обновил ли Google свои образцы для Q в этом вопросе.
@androiddeveloper: «Что приложения медиаплеера (видео, аудио и изображения) запрашивают у ОС на Q, если это не разрешение на хранение?» -- просят READ_EXTERNAL_STORAGE. Это описано в developer.android.com/preview/privacy/scoped-storage.
@CommonsWare Понятно. Кажется, я пропустил эту часть. Итак, насколько я помню, разрешение на хранение сильно уменьшилось. Он разрешает доступ только к медиафайлам, и даже тогда он не может получить всю информацию о них (метаданные) по умолчанию. И он даже не разрешает доступ к этим файлам с использованием пути к файлу, потому что если бы это было так, это означало бы, что я мог бы просто использовать InputStream, чтобы получить все, что находится внутри медиафайла, включая защищенные метаданные... Верно?
@androiddeveloper: Это описание соответствует моему пониманию.
@CommonsWare Я вижу. Спасибо.
@CommonsWare Подождите, что касается медиафайлов, здесь говорится, что для получения всех метаданных нам потребуется разрешение «ACCESS_MEDIA_LOCATION». Добавляя его, я заметил, что он принадлежит к группе разрешений на хранение. Так зачем он вообще нужен? Ведь он будет предоставлен вместе с разрешением на хранение... Странно
«ACCESS_MEDIA_LOCATION», по-видимому, является их главной причиной абстрагирования нас от файловой системы. Без этого разрешения вы не сможете увидеть временную метку места, где были сделаны фотографии (обычно это формат .jpg, поэтому вы можете извлечь его из самого файла, а не из хранилища). Если у вас нет разрешения на доступ к .jpg, вы можете получить доступ к входному потоку, который предоставляет медиастор, вы удалите эту информацию из потока. Разрешение на хранение используется только для того, чтобы медиастор давал вам доступ к носителям, которые вы сами не создавали.
Есть ли для этого пример Java?
@GauravMall: У кого-то может быть такой - у меня нет. Извиняюсь!
Ох, ну ладно. Кстати, этот код есть в какой-то документации?
Опубликовал ответ на Java. Спасибо за ответ :)
@GauravMall: «этот код есть в какой-то документации?» -- Кажется, я создал его на основе этот пример сохранения видео через MediaStore. Я просто настроил его для изображений.
@CommonsWare Как я могу создать папку в Android Q, поскольку getExternalStoragePublicDirectory() устарела. Помощь будет оценена.
@TusharPingale: используйте методы Context, например getExternalFilesDir(). См. это и это.
Проблема с MEDIA STORE: он предназначен для медиафайлов (аудио, изображений и видео). Мое приложение сохраняет 2 базы данных (sqlite) в каталоге DOWNLOAD, и мне нужны эти файлы для работы... Я не хочу загружать и сохранять эти файлы db в MOVIES или другом медиа-каталоге, я хочу продолжать загружать свои файлы в подкаталог каталога DOWNLOAD, как я делаю уже несколько лет! Я не могу обновить цель SDK приложения до 29 из-за этой проблемы. Есть ли у кого-то решение? СПАСИБО
@Christian: «Проблема с MEDIA STORE: он создан для медиафайлов (аудио, изображений и видео)» — Android 10 также добавил MediaStore.Downloads. «Я хочу продолжить загрузку моих файлов в подкаталог каталога DOWNLOAD» — используйте MediaStore.Downloads. См. commonsware.com/blog/2020/01/11/…
@CommonsWare Проблема в том, что нет способа «обновить» файлы, созданные моим приложением (без перезагрузки устройства или ожидания X времени), или есть? MediaScannerConnection требует, чтобы я передал файловый объект. Также невозможно узнать, когда MediaRecorder закончит запись файла — до Q мы могли использовать FileObserver. Это оставляет мне один вариант — использовать getExternalFilesDir(). Проблема в том, что файл не будет доступен пользователю в общедоступном каталоге (Environment.DIRECTORY_MOVIES). У Вас есть какие-то предложения?
@HB.: Если вы insert() попадаете в MediaStore или update() содержимое MediaStore, MediaStore немедленно «обновляется», чтобы отразить то, что вы вставили или обновили.
@CommonsWare Но сначала я создаю Uri, как вы сделали выше, а затем передаю FileDescriptor этого Uri (как вы упомянули здесь — stackoverflow.com/a/46897595/5550161) в MediaRecorder. Невозможно узнать, когда MediaRecorder завершит запись файла, не используя FileObserver - Если я хочу продолжать использовать FileObserver, я должен запросить устаревшее хранилище - Если я запрошу устаревшее хранилище, я могу продолжать использовать getExternalStoragePublicDirectory(). Итак, у меня есть эти варианты? - Используйте устаревший API или надейтесь, что MediaRecorder закончит запись файла к тому времени, когда он мне понадобится.
@HB.: Отправьте отчет об ошибке, чтобы получить MediaRecorder обновление с помощью лучшего API. Или посмотрите, есть ли сторонняя библиотека для записи мультимедиа, которая предлагает вам лучший вариант. Или запишите в файл на getFilesDir() и перенесите его в MediaStore только после завершения записи.
Не могли бы вы помочь мне с stackoverflow.com/questions/63543414/…
@CommonsWare, как перенести файл в MediaStore после записи видеофайла в getFilesDir() или getExternalFilesDir()
Я не понимаю: если я хочу добраться до любого из распространенных путей (например, «Загрузки»), как мне это сделать вместо Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)?
@androiddeveloper: для операций чтения вы можете вызвать getDirectory() на StorageVolume на Android 11+. Это примерно соответствует Environment.getExternalStoragePublicDirectory(), но для каждого тома. StorageManager дает вам доступ к списку StorageVolume объектов.
@CommonsWare Где часть альтернативы выбора типа каталога (Environment.DIRECTORY_...)? Вы имеете в виду, что я просто добавляю его в путь тома? Было ли это устаревшим, поскольку у нас может быть несколько томов с одинаковыми папками? Вот как я должен использовать это сейчас: File(storageManager.primaryStorageVolume.directory!!,Environment.DIRECTORY_DOWNLOADS) ? Если это так, обновите свой ответ, потому что это новый способ его использования.
@androiddeveloper: «Вы имеете в виду, что я просто добавляю его в путь к тому?» -- предположительно, да. «Было ли это устаревшим, поскольку у нас может быть несколько томов, каждый из которых имеет одинаковые папки?» -- Я не знаю насчет части "у всех одинаковые папки". «пожалуйста, обновите свой ответ» - нет, потому что это не связано с ответом. Вопрос и ответ касаются операций записывать, тогда как «путь любого из общих» в лучшем случае будет иметь значение только для операций читать.
@CommonsWare Хорошо, извините и спасибо. Является ли хорошим предположением, что он не может быть обнулен для основного тома хранилища, а также что те же папки (например, DIRECTORY_DOWNLOADS) являются стандартными и подходят для использования на других томах хранилища?
@androiddeveloper: «Хорошо ли предположение, что он не может быть обнулен для основного тома хранилища» - вероятно, стоит проверить null, но я понятия не имею, что null будет означать в этом контексте. «также, что те же папки (например, DIRECTORY_DOWNLOADS) являются стандартными и подходят для использования на других томах хранилища?» -- Я бы не стал предполагать, что эти каталоги существуют.
@CommonsWare Каталоги могут отсутствовать даже на основном томе. Я просто спрашиваю, безопасно ли предположить, что они стандартны и их стоит использовать таким образом, или, может быть, стандартными считаются только папки (DIRECTORY_DOWNLOADS и остальные) основного тома.
@androiddeveloper: Ах, извините, понятия не имею.
@CommonsWare Это нормально. Вы везде помогаете. Большое спасибо за уделенное время.
Как переместить мои файлы из общедоступного каталога в каталог Android/Media/com.myapp в Android 11, как это сделал WhatsApp, не спрашивая разрешения? как получить путь к общедоступному каталогу, если getExternalStoragePublicDirectory теперь устарел в Q?
Ответ @CommonsWare потрясающий. Но для тех, кто хочет это на Java, вам нужно попробовать это:
ContentResolver resolver = context.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
Согласно предложению @SamChen, код для текстовых файлов должен выглядеть так:
Uri uri = resolver.insert(MediaStore.Files.getContentUri("external"), contentValues);
Потому что мы бы не хотели, чтобы файлы txt оставались в папке с изображениями.
Итак, место, где у меня есть mimeType, вы вводите тип пантомимы, который вы хотите. Например, если вы хотите txt (@Panache), вы должны заменить mimeType этой строкой: "text/plain". Вот список типов пантомимы: https://www.freeformatter.com/mime-types-list.html
Кроме того, там, где у меня есть переменная name, вы заменяете ее именем файла в вашем случае.
Гаурав, ваш ответ хорош для java-парней, но можете ли вы упомянуть, каков синтаксис для txt-файла?
Gaurav я получаю сообщение об ошибке, не могу вставить текст/обычный текст в MediaStore.Images.Media. Я передал имя как file.getName и mimetype = text/plain. пожалуйста, помогите
Гаурав, только вопрос, а где в этом коде путь к исходному файлу, разве это не обязательно? давайте обсудим здесь stackoverflow.com/questions/59511147/…
Для текстового файла запомните это Uri uri = getContentResolver().insert(MediaStore.Files.getContentUri("external"), values);
Не могли бы вы помочь мне с stackoverflow.com/questions/63543414/…
val imgUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
Как переместить мои файлы из общедоступного каталога в каталог Android/Media/com.myapp в Android 11, как это сделал WhatsApp, не спрашивая разрешения? как получить путь к общедоступному каталогу, если getExternalStoragePublicDirectory теперь устарел в Q?
@bdevloper Я не думаю, что вы можете сделать это, не спрашивая разрешения. Вот и весь вопрос, который здесь обсуждается. И в принципе, в моем коде вы можете заменить Environment.DIRECTORY_DOWNLOADS на любой каталог, который хотите.
тогда как WhatsApp сделал? Я не давал разрешения на manage_file_access, и все же они переместили всю папку внутрь Android\media\com.whatsapp
Я могу переместить свою папку с помощью кода это, но я не уверен, что это сработает после выхода в play store. Надеюсь, что использование сохранитьLegacyExternalStorage может помочь.
@SamChen включает ли файл .xls в текстовые файлы?
@Pif Вы можете попробовать установить mimeType на "text/xls", я никогда не пробовал.
@SamChen, я пытаюсь text/xls и application/vnd.ms-excel сохранить сгенерированный файл, но размер файла 0 КБ, есть идеи, что не так?
@Pif Я не знаю, может быть, файл excel не распознается MediaStore как обычный текстовый файл, но у меня есть идея, вы можете преобразовать файл excel в файл json, text/json это приемлемо, я могу гарантировать. Затем вы конвертируете его обратно в excel. Тем временем спросите StackOverflow.
Использование MediaStore совершенно бесполезно, если вам нужно хранить кучу файлов, в которых смешаны распознанные и нераспознанные мимы. Исключения будут выброшены, если вы это сделаете.
Приложения с таргетингом на Android Q — API 29+ отключил доступ к хранилищу по умолчанию из-за проблем с безопасностью. Если вы хотите включить его, добавьте следующий атрибут в AndroidManifest.xml:
<manifest ... >
<!-- This attribute is "false" by default for Android Q or higher -->
<application android:requestLegacyExternalStorage = "true" ... >
...
</application>
</manifest>
тогда вы должны использовать getExternalStorageDirectory() вместо getExternalStoragePublicDirectory().
Пример: если вы хотите создать каталог во внутренней памяти, если он не существует.
File mediaStorageDir = new File(Environment.getExternalStorageDirectory() + "/SampleFolder");
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("error", "failed to create directory");
}
}
Вам действительно нужно использовать requestLegacyExternalStorage = "true" для хранения с заданной областью? Я думаю, что раз вы используете getExternalStorageDirectory(), это не обязательно. Кроме того, устаревший флаг игнорируется в API 30+.
Это не сработает, если вы пропустили requestLegacyExternalStorage = "true" на версии API целевого устройства выше 28+.
Это нехорошо, так как согласно документации это всего лишь временное решение. Используйте MediaStore и ContentValues
import android.content.ContentValues
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
class MyActivity : AppCompatActivity() {
@RequiresApi(Build.VERSION_CODES.Q)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_mine)
val editText: EditText = findViewById(R.id.edt)
val write: Button = findViewById(R.id.Output)
val read: Button = findViewById(R.id.Input)
val textView: TextView = findViewById(R.id.textView)
val resolver = this.contentResolver
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "myDoc1")
put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
put(MediaStore.MediaColumns.RELATIVE_PATH, "Documents")
}
val uri: Uri? = resolver.insert(MediaStore.Files.getContentUri("external"), contentValues)
Log.d("Uri", "$uri")
write.setOnClickListener {
val edt : String = editText.text.toString()
if (uri != null) {
resolver.openOutputStream(uri).use {
it?.write("$edt".toByteArray())
it?.close()
}
}
}
read.setOnClickListener {
if (uri != null) {
resolver.openInputStream(uri).use {
val data = ByteArray(50)
it?.read(data)
textView.text = String(data)
}
}
}
}
}Здесь я сохраняю текстовый файл в папке «Документ» телефона, записывая текст в текст редактирования и нажимая кнопку «Записать», он сохраняет файл с написанным текстом. При нажатии кнопки «Читать» он выведет текст из этого файла, а затем отобразит его в текстовом представлении.
It will not run on devices that are below android Q or android 10 as RELATIVE_PATH can only be used in these versions.
Как переместить мои файлы из общедоступного каталога в каталог Android/Media/com.myapp в Android 11, как это сделал WhatsApp, не спрашивая разрешения? как получить путь к общедоступному каталогу, если getExternalStoragePublicDirectory теперь устарел в Q?
Для Xamarin.Android может помочь следующий код из опубликованного проекта:
Java.IO.File jFolder;
if ((int)Android.OS.Build.VERSION.SdkInt >= 29)
{
jFolder = new Java.IO.File(Android.App.Application.Context.GetExternalFilesDir(Environment.DirectoryDcim), "Camera");
}
else
{
jFolder = new Java.IO.File(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryDcim), "Camera");
}
if (!jFolder.Exists())
jFolder.Mkdirs();
var filename = GenerateJpgFileName();
var jFile = new Java.IO.File(jFolder, filename);
var fullFilename = jFile.AbsoluteFile.ToString();
using (var output = new System.IO.FileStream(fullFilename, System.IO.FileMode.Create))
{
outputBitmap.Compress(Bitmap.CompressFormat.Jpeg, 90, output);
output.Close();
}
Не используя разрешения в Android, это делается из общего проекта с помощью Xamarin.Essentials.
Поправьте меня, если я ошибаюсь, но Context.GetExternalFilesDir(Environment.DirectoryDcim) не предоставляет вам путь к папке вашего собственного приложения, что означает, что если вы удалите приложение, эти файлы тоже будут удалены? Это в отличие от другого пути, который позволяет файлам, которые вы создали, оставаться...
Как переместить мои файлы из общедоступного каталога в каталог Android/Media/com.myapp в Android 11, как это сделал WhatsApp, не спрашивая разрешения? как получить путь к общедоступному каталогу, если getExternalStoragePublicDirectory теперь устарел в Q?
Обычно я использовал этот способ:
var data: File =Environment.getExternalStoragePublicDirectory
(Environment.DIRECTORY_DOWNLOADS)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
data = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)!!
}
Environment.getExternalStoragePublicDirectory у меня работает на SDK 30. Только на SDK 29 не работает. У вас есть какая-либо информация, если они устарели на SDK 29 и вернули его на 30 или что-то подобное?
@Donki, вы проверяли --- приложение android:requestLegacyExternalStorage = "true" --- в манифесте?!
Если вы хотите сохранить файл во внешнем хранилище приложения, да, вы можете использовать context.getExternalFilesDir(). Многие ответы указывают на это.
Однако это не ответ на этот вопрос, потому что getExternalFilesDir() — это внешнее хранилище для конкретного приложения, а getExternalStoragePublicDirectory() — это общее хранилище.
Например, вы хотите сохранить загруженный файл PDF в «Общий» каталог загрузки. Как ты это делаешь ? Для API 29 и выше вы можете делать это без разрешения.
Для API 28 и ниже вам нужен метод getExternalStoragePublicDirectory(), но он устарел. Что, если вы не хотите использовать этот устаревший метод? Затем вы можете использовать файловый менеджер SAF (Intent#ACTION_OPEN_DOCUMENT). Как сказано в вопросе, для этого пользователь должен выбрать местоположение вручную.
Это именно то, чего хочет Google. Чтобы повысить конфиденциальность пользователей, прямой доступ к общим/внешним устройствам хранения не рекомендуется.
When an app targets Build.VERSION_CODES.Q, the path returned from this method is no longer directly accessible to apps. Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
Подробности приведены по следующей ссылке:
https://developer.android.com/reference/android/os/Environment#getExternalStorageDirectory()
Спасибо за ответ. В качестве примечания, я только что увидел в документации, что есть также новое поле «IS_PENDING», которое, я предполагаю, что, возможно, мне также следует включить при создании ContentValues, чтобы быть в безопасности при записи файла, а затем обновить после того, как файл будет полностью сохранен.