Использование плагина flutter_downloader для реализации загрузки файлов во Flutter

Flutter
Использование плагина flutter_downloader для реализации загрузки файлов во Flutter

предисловие

Раньше был апплет WeChat под названием «Open Lite», но из-за ограничений самого апплета не было возможности реализовать функцию скачивания файлов, и парсить можно было только ссылку на скачивание. А ограниченный платформой WeChat, обзор небольших программ — очень хлопотное дело, поэтому у меня идея APP.

С тех пор, как Flutter родился в прошлом году, я внимательно следил за его развитием, через год снова взялся за него и обнаружил, что его экология начала формироваться, поэтому решил использовать Flutter для переделки «Open Lite». Позже я буду время от времени обновлять некоторые статьи, связанные с Flutter, и я надеюсь, что вы поддержите больше. В этой статье описан процесс использования Flutter для реализации функции загрузки файлов.

Полный исходный код можно получить в общедоступной учетной записи: «01 двоичный файл», фоновый ответ: «Загрузка файла Flutter».

Начинать

Давайте сначала посмотрим на достигнутый эффект:

iOS

Android

Эффект реализации этой демонстрации очень прост: просто нажмите кнопку, затем загрузите файл и предложите пользователю открыть файл после завершения.

Готов к работе

IDE, используемая в этой демонстрации,Android Studio, при использовании следующих библиотек:

flutter_downloader: ^1.1.7
path_provider: 1.1.2
permission_handler: ^3.1.0
progress_dialog: ^1.1.0+1
toast: ^0.1.4

Сначала мы создаем новый пустой проект, а затем добавляем приведенные выше зависимости в файл проекта.pubspec.yamlфайл, добавьте местоположение следующим образом:

Далее мы можемTerminalввод вflutter packages getИли нажмите в верхнем левом углу IDEPackages getСлова устанавливают зависимости.

Затем удалите лишний код в исходном проекте и добавьте кнопку посередине.

body: Center(
  child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      RaisedButton(
        child: Text("点我下载文件"),
        onPressed: () {
          // 执行下载操作
          _doDownloadOperation();
        },
      ),
    ],
  ),
),

в_doDownloadOperation()Именно так мы выполняем операции загрузки, на этом предварительная подготовка заканчивается.

логический анализ

Хотя весь процесс загрузки демо очень прост, все же необходимо проанализировать весь процесс загрузки, как показано на следующем рисунке:

Итак, следующее, что мы делаем, это:

  1. Разрешения на доступ: сетевые разрешения, разрешения на хранение
  2. Получить путь загрузки
  3. Установите обратный вызов загрузки (для мониторинга процесса загрузки)

действовать

получать разрешение

Здесь используется плагин для получения разрешений:permission_handler, этот подключаемый модуль обеспечивает межплатформенную (Android и iOS) проверку разрешений и доступ к API по адресу:универсальный.flutter-io.capable/packages/PE…

Откройте корневой каталог проектаandroid/app/src/main/AndroidManifest.xmlфайл, расположение показано ниже:

Затем добавьте объявление разрешений, которые нам нужно использовать, как показано ниже:

Далее мы можем написать код для получения необходимых разрешений. Создавать_checkPermission()Функция используется для определения того, предоставлено ли разрешение. Конечно, из-за различий платформ нам нужно судить, что это платформа Android.Код приложения выглядит следующим образом:

// 申请权限
Future<bool> _checkPermission() async {
  // 先对所在平台进行判断
  if (Theme.of(context).platform == TargetPlatform.android) {
    PermissionStatus permission = await PermissionHandler()
        .checkPermissionStatus(PermissionGroup.storage);
    if (permission != PermissionStatus.granted) {
      Map<PermissionGroup, PermissionStatus> permissions =
          await PermissionHandler()
              .requestPermissions([PermissionGroup.storage]);
      if (permissions[PermissionGroup.storage] == PermissionStatus.granted) {
        return true;
      }
    } else {
      return true;
    }
  } else {
    return true;
  }
  return false;
}

Получить путь загрузки

Вот используемый плагинpath_provider, это подключаемый модуль, который взаимодействует с библиотекой ввода-вывода Dart для реализации чтения и записи файлов во Flutter.На китайском веб-сайте Flutter есть подробное введение в подключаемый модуль (флаттер съешь тот.клуб/Reading-Old…), тут нужно понимать проблему, то есть в iOS нет понятия внешнего хранилища, поэтому надо судить о платформе, код такой:

// 获取存储路径
Future<String> _findLocalPath() async {
  // 因为Apple没有外置存储,所以第一步我们需要先对所在平台进行判断
  // 如果是android,使用getExternalStorageDirectory
  // 如果是iOS,使用getApplicationSupportDirectory
  final directory = Theme.of(context).platform == TargetPlatform.android
      ? await getExternalStorageDirectory()
      : await getApplicationSupportDirectory();
  return directory.path;
}

