Вопрос или проблема
На самом деле, я хотел создать загрузчик файлов на 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:
-
Использование Пакета
file_picker
:
Пакетfile_picker
является вполне подходящим решением для выбора файлов и папок на устройствах Android. Однако если вы столкнулись с проблемами совместимости, вот альтернативы и улучшения: -
Использование Пакета
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); }
-
Использование Пакета
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; }
-
Код для 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 } }
-
Использование главного файла
AndroidManifest.xml
:
Убедитесь, что вы добавили необходимые разрешения в файл манифеста, например:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Если вы используете SAF, вы не нуждаетесь в полном доступе к файловой системе, однако обработка разрешений все еще крайне важна.
Заключение
Применяя вышеуказанные методы, вы можете эффективно реализовать функциональность скачивания файлов с доступом к папкам на устройствах Android, которая будет работать более стабильно и предсказуемо. Если какие-либо из предложенных пакетов по-прежнему оказывают влияние на производительность вашего приложения, возможно, стоит обратиться к документации по каждому пакету или исследовать другие доступные решения от сообщества Flutter.