Допустим, я разрабатываю приложение для чата, которое может делиться с другими файлами ЛЮБОГО типа (без ограничений типа mime): например, изображения, видео, документы, а также сжатые файлы, такие как zip, rar, apk или даже менее частые типы файлов. например, файлы Photoshop или AutoCAD.
В Android 9 или ниже я напрямую загружаю эти файлы в каталог Download, но теперь это невозможно в Android 10, не показывая пользователю намерение спросить, где их загрузить ...
Невозможно? но тогда почему Google Chrome или другие браузеры могут это делать? Фактически они по-прежнему загружают файлы в каталог загрузки, не спрашивая пользователя в Android 10.
Сначала я проанализировал Whatsapp, чтобы увидеть, как они этого достигают, но они используют атрибут requestLegacyExternalStorage в AndroidManifest. Но затем я проанализировал Chrome, и он нацелен на Android 10 без использования requestLegacyExternalStorage. Как такое возможно?
Я уже несколько дней гуглил, как приложения могут загружать файл прямо в каталог загрузки на Android 10 (Q), не спрашивая пользователя, где его разместить, так же, как это делает Chrome.
Я прочитал документацию по Android для разработчиков, множество вопросов по Stackoverflow, сообщения в блогах в Интернете и группы Google, но все же я не нашел способа продолжать делать то же самое, что и в Android 9, и даже не нашел решения, которое меня во многом удовлетворяет.
Что я пробовал на данный момент:
Откройте SAF с намерением ACTION_CREATE_DOCUMENT, чтобы запросить разрешение, но, по-видимому, нет возможности открыть его в автоматическом режиме. Всегда открывается Activity, чтобы спросить пользователя, куда поместить файл. Но должен ли я открывать это намерение для каждого файла? Мое приложение может автоматически загружать файлы чата в фоновом режиме. Неприемлемое решение.
Получите доступ с помощью SAF в начале приложения с uri, указывающим на любой каталог для загрузки содержимого:
StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); i = sm.getPrimaryStorageVolume().createOpenDocumentTreeIntent();
Что за уродливое занятие - спрашивать разрешения у пользователя, не так ли? Хотя это НЕ то, что делает Google Chrome.
Или снова, используя ACTION_CREATE_DOCUMENT, сохраните Uri, который я получаю в onActivityResult (), и используйте grantPermission () и getContentResolver (). TakePersistableUriPermission (). Но при этом создается не каталог, а файл.
Я также попытался получить MediaStore.Downloads.INTERNAL_CONTENT_URI или MediaStore.Downloads.EXTERNAL_CONTENT_URI и сохранить файл с помощью Context.getContentResolver.insert (), но какое совпадение, хотя они аннотированы как @NonNull, они фактически возвращают ... НУЛЕВОЙ
Добавление requestLegacyExternalStorage = "false" в качестве атрибута метки приложения моего AndroidManifest.xml. Но это всего лишь патч для разработчиков, чтобы выиграть время, пока они не внесут изменения и не адаптируют свой код. К тому же это не то, что делает Google Chrome.
getFilesDir () и getExternalFilesDir () и getExternalFilesDirs () по-прежнему доступны, но файлы, хранящиеся в этих каталогах, удаляются при удалении моего приложения. Пользователи ожидают, что при удалении моего приложения их файлы сохранятся. Опять же, это не подходящее решение для меня.
Мое временное решение:
Я нашел обходной путь, который позволяет загружать куда угодно без добавления requestLegacyExternalStorage = "false".
Он заключается в получении Uri из объекта File с помощью:
val downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val file = File(downloadDir, fileName)
val authority = "${context.packageName}.provider"
val accessibleUri = FileProvider.getUriForFile(context, authority, file)
Наличие provider_paths.xml
<paths>
<external-path name="external_files" path="."/>
</paths>
И установив его на AndroidManifest.xml:
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
Проблема:
Он использует метод getExternalStoragePublicDirectory, который устарел в Android Q и, скорее всего, будет удален на Android 11. Вы можете подумать, что можете создать свой собственный путь вручную, поскольку знаете реальный путь (/ storage / emulated / 0 / Download / ) и продолжайте создавать объект File, но что, если Google решит изменить путь к каталогу загрузки на Android 11?
Боюсь, это не долгосрочное решение, поэтому
Мой вопрос:
Как я могу добиться этого, не используя устаревший метод? И дополнительный вопрос: Как, черт возьми, Google Chrome получает доступ к каталогу загрузок?
but that's now impossible in Android 10 without showing an Intent to the user to ask where to download them...
Нет. Вовсе нет. Вы по-прежнему можете использовать getFilesDir (), getExternalFilesDir () и getExternalFilesDirs (). - person blackapps   schedule 29.11.2019how apps can download a file directly to Download directory on Android 10 (Q) without having to ask user where to place it,
. Непроверено: не загружается ли DownloadManager по умолчанию в эту папку? - person blackapps   schedule 29.11.2019but still there are some other kind of files that does not belong to that categories
Да. Но кого это волнует? Приложения MediaStore или Галерея их просто не покажут. Пора немного поэкспериментировать. - person blackapps   schedule 29.11.2019