С помощью приведенного выше кода мы можем получить путь к хранилищу, но что, если мы не хотим загружать файл в путь к хранилищу? Например, мне нравится устанавливать отдельный/DownloadПуть специально используется для сохранения загруженного файла, что на самом деле очень просто:

// 获取存储路径
var _localPath = (await _findLocalPath()) + '/Download';

final savedDir = Directory(_localPath);
// 判断下载路径是否存在
bool hasExisted = await savedDir.exists();
// 不存在就新建路径
if (!hasExisted) {
  savedDir.create();
}

загрузить файл

Скачать файл Здесь я нашел некоторую информацию и обнаружил, что там, кажется, только одинflutter_downloaderПлагин, я не знаю, что происходит. Процесс настройки этого плагина тоже довольно сложен, но к счастью документация (universal.flutter-io.capable/packages/law…) написано довольно четко. Этот плагин может реализовать фоновую загрузку на базе AndroidWorkManagerВ iOSNSURLSessionDownloadTaskосуществленный.

Далее поговорим о настройках на стороне iOS и Android соответственно.

Конфигурация плагина

Конфигурация на стороне iOS

  • включитьbackground mode

Чтобы выполнить этот шаг, мы открываем проектiOS module,Как показано ниже:

Затем дважды щелкните слеваRunnerвариант, выбирайCapabilitiesопция, включенная, как показаноbackground mode

  • Добавить кsqliteБиблиотека зависимостей

Документация также предоставляет некоторыеНеобязательный:

  • Настроить поддержку HTTP-запросов

Из соображений безопасности Apple официально запретила разработчикам использовать небезопасный протокол связи http по умолчанию и вместо этого рекомендует разработчикам использовать безопасный протокол https. Если нам все еще нужно использовать протокол http, нам нужно выполнить некоторую настройку.В документе предусмотрено два способа настройки: один – доменное имя, разрешающее один HTTP-запрос, а другой – доменное имя, разрешающее все HTTP-запросы. В демонстрационных целях выберите первые два вида.

просто нужноInfo.plistДобавьте в файл следующий код:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key><true/>
</dict>
  • Установите максимальное количество одновременных загрузок

По умолчанию поддерживается загрузка до 3-х файлов одновременно, если вам нужно изменить один и тот жеInfo.plist

<key>FDMaximumConcurrentTasks</key>
<integer>5</integer>
  • Установить уведомление о завершении загрузки

Так же модифицироватьInfo.plist:

<key>FDAllFilesDownloadedMessage</key>
<string>All files have been downloaded</string>

Конфигурация на стороне Android

После разговора о конфигурации на стороне iOS, давайте поговорим о конфигурации на стороне Android. существуетAndroidManifest.xmlДобавьте в файл следующий код:

<provider
    android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
    android:authorities="${applicationId}.flutter_downloader.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

Места следующие:

WX20190713-174805@2x

Есть и другие опциональные конфигурации, похожие на сторону iOS, с аналогичными функциями, поэтому я не буду их здесь упоминать, подробности смотрите на официальном сайте.

написать код загрузки

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

// 根据 downloadUrl 和 savePath 下载文件
_downloadFile(downloadUrl, savePath) async {
  await FlutterDownloader.enqueue(
    url: downloadUrl,
    savedDir: savePath,
    showNotification: true,
    // show download progress in status bar (for Android)
    openFileFromNotification:
        true, // click on notification to open downloaded file (for Android)
  );
}

Конечно, мы должны представить заранееflutter_downloaderбиблиотека

import 'package:flutter_downloader/flutter_downloader.dart';

Документ также предоставляет другие API, такие как приостановка загрузки и отмена загрузки, которые не будут здесь описываться, документ написан очень ясно.

На данный момент логика загрузки фактически завершена.Однако логика загрузки была реализована.Чтобы пользователи поняли, нам нужно добавить некоторую подсказку, такую ​​как индикатор выполнения загрузки и подсказка о завершении загрузки, показанные в демонстрации на в начале окна, давайте настроим эти подсказки для загрузки.

Установить информацию о загрузке

Здесь процесс загрузки показан в виде диалогового окна и индикатора выполнения.Мы использовалиprogress_dialogЭтот плагин может легко отображать диалог загрузки по адресу https://pub.flutter-io.cn/packages/progress_dialog.

использоватьprogress_dialogПлагин очень простой, сначала мы вводим файл зависимостей:

import 'package:progress_dialog/progress_dialog.dart';

Затем создайте диалог:

ProgressDialog pr;

Если мы хотим создать диалоговое окно с запросом на загрузку, нам просто нужно инициализировать диалоговое окно в соответствующем месте:

