123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- import 'dart:async';
- import 'dart:io';
- import 'package:app_installer/app_installer.dart';
- import 'package:dio/dio.dart';
- class DownloadStatus {
- String tag;
- String path;
- int count;
- int total;
- bool done;
- bool failed;
- DioError? error;
- DownloadStatus(
- this.tag, this.path, this.count, this.total, this.done, this.failed,{this.error});
- }
- /*
- * 文件下载
- * 懒加载单例
- */
- class DownLoadManage {
- //用于记录正在下载的url,避免重复下载
- // var downloadingUrls = new List();
- var downloadingUrls = new Map<String, CancelToken>();
- // 单例公开访问点
- factory DownLoadManage() => _getInstance();
- // 静态私有成员,没有初始化
- static DownLoadManage? _instance;
- // 私有构造函数
- DownLoadManage._() {
- // 具体初始化代码
- }
- // 静态、同步、私有访问点
- static DownLoadManage _getInstance() {
- if (_instance == null) {
- _instance = DownLoadManage._();
- }
- return _instance!;
- }
- final StreamController<DownloadStatus> _controller =
- StreamController.broadcast();
- Stream<DownloadStatus> get stream => _controller.stream;
- /*
- *下载
- */
- Future<bool> download(url, savePath) async {
- int downloadStart = 0;
- bool fileExists = false;
- File f = File(savePath);
- if (await f.exists()) {
- downloadStart = f.lengthSync();
- fileExists = true;
- }
- print(
- "download $url $fileExists ${downloadingUrls.containsKey(url)} ${downloadingUrls[url]?.isCancelled} ${downloadingUrls.length}");
- if (fileExists &&
- downloadingUrls.containsKey(url) &&
- !(downloadingUrls[url]?.isCancelled ?? false)) {
- print("download $url $fileExists");
- //正在下载
- return false;
- }
- CancelToken cancelToken = new CancelToken();
- // downloadingUrls[url] = cancelToken;
- if (downloadingUrls[url] == null) {
- downloadingUrls[url] = cancelToken;
- }
- var dio = Dio();
- String contentLength;
- int _total = 0;
- try {
- contentLength = await _getContentLength(dio, url, cancelToken);
- print("download contentLength :$contentLength");
- _total = int.parse(contentLength);
- print("download start :$downloadStart -- contentLength: $contentLength");
- if (downloadStart >= _total) {
- stop(url);
- //存在本地文件,命中缓存
- _controller.add(
- DownloadStatus(url, savePath, downloadStart, _total, true, false));
- // done?.call();
- return true;
- }
- } catch (e) {
- print(e);
- stop(url);
- return false;
- }
- cancelToken = new CancelToken();
- downloadingUrls[url] = cancelToken;
- File tmp = File("$savePath.tmp$downloadStart");
- tmp.createSync();
- var resp = await dio
- .download(url, tmp.path,
- deleteOnError: false,
- onReceiveProgress: (index, total) {
- _controller.add(DownloadStatus(
- url, savePath, index + downloadStart, _total, false, false));
- // print("url --- > $index, $total");
- },
- // onReceiveProgress?.call(index + downloadStart, _total),
- cancelToken: cancelToken,
- options: Options(
- followRedirects: false,
- headers: {"range": "bytes=$downloadStart-$contentLength"},
- ))
- .whenComplete(() {
- downloadingUrls.remove(url);
- print("download whenComplete $url");
- }).catchError((e) async {
- print("download catch $e");
- downloadingUrls.remove(url);
- if(e is DioError){
- _controller.add(DownloadStatus(url, savePath, 0, _total, false, true, error: e));
- }else {
- _controller.add(DownloadStatus(url, savePath, 0, _total, false, true));
- }
- // failed?.call(e);
- });
- await append(f, tmp);
- if (resp != null) {
- // done?.call();
- _controller.add(DownloadStatus(url, savePath, 0, _total, true, false));
- return true;
- }
- return false;
- // downloadingUrls.remove(url);
- // done.call();
- }
- append(File file, File tmp) async {
- IOSink ioSink = file.openWrite(mode: FileMode.writeOnlyAppend);
- await ioSink.addStream(tmp.openRead());
- await tmp.delete(); //删除临时文件
- await ioSink.close();
- print("download save file ---------file --- ${file.lengthSync()}");
- }
- /*
- * 获取下载的文件大小
- */
- Future _getContentLength(Dio dio, url, CancelToken cancelToken) async {
- try {
- Response response = await dio.head(url, cancelToken: cancelToken);
- return response.headers.value(Headers.contentLengthHeader);
- } catch (e) {
- print("download _getContentLength Failed:" + e.toString());
- return 0;
- }
- }
- void stop(String url) {
- if (downloadingUrls.containsKey(url)) {
- try {
- downloadingUrls[url]?.cancel();
- } catch (e) {
- print(e);
- }
- }
- downloadingUrls.remove(url);
- }
- bool isDowning(String url) {
- return downloadingUrls.containsKey(url);
- }
- }
|