Есть ли ЛУЧШИЙ и ЧИСТЫЙ способ использовать SAF (Storage Access Framework) в Flutter?

Вопрос или проблема

На самом деле, я хотел создать загрузчик файлов на Flutter для Android, который может одновременно загружать файлы. Для этого мне нужен доступ к файловой системе или к любой папке на диске, которую выберет пользователь. Я пробовал использовать пакет Filepicker в Flutter, но он работает на некоторых устройствах, а на некоторых нет (несмотря на то, что я включил разрешения на управление хранилищем в файле манифеста).

Я попытался создать простой нативный код платформы с использованием kotlin и получить путь, выбранный пользователем, с помощью

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CODE_FOLDER_PICKER && resultCode == RESULT_OK) {
            data?.data?.let { uri ->
                contentResolver.takePersistableUriPermission(
                    uri,
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                )

                // Преобразовать URI в путь к файлу
                val folderPath = getAbsolutePathFromUri(uri) ?: ""

                // Вернуть путь к папке на сторону Flutter
                pendingResult?.success(folderPath)
                pendingResult = null
            }
        } else {
            // Если пользователь отменяет выбор папки, вернуть пустую строку
            pendingResult?.success("")
            pendingResult = null
        }
    }

Но он возвращает значение в форме ‘tree/downloads’, что тоже не работает, и даже если я отформатировал этот путь в /storage/emulated/0/Downloads, всё равно возникает ошибка “Доступ запрещен”.

Поэтому я хочу узнать, знает ли кто-нибудь, как лучше получить доступ к файловой системе, чтобы это работало на большинстве устройств Android и был предсказуемым способом. (Не просто случайным образом, как иногда работает, а иногда нет, и без указания полного доступа к хранилищу в манифесте.)

Обновления: файл-пикер хороший, но если он не работает, попробуйте использовать flutter_file_dialog или ext_storage для доступа к папке.

Ответ или решение

Для создания надежного и чистого способа доступа к хранилищу в Flutter с использованием Storage Access Framework (SAF), который будет работать на большинстве устройств Android, рекомендуется следовать нескольким шагам и подходам.

Шаги для доступа к хранилищу с использованием SAF в Flutter:

  1. Использование Пакета file_picker:
    Пакет file_picker является вполне подходящим решением для выбора файлов и папок на устройствах Android. Однако если вы столкнулись с проблемами совместимости, вот альтернативы и улучшения:

  2. Использование Пакета flutter_file_dialog:
    Этот пакет предоставляет диалоговое окно для выбора файлов и папок, что делает его более интегрированным и простым в использовании.

    import 'package:flutter_file_dialog/flutter_file_dialog.dart';
    
    Future<String?> pickFolder() async {
     final params = OpenFileDialogParams(
       dialogType: OpenFileDialogType.folder,
       fileExtensions: [], // Укажите расширения, если нужно
     );
     return await FlutterFileDialog.pickFile(params: params);
    }
  3. Использование Пакета ext_storage:
    Этот пакет позволяет получить доступ к различным стандартным директориям устройства, включая папку "Downloads". Важно отметить, что ext_storage работает на устройствах, поддерживающих внешнее хранилище, и вы можете избежать проблем с URI.

    import 'package:ext_storage/ext_storage.dart';
    
    Future<String> getDownloadPath() async {
     String downloadsPath = await ExtStorage.getExternalStoragePublicDirectory(ExtStorage.DIRECTORY_DOWNLOADS);
     return downloadsPath;
    }
  4. Код для Kotlin:
    Если вы хотите использовать Kotlin для директного доступа и передачи URI обратно в Flutter, убедитесь, что вы обрабатываете разрешения правильно и используете takePersistableUriPermission для сохранения доступа.

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
       super.onActivityResult(requestCode, resultCode, data)
       if (requestCode == REQUEST_CODE_FOLDER_PICKER && resultCode == RESULT_OK) {
           data?.data?.let { uri ->
               contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
    
               // Отправьте URI обратно в Flutter
               val folderPath = uri.toString() // Используйте URI для дальнейшей работы
               pendingResult?.success(folderPath)
               pendingResult = null
           }
       } else {
           pendingResult?.success("")
           pendingResult = null
       }
    }
  5. Использование главного файла AndroidManifest.xml:
    Убедитесь, что вы добавили необходимые разрешения в файл манифеста, например:

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

    Если вы используете SAF, вы не нуждаетесь в полном доступе к файловой системе, однако обработка разрешений все еще крайне важна.

Заключение

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

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

Капча загружается...