Files
2026-09-03 17:50:23 +08:00

86 lines
3.0 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import '../config/app_config.dart';
/// App 版本更新信息(GET /api/v1/app/update 响应 data;无记录时为空信息)
class AppUpdateInfo {
final String version;
final String notes;
const AppUpdateInfo({required this.version, required this.notes});
/// 服务器无版本记录时返回空信息,调用方视为无需更新
bool get isEmpty => version.isEmpty;
}
/// 启动时版本更新检查:仅 Android 检查;服务器版本高于本地版本即强制更新
/// (无普通/强制之分)。2026-09-03 起更新走浏览器下载 APK 手动安装。
class UpdateChecker {
final String baseUrl;
final http.Client _client;
UpdateChecker({String? baseUrl, http.Client? client})
: baseUrl = baseUrl ?? AppConfig.apiBaseUrl,
_client = client ?? http.Client();
/// 下载地址:固定静态路径(管理端上传的 APK 覆盖保存为固定文件)
static String downloadUrl({String? baseUrl}) =>
'${baseUrl ?? AppConfig.apiBaseUrl}/download/observer-latest.apk';
/// 拉取服务器最新版本;非 Android 或网络异常时返回空信息,不阻塞启动
Future<AppUpdateInfo> fetch() async {
if (!Platform.isAndroid) {
return const AppUpdateInfo(version: '', notes: '');
}
try {
final res = await _client
.get(Uri.parse('$baseUrl/api/v1/app/update'))
.timeout(const Duration(seconds: 30));
// 服务器 Content-Type 无 charsethttp 包默认按 latin1 解码会乱码 → 显式 utf8
final body =
jsonDecode(utf8.decode(res.bodyBytes)) as Map<String, dynamic>;
final data = body['data'] as Map<String, dynamic>? ?? const {};
return AppUpdateInfo(
version: data['version'] as String? ?? '',
notes: data['notes'] as String? ?? '',
);
} catch (_) {
return const AppUpdateInfo(version: '', notes: '');
}
}
/// 是否需要更新:服务器版本高于已装版本(2026-09-03 起更新改浏览器下载,
/// 安装结果由系统安装器完成,App 无法感知,故不再记录「已确认接受版本」)
static bool needsUpdate(String server, String installed) {
if (server.isEmpty || installed.isEmpty) return false;
return isNewer(server, installed);
}
/// 语义化版本号比较:a > b 返回 true。按数字段比较(1.10.0 > 1.9.9),
/// 任一版本号解析失败时视为相等(不触发更新)。
static bool isNewer(String a, String b) {
final pa = _parse(a);
final pb = _parse(b);
if (pa == null || pb == null) return false;
for (var i = 0; i < 3; i++) {
if (pa[i] != pb[i]) return pa[i] > pb[i];
}
return false;
}
static List<int>? _parse(String v) {
final parts = v.split('.');
if (parts.length != 3) return null;
final nums = <int>[];
for (final p in parts) {
final n = int.tryParse(p);
if (n == null) return null;
nums.add(n);
}
return nums;
}
}