123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- import 'dart:async';
- import 'dart:io';
- import 'package:dio/dio.dart' as dio;
- import 'package:dio/dio.dart';
- /*
- * 文件下载
- * 懒加载单例
- */
- class DownLoadManage {
- //用于记录正在下载的url,避免重复下载
- // var downloadingUrls = new List();
- var downloadingUrls = new Map<String, CancelToken>();
- // 单例公开访问点
- factory DownLoadManage() => _getInstance();
- // 静态私有成员,没有初始化
- static DownLoadManage _instance;
- // 私有构造函数
- DownLoadManage._() {
- // 具体初始化代码
- }
- Object _assureDioError(err) {
- if (err is DioError) {
- return err;
- } else {
- var _err = DioError(error: err);
- return _err;
- }
- }
- // 静态、同步、私有访问点
- static DownLoadManage _getInstance() {
- if (_instance == null) {
- _instance = DownLoadManage._();
- }
- return _instance;
- }
- /*
- *下载
- */
- Future download(url, savePath, {ProgressCallback onReceiveProgress, Function done, Function failed}) async {
- int downloadStart = 0;
- bool fileExists = false;
- File f = File(savePath);
- if (await f.exists()) {
- downloadStart = f.lengthSync();
- fileExists = true;
- }
- print("$url $fileExists ${downloadingUrls.containsKey(url) } ${downloadingUrls[url]?.isCancelled} ${downloadingUrls.length}");
- if (fileExists && downloadingUrls.containsKey(url) && !downloadingUrls[url].isCancelled) {
- print("$url $fileExists");
- //正在下载
- return;
- }
- 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("contentLength :$contentLength");
- _total = int.parse(contentLength);
- print("start :$downloadStart -- contentLength: $contentLength");
- if (downloadStart >= _total) {
- //存在本地文件,命中缓存
- done();
- return;
- }
- } catch (e) {
- print(e);
- stop(url);
- return;
- }
- 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) => onReceiveProgress(index + downloadStart, _total),
- cancelToken: cancelToken,
- options: Options(
- followRedirects: false,
- headers: {"range": "bytes=$downloadStart-$contentLength"},
- ))
- .whenComplete(() {
- downloadingUrls.remove(url);
- }).catchError((e) async {
- failed.call(e);
- });
- await append(f, tmp);
- if (resp != null) {
- done.call();
- }
- // downloadingUrls.remove(url);
- // done.call();
- }
- append(File file, File tmp) async {
- IOSink ioSink = file.openWrite(mode: FileMode.writeOnlyAppend);
- print("save file ---------1111111111111 --- ${tmp.lengthSync()}");
- await ioSink.addStream(tmp.openRead());
- await tmp.delete(); //删除临时文件
- await ioSink.close();
- }
- /*
- * 获取下载的文件大小
- */
- 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("_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);
- }
- }
- }
- Future<T> _listenCancelForAsyncTask<T>(CancelToken cancelToken, Future<T> future) {
- if (cancelToken != null && cancelToken.cancelError == null) {
- // cancelToken.addCompleter(completer);
- // return Future.any([completer.future, future]).then<T>((result) {
- // cancelToken.removeCompleter(completer);
- // return result;
- // }).catchError((e) {
- // cancelToken.removeCompleter(completer);
- // throw e;
- // });
- // }
- return Future.any([cancelToken.whenCancel, future]).then((value) {
- // return value;
- cancelToken.cancel("下载取消");
- return value;
- }).catchError((e) {
- throw e;
- });
- } else {
- return future;
- }
- }
- }
|