startDownload method

Future<void> startDownload()

开始或继续下载

Implementation

Future<void> startDownload() async {
  if (!Platform.isAndroid) assert(false, 'Only Android is supported');

  if (_updateInfo == null || _updateInfo!.latestVersion == null) {
    _log('错误: 更新信息或下载链接为空。');
    statusNotifier.value = DownloadStatus.error;
    return;
  }

  if (statusNotifier.value == DownloadStatus.downloading) {
    _log('下载已在进行中。');
    return;
  }

  statusNotifier.value = DownloadStatus.downloading;
  _cancelToken = CancelToken();

  final latestVersion = _updateInfo!.latestVersion!;

  try {
    final tempDir = await getTemporaryDirectory();
    _savePath = '${tempDir.path}/app-v${latestVersion.version}.apk';

    _log('本地路径: $_savePath');
    _log('下载链接: ${latestVersion.downloadUrl}');

    int existingLength = 0;
    final file = File(_savePath!);
    if (await file.exists()) {
      existingLength = await file.length();
      _log('文件已存在,大小: $existingLength bytes. 尝试断点续传。');
    }

    // 检查已下载部分是否等于总大小
    if (latestVersion.apkSize == existingLength) {
      _log('文件已完整下载,直接进入完成状态。');
      await _onDownloadCompleted();
      return;
    }

    await _dio.download(
      latestVersion.downloadUrl,
      _savePath,
      cancelToken: _cancelToken,
      onReceiveProgress: (received, total) {
        // total 可能为-1,如果服务器未返回Content-Length
        final int totalSize = total > 0 ? total : (latestVersion.apkSize);
        if (totalSize > 0) {
          progressNotifier.value = (existingLength + received) / (existingLength + totalSize);
        }
        _log('下载进度: ${progressNotifier.value.toStringAsFixed(2)}');
      },
      // 设置 Range 请求头以实现断点续传
      options: Options(headers: {'range': 'bytes=$existingLength-'}),
      deleteOnError: true,
    );

    await _onDownloadCompleted();
  } on DioException catch (e) {
    if (CancelToken.isCancel(e)) {
      statusNotifier.value = DownloadStatus.paused;
      _log('下载已暂停。');
    } else {
      statusNotifier.value = DownloadStatus.error;
      _log('下载出错: $e');
      _errorHandler?.call(e);
    }
  } catch (e) {
    statusNotifier.value = DownloadStatus.error;
    _log('下载时发生未知错误: $e');
    _errorHandler?.call(e);
  }
}