Dio
dio是一个强大的Dart Http请求库,提供了丰富的功能和易于使用的API,支持文件上传和下载。
这个就不介绍了,网上有很多的封装案例。
background_downloader
简介
适用于iOS,Android,MacOS,Windows和Linux的后台文件下载器和上传器。
官方文档
https://pub-web.flutter-io.cn/packages/background_downloader
安装
flutter pub add background_downloader
示例1:下载
class _MyHomePageState extends State<MyHomePage> {
// 文件信息
String fileInfo = '';
// 下载进度
double progress = 0.0;
// 任务状态
String taskStatus = '';
// 任务
late DownloadTask task;
// 下载单个文件
_downloadFile() async {
task = DownloadTask(
url:
'https://vd3.bdstatic.com/mda-ma6igm4b0znfbqve/sc/cae_h264_nowatermark/1609998111/mda-ma6igm4b0znfbqve.mp4', // 下载地址
// urlQueryParameters: {'q': 'pizza'}, // 请求参数
filename: 'mov_bbb.mp4', // 文件名
//headers: {'myHeader': 'value'}, 请求头
directory: 'my_sub_directory', // 文件存储目录
updates: Updates.statusAndProgress, // 更新任务状态和下载进度
requiresWiFi: true, // 使用wifi
retries: 5, // 下载的重试次数
allowPause: true, // 运行暂停
metaData: 'data for me' // 元数据,可以存储一些对于下载任务有用的信息,方便后续相关操作
);
// 监听下载
final result =
await FileDownloader().download(task, onProgress: (progress) {
setState(() {
this.progress = progress;
});
}, onStatus: (states) {
String msg = '';
if (states == TaskStatus.complete) {
msg = '下载完成';
// 下载完成后,将文件移动到共享目录后,其他应用也可以访问。否则只能在本应用内访问
FileDownloader().moveToSharedStorage(task, SharedStorage.downloads);
} else if (states == TaskStatus.canceled) {
msg = '已取消';
setState(() {
progress = 0;
});
} else if (states == TaskStatus.paused) {
msg = '已暂停';
} else if (states == TaskStatus.running) {
msg = '下载中...';
} else {
msg = '下载失败';
}
setState(() {
taskStatus = msg;
});
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Column(
children: [
const SizedBox(
height: 20,
),
Text("文件信息:$fileInfo"),
const SizedBox(
height: 20,
),
Row(
children: [
const Text("下载进度:"),
Expanded(
child: LinearProgressIndicator(
value: progress,
backgroundColor: Colors.greenAccent,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.red),
)),
Text("${(progress * 100).toStringAsFixed(1)}%")
],
),
Text("任务状态:$taskStatus"),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: [
ElevatedButton(
onPressed: _downloadFile, child: const Text("下载")),
ElevatedButton(
onPressed: () async {
// 暂停任务
await FileDownloader().pause(task);
},
child: const Text("暂停")),
ElevatedButton(
onPressed: () async {
// 根据固定的任务id取消
await FileDownloader().cancelTaskWithId(task.taskId);
// 取消所有
//FileDownloader().cancelTasksWithIds(taskIds)
},
child: const Text("取消")),
ElevatedButton(
onPressed: () async {
await FileDownloader().resume(task);
},
child: const Text("恢复"))
],
)
],
));
}
}
注意:
- 默认下载的文件是在本应用内,其他应用无访问权限。要想要被访问到需要在下载完成后执行
FileDownloader().moveToSharedStorage(task, SharedStorage.downloads);
- 点击暂停后,再点击恢复可以继续下载。点击取消后,再点击恢复无法继续下载。
示例2:上传
/// define the multi-part upload task (subset of parameters shown)
final task = UploadTask(
url: 'https://myserver.com/uploads',
filename: 'myData.txt',
fields: {'datafield': 'value'},
fileField: 'myFile',
updates: Updates.statusAndProgress // request status and progress updates
);
// Start upload, and wait for result. Show progress and status changes
// while uploading
final result = await FileDownloader().upload(task,
onProgress: (progress) => print('Progress: ${progress * 100}%'),
onStatus: (status) => print('Status: $status')
);
// Act on result, similar to download
这个没有服务器,没有尝试,上面的是官方例子。
示例3:批量下载
final tasks = [task1, task2, task3]; // a list of Download tasks
// download the batch
final result = await FileDownloader().downloadBatch(tasks,
batchProgressCallback: (succeeded, failed) =>
print('Completed ${succeeded + failed} out of ${tasks.length}, $failed failed')
);
使用DownloadTask
会返回一个任务,多个任务可以使用downloadBatch
来进行批量下载。
示例4:发起通知
按照官方例子试了一下,一直没有发起通知。
我这里的问题是app没有通知权限,在设置里也无法开启通知。
如果你也没有成功的话,可以使用flutter_local_notifications
来实现通知功能
Flutter:flutter_local_notifications——消息推送的学习
示例5:打开下载文件
_downloadFile() async {
task = DownloadTask(
url:
'https://ppt.1ppt.com/uploads/soft/2307/1-230H1092638.zip', // 下载地址
// urlQueryParameters: {'q': 'pizza'}, // 请求参数
filename: '1-230H1092638.zip', // 文件名
//headers: {'myHeader': 'value'}, 请求头
directory: 'my_sub_directory', // 文件存储目录
baseDirectory: BaseDirectory.applicationSupport,
updates: Updates.statusAndProgress, // 更新任务状态和下载进度
requiresWiFi: true, // 使用wifi
retries: 5, // 下载的重试次数
allowPause: true, // 运行暂停
metaData: 'data for me' // 元数据,可以存储一些对于下载任务有用的信息,方便后续相关操作
);
// 监听下载
final result =
await FileDownloader().download(task, onProgress: (progress) {
setState(() {
this.progress = progress;
});
}, onStatus: (states) async{
String msg = '';
if (states == TaskStatus.complete) {
msg = '下载完成';
await FileDownloader().openFile(task: task);
print("路径:${await task.filePath()}");
} else if (states == TaskStatus.canceled) {
msg = '已取消';
setState(() {
progress = 0;
});
} else if (states == TaskStatus.paused) {
msg = '已暂停';
} else if (states == TaskStatus.running) {
msg = '下载中...';
} else {
msg = '下载失败';
}
setState(() {
taskStatus = msg;
});
});
}
注意:
- 必须要添加
baseDirectory: BaseDirectory.applicationSupport,
,否则是无法打开文件的 - 如果要打开文件,那么就不能使用
FileDownloader().moveToSharedStorage(task, SharedStorage.downloads);
移动文件,会导致找不到文件进而打不开。另外打开文件时会调用你手机里有的应用程序打开,我试了一下图片、mp4
下载完成后是可以直接打开的,但是zip
这样的文件是无法直接打开的,这时会让你选择你手机里的应用来打开。
遇到的问题
这是因为background_downloader
要求最小的sdk版本是24,而Flutter会自动设置minSdkVersion
为16(Android 4.1),在你的Flutter项目的android/app/build.gradle
文件中,将minSdkVersion
更改为24或更高的版本。然后运行flutter clean
清理项目,并重新构建你的应用程序。
从flutter仓库找到了该问题的解决方案:https://github.com/flutter/flutter/issues/119247
在android / app/build.gradle
文件中添加
configurations.all {
resolutionStrategy {
eachDependency {
if ((requested.group == "org.jetbrains.kotlin") && (requested.name.startsWith("kotlin-stdlib"))) {
useVersion("1.8.0")
}
}
}
}