Как я могу предоставить разрешение на хранение в DIRECTORY_DOWNLOADS при работе на Android 10?

Моя проблема

У меня есть приложение для Android, ориентированное на API 30, которое хранит файл данных в общедоступном каталоге DIRECTORY_DOWNLOADS, чтобы пользователи могли получить доступ и скопировать его в свой каталог в другом месте.

Это работает для API 28 и ниже и для API 30, но не для API 29, доступ к которому запрещен.

Что я сделал до сих пор

Я изучил здесь различные сообщения, в том числе ответы опытных пользователей, которые ответили на темы по API 29 / Android 10, а также на соответствующие темы для разработчиков Android, но не смогли найти конкретный ответ на мою проблему (или тот, который я могу понять. ). Некоторые примеры, которые я видел, находятся на Kotlin - я знаком с Java, но не с Kotlin.

Что у меня в коде

В моем манифесте:

          <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

(Первый и третий предназначены для других функций моего приложения.)

В build.gradle:

          compileSdkVersion 30
    defaultConfig {
        applicationId "com.enborne.spine"
        minSdkVersion 19
        targetSdkVersion 30
        versionCode 29
        versionName "3.0"
        signingConfig signingConfigs.config
    }

В моем коде Java:

Мой основной класс Spine включает следующие глобальные переменные:

          public static File      dataDir;
    public static File      fileSaveDir;

В других модулях у меня есть:

                  Spine.dataDir = getFilesDir();
            Spine.fileSaveDir =
                    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);

и код, сохраняющий файл:

                          // Default toast text
                    toastText = "Failed to save file";

                    // [code to build fileName snipped]

                    // Create the output file
                    outFile = new File(Spine.fileSaveDir, fileName);
                    
                    try
                    {
                        out = new BufferedWriter(new FileWriter(outFile), 1024);
                    
                        // Output the formatted body
                        // [code snipped]

                        // Flush and close file
                        out.flush();
                        out.close();

                        // File has been saved
                        toastText = "File saved as " + formatDesc;
                    }
                    catch (IOException e)
                    {
                        toastText += "\n" + e.getMessage();
                    }

При работе с API 29 возникает исключение при попытке создать BufferedWriter. В остальном на других уровнях API все работает. Я везде искал решение этой проблемы, но так и не нашел.

Фактический вывод текста тоста при работе в эмуляторе API 29 в Android Studio:

      Failed to save file
/storage/emulated/0/Download/
20210520.txt: open failed : EACCES
(Permission denied)

3 ответа

      <application
        android:requestLegacyExternalStorage="true"
    ....

Добавьте это в свой манифест Android.

Приложения, которые работают на Android 11, но нацелены на Android 10 (уровень API 29), по-прежнему могут запрашивать атрибут requestLegacyExternalStorage. Этот флаг позволяет приложениям временно отказаться от изменений, связанных с ограниченным хранилищем, таких как предоставление доступа к разным каталогам и различным типам мультимедийных файлов. После обновления приложения до Android 11 система игнорирует флаг requestLegacyExternalStorage.

Если ваше приложение отказывается от ограниченного хранилища при работе на устройствах Android 10, рекомендуется продолжать устанавливать для requestLegacyExternalStorage значение true в файле манифеста вашего приложения. Таким образом, ваше приложение может продолжать вести себя должным образом на устройствах под управлением Android 10.

Источник: https://developer.android.com/about/versions/11/privacy/storage.

Решение (спасибо тем, кто ответил) состоит в том, чтобы добавить android:requestLegacyExternalStorage="true" в раздел манифеста приложения, по-прежнему ориентируясь на API 30.

Во время всего моего тестирования у меня было это в неправильном разделе манифеста, поэтому я не мог заставить его работать.

Некоторое время вам понадобится разрешение времени выполнения для записи во внешнее хранилище .

      if (ContextCompat.checkSelfPermission(Main_activity.this),
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            if (!ActivityCompat.shouldShowRequestPermissionRationale(OMain_activity.this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                ActivityCompat.requestPermissions(getActivity(),
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        1);
            }
    }
Другие вопросы по тегам