本示例中使用第三方库 flutter_downloader 使用Getx状态管理
在pubspec.yaml 引入插件
dependencies:
flutter_downloader: ^1.11.6
在mian.dart中初始化插件
await FlutterDownloader.initialize(
debug:
true, // optional: set to false to disable printing logs to console (default: true)
ignoreSsl:
true // option: set to false to disable working with http links (default: false)
);
实际使用 文件详情controller
///声明接收端口
final ReceivePort _port = ReceivePort();
///下载状态
bool isDown = false;
///本地文件路径
late String _saveLocalPath;
///文件下载ID
dynamic taskId = 0;
///下载文档
Future<void> downloaderPdf() async {
if (filePath.isEmpty) {
print('文件地址为空');
return;
}
if (isDown) {
print('正在下载,请勿重复点击');
return;
}
///loading
isDown = true;
print('下载中...');
taskId = await FlutterDownloader.enqueue(
url: filePath, ///文件地址
savedDir: _saveLocalPath,
fileName: '测试文档',
showNotification:
false, ///在状态栏显示下载进度(仅限Android)
openFileFromNotification:
false, ///点击通知打开下载的文件 (仅限Android)
);
///合成本地路径 可以用来缓存 在下载记录中直接打开
localFilePath = '$_saveLocalPath/${fileDetails.filename}';
update();
}
///下载监听
void _bindBackgroundIsolate() {
final isSuccess = IsolateNameServer.registerPortWithName(
_port.sendPort,
'downloader_send_port',
);
if (!isSuccess) {
_unbindBackgroundIsolate();
_bindBackgroundIsolate();
return;
}
_port.listen((dynamic data) async {
///重新下载状态
isDown = false;
final taskId = (data as List<dynamic>)[0] as String;
final status = data[1];
final progress = data[2] as int;
if (status == 3) {
print('下载完成');
///打开文件
///删除下载任务
await FlutterDownloader.remove(
taskId: taskId,
shouldDeleteContent: true,
);
}
///其他status 自行处理
});
}
///释放监听
void _unbindBackgroundIsolate() {
IsolateNameServer.removePortNameMapping('downloader_send_port');
}
///注册监听事件
('vm:entry-point')
static void downloadCallback(
String id,
int status,
int progress,
) {
IsolateNameServer.lookupPortByName('downloader_send_port')
?.send([id, status, progress]);
}
void onInit() {
super.onInit();
WidgetsBinding.instance.addPostFrameCallback((_) async {
_bindBackgroundIsolate();
FlutterDownloader.registerCallback(downloadCallback);
///获取文件存储路径
_saveLocalPath = await FileDirPath().prepareSaveDir();
update();
});
}
///页面关闭销毁监听
onClose() {
_unbindBackgroundIsolate();
super.onClose();
}
FileDirPath() 工具类 获取本地存储路径
导入对应插件
# 文件
path_provider: ^2.1.0
# 权限请求
permission_handler: ^11.0.0
# 设备信息
device_info_plus: ^9.1.1
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
class FileDirPath {
late bool _permissionReady;
Future<void> retryRequestPermission() async {
final hasGranted = await _checkPermission();
if (hasGranted) {
await prepareSaveDir();
}
_permissionReady = hasGranted;
}
///获取文件保存路径
Future<String> prepareSaveDir() async {
String localPath = (await _getSavedDir())!;
final savedDir = Directory(localPath);
if (!savedDir.existsSync()) {
await savedDir.create();
}
return localPath;
}
Future<String?> _getSavedDir() async {
String? externalStorageDirPath;
final Directory? downloadsDir;
if (Platform.isAndroid) {
try {
downloadsDir = await getDownloadsDirectory();
externalStorageDirPath = downloadsDir!.path;
print('externalStorageDirPath: $externalStorageDirPath');
} catch (err, st) {
print('failed to get downloads path: $err, $st');
final directory = await getExternalStorageDirectory();
externalStorageDirPath = directory?.path;
}
} else if (Platform.isIOS) {
// var dir = (await _dirsOnIOS)[0]; // temporary
// var dir = (await _dirsOnIOS)[1]; // applicationSupport
// var dir = (await _dirsOnIOS)[2]; // library
var dir = (await _dirsOnIOS)[3]; // applicationDocuments
//var dir = (await _dirsOnIOS)[4]; // downloads
dir ??= await getApplicationDocumentsDirectory();
externalStorageDirPath = dir.absolute.path;
}
return externalStorageDirPath;
}
Future<List<Directory?>> get _dirsOnIOS async {
final temporary = await getTemporaryDirectory();
final applicationSupport = await getApplicationSupportDirectory();
final library = await getLibraryDirectory();
final applicationDocuments = await getApplicationDocumentsDirectory();
final downloads = await getDownloadsDirectory();
final dirs = [
temporary,
applicationSupport,
library,
applicationDocuments,
downloads
];
return dirs;
}
Future<bool> _checkPermission() async {
if (Platform.isIOS) {
return true;
}
if (Platform.isAndroid) {
final info = await DeviceInfoPlugin().androidInfo;
if (info.version.sdkInt > 28) {
return true;
}
final status = await Permission.storage.status;
if (status == PermissionStatus.granted) {
return true;
}
final result = await Permission.storage.request();
return result == PermissionStatus.granted;
}
throw StateError('unknown platform');
}
}
总结
- flutter_downloader 集成配置参考插件官方文档
- **Android 存储权限变更 : **Android13以下需要声明存储权限,以上则不需要默认已授权
- 处理下载回调:flutter_downloader 插件提供了下载的回调函数,你可以利用这些回调来处理下载的状态变化,例如进度更新或下载完成。确保在你的应用中处理这些回调以提供更好的用户体验。
- 错误处理: 考虑在下载过程中处理可能的错误情况,例如网络不稳定、存储空间不足等。提供清晰的错误信息以便用户能够了解问题并可能采取相应的措施。
- 释放资源: 当你不再需要下载任务时,确保正确地释放资源,以避免潜在的内存泄漏