startDownload method
开始或继续下载
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);
}
}