用于创建和管理下载任务的插件。支持 iOS 和 Android。
该插件在 Android 上使用WorkManager
,在 iOS 上使用NSURLSessionDownloadTask
在后台运行下载任务。
Android 11 中外部存储 API 的更改导致当前实现出现一些问题。我决定使用新策略重新设计这个插件来管理下载文件位置。本 PR 中仍在分类和讨论中。非常感谢 Flutter 开发人员的贡献和反馈,以获得更好的插件设计。
在此软件包的早期版本中,存在与 SQL 注入相关的已知漏洞。 SQL 注入是一种安全漏洞,可以允许恶意用户操纵应用程序执行的 SQL 查询,从而可能导致未经授权的访问或操纵数据库。
强烈建议升级到该软件包的最新版本,以确保您的应用程序不会受到 SQL 注入漏洞的影响。最新版本包含必要的安全改进和补丁来减轻此类风险。
以下步骤需要在 Xcode 中打开您的ios
项目。
启用后台模式。
添加sqlite
库。
配置AppDelegate
:
Objective-C:
/// AppDelegate.h#import#import @interface AppDelegate : FlutterAppDelegate@end
// AppDelegate.m#include "AppDelegate.h"#include "GeneratePluginRegistrant.h"#include "FlutterDownloaderPlugin.h"@implementation AppDelegatevoid registerPlugins(NSObject*registry) { if (![registry hasPlugin:@"FlutterDownloaderPlugin" ]) { [FlutterDownloaderPlugin registerWithRegistrar:[注册表registrarForPlugin:@"FlutterDownloaderPlugin"]]; } } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratePluginRegistrant registerWithRegistry:self]; [FlutterDownloaderPlugin setPluginRegistrantCallback:registerPlugins]; // 应用程序启动后覆盖自定义点。 返回[超级应用程序:应用程序didFinishLaunchingWithOptions:launchOptions]; }@结尾
或者斯威夫特:
导入 UIKit 导入颤振 导入 flutter_downloader@UIApplicationMain@objc 类 AppDelegate: FlutterAppDelegate { 覆盖 func application( _ 应用程序:UIApplication, didFinishLaunchingWithOptions launchOptions:[UIApplication.LaunchOptionsKey:任何]? ) -> Bool { generatedPluginRegistrant.register(with: self) FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins) return super.application(application, didFinishLaunchingWithOptions: launchOptions) }}private func registerPlugins(registry: FlutterPluginRegistry) { if (!registry.hasPlugin("FlutterDownloaderPlugin")) { FlutterDownloaderPlugin.register(with:registry.registrar(forPlugin: "FlutterDownloaderPlugin")!) }}
支持 HTTP 请求:如果要使用 HTTP 请求下载文件,则需要禁用 Apple Transport Security (ATS) 功能。有两个选择:
仅针对特定域禁用 ATS:(将以下代码添加到您的Info.plist
文件中)
NSAppTransportSecurity <字典>NSExceptionDomains <字典>www.yourserver.com NSincludesSubdomains NSTemporaryExceptionAllowsInsecureHTTPLoads NSTemporaryExceptionMinimumTLSVersion <字符串>TLSv1.1字符串> 字典> 字典> 字典>
完全禁用 ATS。将以下内容添加到您的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="vn.hunghd.flutterdownloader.MAX_CONCURRENT_TASKS" android:value="5" />
您可以通过本地化以下消息来本地化下载进度通知中的文本。
下载已开始 正在下载 下载已取消 下载失败 下载完成 下载已暂停
您可以在此处了解有关 Android 本地化的更多信息。
要打开并安装.apk
文件,您的应用程序需要REQUEST_INSTALL_PACKAGES
权限。在AndroidManifest.xml
中添加以下内容:
参见:
修复 Android 9 Pie 上的明文流量错误
导入 'package:flutter_downloader/flutter_downloader.dart';void main() { WidgetsFlutterBinding.ensureInitialized(); // 使用之前必须初始化插件await FlutterDownloader.initialize( debug: true, // 可选:设置为 false 以禁用将日志打印到控制台(默认值:true) ignoreSsl: true // 选项:设置为 false 以禁用 http 链接(默认值: false) ); 运行应用程序(/*...*/) }
最终任务Id =等待FlutterDownloader.enqueue( url: '您的下载链接', headers: {}, // 可选:使用 url(身份验证令牌等)发送标头 saveDir: '要保存下载文件的目录路径', showNotification: true, // 在状态栏中显示下载进度(适用于 Android) openFileFromNotification: true, // 单击通知打开下载的文件(适用于 Android);
等待 FlutterDownloader.registerCallback(回调); // 回调是顶级函数或静态函数
重要的
UI在主isolate上渲染,而下载事件来自后台isolate(换句话说, callback
中的代码在后台isolate中运行),因此您必须处理两个isolate之间的通信。例如:
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) { Final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port'); send.send([id, 状态, 进度]); }
@pragma('vm:entry-point')
必须放置在callback
函数上方,以避免 Android 发布模式下的树抖动。
最终任务=等待FlutterDownloader.loadTasks();
最终任务=等待FlutterDownloader.loadTasksWithRawQuery(query: query);
为了成功将数据解析为DownloadTask
对象,您应该从数据库中加载包含所有字段的数据(换句话说,使用SELECT *
)。例如:
SELECT * FROM 任务 WHERE status=3
下面是task
表的架构, flutter_downloader
插件存储有关下载任务的信息
创建表 `task` ( `id` INTEGER PRIMARY KEY AUTOINCRMENT, `task_id` VARCHAR ( 256 ), `url` TEXT, `status` INTEGER DEFAULT 0, `progress` INTEGER DEFAULT 0, `file_name` TEXT, `saved_dir` TEXT 、`可恢复` TINYINT 默认值 0、`headers` 文本、`show_notification` TINYINT 默认值 0、`open_file_from_notification` TINYINT 默认值 0、`time_created` INTEGER 默认值 0);
FlutterDownloader.cancel(taskId: taskId);
FlutterDownloader.cancelAll();
FlutterDownloader.pause(taskId:taskId);
FlutterDownloader.resume(taskId: taskId);
resume()
将返回一个新的taskId
该任务 ID 对应于为继续下载过程而创建的新后台任务。您应该用新的taskId
替换旧的taskId
(已paused
状态)以继续跟踪下载进度。
FlutterDownloader.retry(taskId: taskId);
retry()
将返回一个新的taskId
(就像resume()
一样)
FlutterDownloader.remove(taskId: taskId, shouldDeleteContent:false);
FlutterDownloader.open(taskId: taskId);
在 Android 上,您只能打开位于外部存储中的下载文件,并且设备上至少有一个应用程序可以读取该文件类型。
如果您遇到任何问题或认为该插件缺少某些功能,请随时提出问题。
也非常欢迎请求请求!