DownloadManager не работает на Android 10 (Q)

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

Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)

Здесь все отлично работает с Android api 19-28. Проблемы возникают при тестировании на API 29 (Q / 10). В Android реализовано ограниченное хранилище, поэтому getExternalStoragePublicDirectory устарел ... В результате мне нужно найти совместимое решение для поддержки API 19- 29. Я не могу использовать внутреннее хранилище приложения, так как DownloadManager вызовет исключение SecurityException. В документации Android указано, что я могу использовать DownloadManager.Request setDestinationUri, и даже упоминается для Android Q, что я могу использовать Context.getExternalFilesDir(String). Когда я это делаю, путь по-прежнему остается эмулированным путем:

/storage/emulated/0/Android/data/com.my.package.name/files/Download/myFile.xml

Я получаю ответ от диспетчера загрузок о том, что загрузка завершена (с правильным идентификатором), но затем я не могу получить загрузку из области, в которой я ее сохранил. Я проверяю, существует ли файл, и он возвращает false:

new File("/storage/emulated/0/Android/data/com.my.package.name/files/Download/myFile.xml").exists();

Любая помощь приветствуется

Добавление кода для контекста. Итак, настройка менеджера загрузок

    private void startDownload() {
        IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
        registerReceiver(downloadReceiver, filter);

        String remoteURL= getString(R.string.remote_url);

        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(remoteUrl));
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
        request.setTitle(getString(R.string.download_title));
        request.setDescription(getString(R.string.download_description));
        request.setDestinationUri(Uri.fromFile(new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "myFile.xml")));

        DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
        mainDownloadID= manager.enqueue(request);
    }

проверка файла, если он существует:

new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "myFile.xml").exists(); //this returns false in the onReceive (and download IDs match)

person New Guy    schedule 04.12.2019    source источник


Ответы (3)


Попробуйте добавить это в свой файл манифеста в теге приложения

android: requestLegacyExternalStorage = "true"

person Сергей Серпивский    schedule 04.12.2019
comment
Лучше перейти на новые методы вместо быстрого взлома, который не будет работать в следующей версии Android - person Andrew; 04.12.2019
comment
как заявил @Andrew, я хотел бы более полное решение проблемы. - person New Guy; 04.12.2019
comment
да, это не так хорошо, но это работает, и если вам нужно быстрое решение, это то, что вам нужно - person Сергей Серпивский; 04.12.2019
comment
@Andrew проверьте это commonsware.com/blog/ 2019/06/07 / - person Сергей Серпивский; 04.12.2019
comment
@ Сергей Серпивский да, я уже знаю всю информацию в этом блоге, поэтому предложил перейти на новые методы. - person Andrew; 04.12.2019
comment
мой сценарий я уже добавил android: requestLegacyExternalStorage = true, даже я получил ту же ошибку только android10 - person Hari Shankar S; 04.08.2020

Пути к файлам вне частных каталогов приложения в Android Q и выше бесполезны.

См. https://developer.android.com/training/data-storage#scoped-storage

Вам также нужно спросить пользователя, где скачать файлы, это даст вам URI для DownloadManager назначения.

https://developer.android.com/training/data-storage/shared/documents-files#grant-access-directory

Вы, вероятно, захотите сохранить это разрешение

https://developer.android.com/training/data-storage/shared/documents-files#persist-permissions

person Andrew    schedule 04.12.2019
comment
это интересно, другим приложениям не нужен доступ к файлу, который я загружаю. Вопрос, как мне сохранить местоположение файла, которое пользователь выбрал в первый раз? Я не хочу каждый раз спрашивать пользователя, если я уже загрузил его, я просто хочу вытащить его из того места, где пользователь сначала сказал мне, где его хранить. - person New Guy; 04.12.2019
comment
Последняя ссылка показывает, как получить разрешения, которые сохраняются после перезагрузки устройства. Если другому приложению не требуется доступ к файлам, которые вы загружаете, было бы лучше сохранить их в личном каталоге вашего приложения, что намного проще, так как не требует разрешений. - person Andrew; 04.12.2019
comment
Верно, но я хотел бы использовать DownloadManager для загрузки нужных мне файлов, и он не может занимать местоположение частного каталога приложений для пункта назначения (вызовет исключение SecurityException). - person New Guy; 04.12.2019

Да. Его объем хранилища, но даже если вы можете загрузить файл в Q + с помощью downloadmanger, делать это не нужно android:requestLegacyExternalStorage="true"

Я так и делаю.

  1. манифест
  • -->
  1. Downloadmanger

     val fileName =
         Constants.FILE_NAME + Date().time
    
     val downloadUri = Uri.parse(media.url)
     val request = DownloadManager.Request(
         downloadUri
     )
     request.setAllowedNetworkTypes(
         DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE
     )
         .setAllowedOverRoaming(true).setTitle("Some name")
         .setDescription("Downloading file")
         .setDestinationInExternalPublicDir(
             Environment.DIRECTORY_DOWNLOADS, File.separator + FOLDER + File.separator + fileName
         )
    
    
     Toast.makeText(
         context,
         "Download successfully to ${downloadUri?.path}",
         Toast.LENGTH_LONG
     ).show()
    
     downloadManager.enqueue(request)
    

Следовательно, он будет запрашивать разрешение на запись ниже Q, но в Q и Q + он будет загружаться без запроса разрешения в / Download / folder dir.

person Mohd Faizan    schedule 23.01.2021