download.dart 4.4 KB

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