rangDownload method

Future<CancelToken> rangDownload(
  1. String url,
  2. String savePath, {
  3. Map<String, dynamic>? queryParameters,
  4. required ProgressCallback? onProgress,
  5. VoidCallback? onDone,
  6. void onError(
    1. dynamic err
    )?,
})

断点下载

Implementation

Future<CancelToken> rangDownload(
  String url,
  String savePath, {
  Map<String, dynamic>? queryParameters,
  required ProgressCallback? onProgress,
  VoidCallback? onDone,
  void Function(dynamic err)? onError,
}) async {
  int start = 0;
  final file = File(savePath);
  if (file.existsSync()) {
    start = file.lengthSync();
  } else {
    file.createIfNotExists(recursive: true);
  }
  final cancelToken = CancelToken();
  try {
    final response = await get<ResponseBody>(
      url,
      queryParameters: queryParameters,
      options: Options(
        responseType: ResponseType.stream,
        followRedirects: false,
        headers: {'range': 'bytes=$start-'},
      ),
    );
    final raf = file.openSync(mode: FileMode.append);
    int received = start;
    var rangHeader = response.headers.value(HttpHeaders.contentRangeHeader) ??
        response.headers.value(HttpHeaders.contentLengthHeader);
    if (rangHeader == null) throw Exception('获取文件长度失败!');
    int total = int.tryParse(rangHeader.split('/').last) ?? 0;

    final stream = response.data!.stream;
    final subscription = stream.listen(
      (data) {
        raf.writeFromSync(data);
        received += data.length;
        onProgress?.call(received, total);
      },
      onDone: () async {
        await raf.close();
        onDone?.call();
      },
      onError: (err) async {
        await raf.close();
        onError?.call(err);
      },
      cancelOnError: true,
    );
    cancelToken.whenCancel.then((_) async {
      await subscription.cancel();
      await raf.close();
    });
  } on Exception catch (err) {
    onError?.call(err);
  }
  return cancelToken;
}