Плагин для создания и управления задачами загрузки. Поддерживает iOS и Android.
Этот плагин использует WorkManager
на Android и NSURLSessionDownloadTask
на iOS для запуска задач загрузки в фоновом режиме.
Изменения API внешнего хранилища в Android 11 вызывают некоторые проблемы в текущей реализации. Я решил перепроектировать этот плагин, добавив новую стратегию управления местоположением загружаемых файлов. Он все еще находится на стадии сортировки и обсуждения в этом PR. Мы очень признательны за вклад и отзывы от разработчика Flutter, чтобы улучшить дизайн плагина.
В предыдущих версиях этого пакета были известные уязвимости, связанные с SQL-инъекцией. SQL-инъекция — это тип уязвимости безопасности, которая может позволить злоумышленникам манипулировать SQL-запросами, выполняемыми приложением, что потенциально может привести к несанкционированному доступу или манипулированию базой данных.
Настоятельно рекомендуется выполнить обновление до последней версии этого пакета, чтобы гарантировать, что ваше приложение не подвержено уязвимостям SQL-инъекций. Последняя версия содержит необходимые улучшения безопасности и исправления для снижения таких рисков.
Следующие шаги требуют открытия проекта ios
в Xcode.
Включите фоновый режим.
Добавьте библиотеку sqlite
.
Настройте AppDelegate
:
Цель-С:
/// AppDelegate.h#import#import @interface AppDelegate : FlutterAppDelegate@end
// AppDelegate.m#include "AppDelegate.h"#include "GeneratedPluginRegistrant.h"#include "FlutterDownloaderPlugin.h"@implementation AppDelegatevoid RegisterPlugins(NSObject* реестр) { if (![registry hasPlugin:@"FlutterDownloaderPlugin" ]) { [FlutterDownloaderPlugin RegisterWithRegistrar: [регистратор реестраForPlugin: @"FlutterDownloaderPlugin"]]; } } - (BOOL)application:(UIApplication *)application DidFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant RegisterWithRegistry:self]; [FlutterDownloaderPlugin setPluginRegistrantCallback:registerPlugins]; // Переопределить точку настройки после запуска приложения. return [суперприложение: приложение DidFinishLaunchingWithOptions: launchOptions]; }@конец
Или Свифт:
импортировать UIKit импортировать флаттер import flutter_downloader@UIApplicationMain@objc class AppDelegate: FlutterAppDelegate { переопределить func application( _ приложение: UIApplication, DidFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins) return super.application(application, DidFinishLaunchingWithOptions: launchOptions) }}private func RegisterPlugins(реестр: FlutterPluginRegistry) { if (!registry.hasPlugin("FlutterDownloaderPlugin")) { FlutterDownloaderPlugin.register(with: Registration.registrar(forPlugin: "FlutterDownloaderPlugin")!) }}
Поддержка HTTP-запроса: если вы хотите загрузить файл с помощью HTTP-запроса, вам необходимо отключить функцию Apple Transport Security (ATS). Есть два варианта:
Отключите ATS только для определенного домена: (добавьте следующий код в файл Info.plist
)
NSAppTransportSecurity <диктат>NSExceptionDomains <диктат>www.yourserver.com NSIncludesSubdomains NSTemporaryExceptionAllowsInsecureHTTPLoads NSTemporaryExceptionMinimumTLSVersion TLSv1.1
Полностью отключить АТС. Добавьте следующее в свой файл Info.plist
)
NSAppTransportSecurity <диктат>NSAllowsArbitraryLoads
Настройте максимальное количество одновременных задач: плагин по умолчанию позволяет запускать 3 задачи загрузки одновременно (если вы ставите в очередь более 3 задач, выполняются только 3 задачи, остальные задачи переводятся в состояние ожидания). Вы можете изменить это число, добавив следующий код в файл Info.plist
.
FDMaximumConcurrentTasks <целое>5целое>
Локализация уведомлений: плагин отправит уведомление пользователю, если все файлы будут загружены, пока ваше приложение не работает на переднем плане. По умолчанию это сообщение на английском языке. Вы можете локализовать это сообщение, добавив и локализовав следующее сообщение в файле Info.plist
. (детали локализации Info.plist
можно найти по этой ссылке)
FDAllFilesDownloadedMessage Все файлы загружены
Примечание:
Этот плагин поддерживает файлы сохранения только в NSDocumentDirectory
Вам не нужно ничего делать дополнительно, чтобы плагин работал на Android.
Однако есть несколько дополнительных настроек, которые вы, возможно, захотите настроить.
Чтобы нажатие на уведомление открывало загруженный файл на Android, добавьте следующий код в AndroidManifest.xml
:
<метаданные android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> поставщик>
Примечания
Вам необходимо сохранить загруженные файлы во внешнем хранилище (где другие приложения имеют разрешение на чтение ваших файлов).
Загруженные файлы можно открыть только в том случае, если на вашем устройстве установлено хотя бы одно приложение, которое может читать файлы этих типов (mp3, pdf и т. д.).
Плагин зависит от библиотеки WorkManager
, а WorkManager
зависит от количества доступных процессоров для настройки максимального количества задач, выполняемых в данный момент. Вы можете установить фиксированный номер для этой конфигурации, добавив следующий код в свой AndroidManifest.xml
:
<метаданные android:name="androidx.work.WorkManagerInitializer" android:value="androidx.startup" инструменты:node="remove" /> <метаданные android:name="vn.hunghd.flutterdownloader.MAX_CONCURRENT_TASKS" android:value="5" />
Вы можете локализовать тексты в уведомлениях о ходе загрузки, локализовав следующие сообщения.
Загрузка началась Идет загрузка Загрузка отменена Загрузка не удалась Загрузка завершена Загрузка приостановлена
Подробнее о локализации на Android можно узнать здесь.
Чтобы открыть и установить файлы .apk
, вашему приложению требуется разрешение REQUEST_INSTALL_PACKAGES
. Добавьте следующее в свой AndroidManifest.xml
:
См. также:
Исправить ошибку Cleartext Traffic на Android 9 Pie
import 'package: flutter_downloader/flutter_downloader.dart';void main() { WidgetsFlutterBinding.ensureInitialized(); // Плагин должен быть инициализирован перед использованием await FlutterDownloader.initialize( отладка: true, // необязательно: установите значение false, чтобы отключить вывод журналов на консоль (по умолчанию: true) ignoreSsl: true // опция: установите значение false, чтобы отключить работу с http-ссылками (по умолчанию: false) ); запуститьПриложение(/*...*/) }
окончательный идентификатор задачи = ожидание FlutterDownloader.enqueue( URL: «ваша ссылка для скачивания», заголовки: {}, // необязательно: заголовок отправляется с URL-адресом (токен аутентификации и т. д.) saveDir: 'путь к каталогу, в котором вы хотите сохранить загруженные файлы', showNotification: true, // показывать прогресс загрузки в строке состояния (для Android) openFileFromNotification: true, // нажмите на уведомление, чтобы открыть загруженный файл (для Android));
дождитесь FlutterDownloader.registerCallback(обратный вызов); // обратный вызов — это статическая функция верхнего уровня
Важный
Пользовательский интерфейс отображается на основном изоляте, а события загрузки поступают из фонового изолята (другими словами, код callback
запускается в фоновом изоляте), поэтому вам придется обрабатывать связь между двумя изолятами. Например:
ReceivePort _port = ReceivePort();@overridevoid initState() { super.initState(); IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port'); _port.listen((динамические данные) { String id = data[0]; DownloadTaskStatus status = DownloadTaskStatus(data[1]); int Progress = data[2]; setState((){ }); }); FlutterDownloader.registerCallback(downloadCallback); }@overridevoid Dispose() { IsolateNameServer.removePortNameMapping('downloader_send_port'); супер.dispose(); }@pragma('vm:entry-point')static void downloadCallback(String id, int status, int Progress) { окончательный SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port'); send.send([id, статус, прогресс]); }
@pragma('vm:entry-point')
необходимо размещать над функцией callback
, чтобы избежать дрожания дерева в режиме выпуска для Android.
финальные задачи = ждут FlutterDownloader.loadTasks();
окончательные задачи = ждут FlutterDownloader.loadTasksWithRawQuery (запрос: запрос);
Чтобы успешно проанализировать данные в объект DownloadTask
, вам необходимо загрузить данные со всеми полями из базы данных (другими словами, использовать SELECT *
). Например:
ВЫБРАТЬ * ИЗ задачи ГДЕ статус=3
Ниже представлена схема таблицы task
, в которой плагин flutter_downloader
хранит информацию о задачах загрузки.
CREATE TABLE `task` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, `task_id` VARCHAR ( 256 ), `url` TEXT, `status` INTEGER DEFAULT 0, `progress` INTEGER DEFAULT 0, `file_name` TEXT, `saved_dir` TEXT , `resumable` TINYINT DEFAULT 0, `headers` TEXT, `show_notification` TINYINT DEFAULT 0, `open_file_from_notification` TINYINT DEFAULT 0, `time_created` INTEGER DEFAULT 0);
FlutterDownloader.cancel(taskId: TaskId);
FlutterDownloader.cancelAll();
FlutterDownloader.pause(taskId: TaskId);
FlutterDownloader.resume(taskId: TaskId);
resume()
вернет новый taskId
соответствующий новой фоновой задаче, созданной для продолжения процесса загрузки. Вам следует заменить старый taskId
(со статусом paused
) на новый taskId
, чтобы продолжить отслеживание хода загрузки.
FlutterDownloader.retry(taskId: TaskId);
retry()
вернет новый taskId
(так же, как resume()
)
FlutterDownloader.remove (taskId: TaskId, mustDeleteContent: false);
FlutterDownloader.open(taskId: TaskId);
На Android вы можете открыть загруженный файл только в том случае, если он размещен во внешнем хранилище и на вашем устройстве есть хотя бы одно приложение, которое может читать этот тип файла.
Не стесняйтесь открывать проблему, если у вас возникнут какие-либо проблемы или вы считаете, что в плагине отсутствует какая-то функция.
Запрос на вытягивание также приветствуется!