download.dart 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:dio/dio.dart' as dio;
  4. import 'package:dio/dio.dart';
  5. /*
  6. * 文件下载
  7. * 懒加载单例
  8. */
  9. class DownLoadManage {
  10. //用于记录正在下载的url,避免重复下载
  11. // var downloadingUrls = new List();
  12. var downloadingUrls = new Map<String, CancelToken>();
  13. // 单例公开访问点
  14. factory DownLoadManage() => _getInstance();
  15. // 静态私有成员,没有初始化
  16. static DownLoadManage _instance;
  17. // 私有构造函数
  18. DownLoadManage._() {
  19. // 具体初始化代码
  20. }
  21. Object _assureDioError(err) {
  22. if (err is DioError) {
  23. return err;
  24. } else {
  25. var _err = DioError(error: err);
  26. return _err;
  27. }
  28. }
  29. // 静态、同步、私有访问点
  30. static DownLoadManage _getInstance() {
  31. if (_instance == null) {
  32. _instance = DownLoadManage._();
  33. }
  34. return _instance;
  35. }
  36. /*
  37. *下载
  38. */
  39. Future download(url, savePath, {ProgressCallback onReceiveProgress, Function done, Function failed}) async {
  40. int downloadStart = 0;
  41. bool fileExists = false;
  42. File f = File(savePath);
  43. if (await f.exists()) {
  44. downloadStart = f.lengthSync();
  45. fileExists = true;
  46. }
  47. print("$url $fileExists ${downloadingUrls.containsKey(url) } ${downloadingUrls[url]?.isCancelled} ${downloadingUrls.length}");
  48. if (fileExists && downloadingUrls.containsKey(url) && !downloadingUrls[url].isCancelled) {
  49. print("$url $fileExists");
  50. //正在下载
  51. return;
  52. }
  53. CancelToken cancelToken = new CancelToken();
  54. // downloadingUrls[url] = cancelToken;
  55. if (downloadingUrls[url] == null) {
  56. downloadingUrls[url] = cancelToken;
  57. }
  58. var dio = Dio();
  59. String contentLength;
  60. int _total=0;
  61. try {
  62. contentLength = await _getContentLength(dio, url, cancelToken);
  63. print("contentLength :$contentLength");
  64. _total = int.parse(contentLength);
  65. print("start :$downloadStart -- contentLength: $contentLength");
  66. if (downloadStart >= _total) {
  67. //存在本地文件,命中缓存
  68. done();
  69. return;
  70. }
  71. } catch (e) {
  72. print(e);
  73. stop(url);
  74. return;
  75. }
  76. cancelToken = new CancelToken();
  77. downloadingUrls[url] = cancelToken;
  78. File tmp = File("$savePath.tmp$downloadStart");
  79. tmp.createSync();
  80. var resp = await dio
  81. .download(url, tmp.path,
  82. deleteOnError: false,
  83. onReceiveProgress: (index, total) => onReceiveProgress(index + downloadStart, _total),
  84. cancelToken: cancelToken,
  85. options: Options(
  86. followRedirects: false,
  87. headers: {"range": "bytes=$downloadStart-$contentLength"},
  88. ))
  89. .whenComplete(() {
  90. downloadingUrls.remove(url);
  91. }).catchError((e) async {
  92. failed.call(e);
  93. });
  94. await append(f, tmp);
  95. if (resp != null) {
  96. done.call();
  97. }
  98. // downloadingUrls.remove(url);
  99. // done.call();
  100. }
  101. append(File file, File tmp) async {
  102. IOSink ioSink = file.openWrite(mode: FileMode.writeOnlyAppend);
  103. print("save file ---------1111111111111 --- ${tmp.lengthSync()}");
  104. await ioSink.addStream(tmp.openRead());
  105. await tmp.delete(); //删除临时文件
  106. await ioSink.close();
  107. }
  108. /*
  109. * 获取下载的文件大小
  110. */
  111. Future _getContentLength(Dio dio, url, CancelToken cancelToken) async {
  112. try {
  113. Response response = await dio.head(url, cancelToken: cancelToken);
  114. return response.headers.value(Headers.contentLengthHeader);
  115. } catch (e) {
  116. print("_getContentLength Failed:" + e.toString());
  117. return 0;
  118. }
  119. }
  120. void stop(String url) {
  121. if (downloadingUrls.containsKey(url)) {
  122. try {
  123. downloadingUrls[url].cancel();
  124. } catch (e) {
  125. print(e);
  126. downloadingUrls.remove(url);
  127. }
  128. }
  129. }
  130. Future<T> _listenCancelForAsyncTask<T>(CancelToken cancelToken, Future<T> future) {
  131. if (cancelToken != null && cancelToken.cancelError == null) {
  132. // cancelToken.addCompleter(completer);
  133. // return Future.any([completer.future, future]).then<T>((result) {
  134. // cancelToken.removeCompleter(completer);
  135. // return result;
  136. // }).catchError((e) {
  137. // cancelToken.removeCompleter(completer);
  138. // throw e;
  139. // });
  140. // }
  141. return Future.any([cancelToken.whenCancel, future]).then((value) {
  142. // return value;
  143. cancelToken.cancel("下载取消");
  144. return value;
  145. }).catchError((e) {
  146. throw e;
  147. });
  148. } else {
  149. return future;
  150. }
  151. }
  152. }