pr = new ProgressDialog(context,ProgressDialogType.Download);

затем выполнитьpr.show();Отображается диалоговое окно. Отменить этот диалог тоже очень просто, достаточно выполнитьpr.hide();

Если вы хотите обновить подсказку в диалоговом окне, такую ​​как ход загрузки, просто выполните следующий код:

pr.update(progress: percentage,message: "Please wait...");

В то же время мы также можемisShowing()Функция для определения того, отображается ли диалоговое окно

bool isProgressDialogShowing = pr.isShowing();

Это очень удобно?

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

FlutterDownloader.registerCallback((id, status, progress) {
  // code to update your UI
});

вidэто идентификатор задачи загрузки,statusэто статус текущей задачи загрузки id, естьundefined,enqueued,running,complete,failed,canceled,pausedэти состояния,progressЭто ход выполнения текущей задачи загрузки идентификатора.

Для удобства я выбираюinitState()Инициализируйте функцию обратного вызова загрузки и диалоговое окно в функции:

@override
void initState() {
  super.initState();
  // 初始化进度条
  ProgressDialog pr = new ProgressDialog(context, ProgressDialogType.Download);
  pr.setMessage('下载中…');
  // 设置下载回调
  FlutterDownloader.registerCallback((id, status, progress) {
  	// 打印输出下载信息
    print('Download task ($id) is in status ($status) and process ($progress)');
    ......
  });

Тогда нам нужно обсудить в соответствии со статусом загрузки

@override
void initState() {
  super.initState();
  ......
  // 设置下载回调
  FlutterDownloader.registerCallback((id, status, progress) {
  	// 打印输出下载信息
    print('Download task ($id) is in status ($status) and process ($progress)');
    if (!pr.isShowing()) {
      pr.show();
    }
    if (status == DownloadTaskStatus.running) {
      pr.update(progress: progress.toDouble(), message: "下载中,请稍后…");
    }
    if (status == DownloadTaskStatus.failed) {
      showToast("下载异常,请稍后重试");
      if (pr.isShowing()) {
        pr.hide();
      }
    }
    if (status == DownloadTaskStatus.complete) {
      print(pr.isShowing());
      if (pr.isShowing()) {
        pr.hide();
      }
    }
  });


На самом деле, операция загрузки файла здесь завершена, но обычно после завершения загрузки приложение предложит вам открыть его, поэтому здесь мы просто расширяем его, чтобы открыть загруженный файл.

Откройте загруженный файл

Как открыть загруженный файл? Плагин уже предоставляет API для открытия загруженного файла, нам просто нужно использовать его, как показано ниже.

// 根据taskId打开下载文件
Future<bool> _openDownloadedFile(taskId) {
  return FlutterDownloader.open(taskId: taskId);
}

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

код показывает, как показано ниже

@override
void initState() {
  super.initState();
		......
    if (status == DownloadTaskStatus.complete) {
      print(pr.isShowing());
      if (pr.isShowing()) {
        pr.hide();
      }
      // 显示是否打开的对话框
      showDialog(
          // 设置点击 dialog 外部不取消 dialog,默认能够取消
          barrierDismissible: false,
          context: context,
          builder: (context) => AlertDialog(
                title: Text('提示'),
                // 标题文字样式
                content: Text('文件下载完成,是否打开?'),
                // 内容文字样式
                backgroundColor: CupertinoColors.white,
                elevation: 8.0,
                // 投影的阴影高度
                semanticLabel: 'Label',
                // 这个用于无障碍下弹出 dialog 的提示
                shape: Border.all(),
                // dialog 的操作按钮,actions 的个数尽量控制不要过多,否则会溢出 `Overflow`
                actions: <Widget>[
                  // 点击取消按钮
                  FlatButton(
                      onPressed: () => Navigator.pop(context),
                      child: Text('取消')),
                  // 点击打开按钮
                  FlatButton(
                      onPressed: () {
                        Navigator.pop(context);
                        // 打开文件
                        _openDownloadedFile(id).then((success) {
                          if (!success) {
                            Scaffold.of(context).showSnackBar(SnackBar(
                                content: Text('Cannot open this file')));
                          }
                        });
                      },
                      child: Text('打开')),
                ],
              ));
    }
  });
}

Использование диалогового окна подробно прокомментировано.

До сих пор мы использовали Flutter для завершения полного процесса загрузки файлов.

Суммировать

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

Наконец, если вам нужен исходный код, вы можете отсканировать QR-код ниже, чтобы подписаться на мою официальную учетную запись «01 binary», и ответить «Загрузка файла Flutter» в фоновом режиме. Позже я буду обновлять некоторые статьи, связанные с Flutter, время от времени. время Я надеюсь, что вы можете поддержать больше.