Читаем/записываем файл в Андроиде без запроса пермишинсов

от автора

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

Manifest.permission.READ_EXTERNAL_STORAGE

Этот подход нормально работал до появления Андроид 11. Потом с помощью специального костыля можно было какое то время жить по старому.

Совсем упертые могут попробывать доказать модерации, что Вам нужен

android.permission.MANAGE_EXTERNAL_STORAGE

Для тех кому сразу интересен результат https://github.com/Muraveiko/EditorExample/blob/main/app/src/main/java/ru/a402d/verysimpleeditor/MainActivity.java#L73 для остальных продолжу по шагам.

Ребят я скажу только одну фразу, после которой все станет на свои места:

В андроиде нет файлов.

Загорелось меня поправить ? Готовы привести кучу примеров почему я не прав. Подождите. Поясню.

1. Забудьте о том как это работает в Windows/Unix (имя и путь к файлу). Фактически нам не нужно для чтения данных фактическое месторасположение файла и его наименование.

static String readTxtFile(InputStream inputStream) {         BufferedReader br = null;         StringBuilder sb = new StringBuilder();         String line;         try {             br = new BufferedReader(new InputStreamReader(inputStream));             while ((line = br.readLine()) != null) {                 sb.append(line).append("\n");             }          } catch (Exception e) {             e.printStackTrace();         } finally {             if (br != null) {                 try {                     br.close();                 } catch (IOException e) {                     e.printStackTrace();                 }             }         }         return sb.toString(); }

Данные мы читаем из потока, который получаем:

getContentResolver().openInputStream(p)

где p — Uri — Универсальный идентификатор ресурса. Файл — это частный случай uri.

2. В адроиде отказались от схемы file: . Взамен ее используется content:

При взаимодействие программ между собой в андроиде используются контент провадеры.

Современный подход получить нужный uri очень просто:

mGetContent.launch("*/*");

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

private final ActivityResultLauncher<String> mGetContent =    registerForActivityResult(             new ActivityResultContracts.GetContent(),             this::fileSelected  );

Это рекомендуемая сейчас замена для activityStartForResult (депрекейтед).

Таким образом для чтения любого файла нам не потребавалось никаких дополнительных разрешений. Доступ к файлу нам предоставил файловый менеджер смартфона.

После неявного вызова ACTION_GET_CONTENT, мы получили URI контента вместе с разрешением его прочитать.

Аналогично для записи:

private final ActivityResultLauncher<Intent> mSaveContent =    registerForActivityResult(             new ActivityResultContracts.StartActivityForResult(),             this::saveSelected );

только нужный интент проще собрать ручками:

Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_TITLE, cTime+".txt");

На гитхабе в качестве примера выложен Очень Простой Редактор 🙂


ссылка на оригинал статьи https://habr.com/ru/articles/769114/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *