fix: deps and auto-update check

This commit is contained in:
2026-07-27 22:15:22 +02:00
parent 77c1747b40
commit 1d687235f4
5 changed files with 107 additions and 158 deletions
+2 -1
View File
@@ -21,12 +21,13 @@ class _KoolTabAppState extends State<KoolTabApp> {
}
Future<void> _checkForUpdates() async {
final updater = AppUpdateUtil(serverUrl: "http://localhost:3000/");
final updater = AppUpdateUtil(serverUrl: "http://localhost:3000");
try {
final update = await updater.checkForUpdate();
if (update == null) {
debugPrint("No update available: ");
return;
}
+35 -111
View File
@@ -2,13 +2,13 @@ import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
// import 'package:open_filex/open_filex.dart';
import 'package:open_filex/open_filex.dart';
// import 'package:package_info_plus/package_info_plus.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
class UpdateInfo {
final bool update;
final String version;
@@ -17,7 +17,6 @@ class UpdateInfo {
final String sha256;
final String download;
UpdateInfo({
required this.update,
required this.version,
@@ -27,7 +26,6 @@ class UpdateInfo {
required this.download,
});
factory UpdateInfo.fromJson(Map<String, dynamic> json) {
return UpdateInfo(
update: json["update"] ?? false,
@@ -40,111 +38,66 @@ class UpdateInfo {
}
}
class AppUpdateUtil {
final String serverUrl;
AppUpdateUtil({
required this.serverUrl,
});
AppUpdateUtil({required this.serverUrl});
/// Gets the installed app version
Future<String> currentVersion() async {
// final info =
// await PackageInfo.fromPlatform();
return "test";
final info = await PackageInfo.fromPlatform();
debugPrint("Current app version: ${info.version}");
return info.version;
}
/// Checks the update server
Future<UpdateInfo?> checkForUpdate() async {
final version =
await currentVersion();
final version = await currentVersion();
final url = Uri.parse("$serverUrl/api/update?version=$version");
final url = Uri.parse(
"$serverUrl/api/update?version=$version",
);
final response =
await http.get(url);
final response = await http.get(url);
if (response.statusCode != 200) {
throw Exception(
"Update server unavailable",
);
throw Exception("Update server unavailable");
}
final data =
jsonDecode(response.body);
final data = jsonDecode(response.body);
if (data["update"] != true) {
return null;
}
return UpdateInfo.fromJson(data);
}
/// Downloads the APK
Future<File> downloadApk(UpdateInfo update, {
Future<File> downloadApk(
UpdateInfo update, {
Function(double progress)? onProgress,
}) async {
final url =
update.download.startsWith("http")
final url = update.download.startsWith("http")
? update.download
: "$serverUrl${update.download}";
final request = http.Request("GET", Uri.parse(url));
final request =
http.Request(
"GET",
Uri.parse(url),
);
final response =
await request.send();
final response = await request.send();
if (response.statusCode != 200) {
throw Exception(
"APK download failed",
);
throw Exception("APK download failed");
}
final total =
response.contentLength ?? 0;
final total = response.contentLength ?? 0;
int received = 0;
final directory = await getTemporaryDirectory();
final directory =
await getTemporaryDirectory();
final file = File("${directory.path}/update.apk");
final file =
File(
"${directory.path}/update.apk",
);
final sink =
file.openWrite();
final sink = file.openWrite();
await for (final chunk in response.stream) {
sink.add(chunk);
@@ -152,9 +105,7 @@ class AppUpdateUtil {
received += chunk.length;
if (total > 0 && onProgress != null) {
onProgress(
received / total,
);
onProgress(received / total);
}
}
@@ -163,25 +114,17 @@ class AppUpdateUtil {
return file;
}
/// Verifies APK checksum
Future<bool> verifySha256(File file,
String expectedHash,) async {
final bytes =
await file.readAsBytes();
Future<bool> verifySha256(File file, String expectedHash) async {
final bytes = await file.readAsBytes();
final digest =
sha256.convert(bytes);
final digest = sha256.convert(bytes);
return digest.toString()
.toLowerCase()
==
expectedHash.toLowerCase();
return digest.toString().toLowerCase() == expectedHash.toLowerCase();
}
/// Opens Android APK installer
Future<void> installApk(File file,) async {
Future<void> installApk(File file) async {
// final result =
// await OpenFilex.open(
// file.path,
@@ -195,48 +138,29 @@ class AppUpdateUtil {
// }
}
/// Full update flow
///
/// Returns:
/// - null if no update exists
/// - UpdateInfo if update is available
///
Future<UpdateInfo?> update({
Function(double progress)? onProgress,
}) async {
final info =
await checkForUpdate();
Future<UpdateInfo?> update({Function(double progress)? onProgress}) async {
final info = await checkForUpdate();
if (info == null) {
return null;
}
final apk =
await downloadApk(
info,
onProgress: onProgress,
);
final apk = await downloadApk(info, onProgress: onProgress);
final valid =
await verifySha256(
apk,
info.sha256,
);
final valid = await verifySha256(apk, info.sha256);
if (!valid) {
throw Exception(
"APK checksum mismatch",
);
throw Exception("APK checksum mismatch");
}
await installApk(
apk,
);
await installApk(apk);
return info;
}
}
}
+13 -13
View File
@@ -57,19 +57,19 @@ class ProductListViewModel extends ChangeNotifier {
notifyListeners();
}
try {
_products = await productService.getProducts();
debugPrint(
_products.map((p) => '${p.name}: ${p.stockQuantity}').join('\n'),
);
} catch (_) {
_errorMessage = 'Could not load products.';
} finally {
_hasLoaded = true;
_isLoading = false;
notifyListeners();
}
// try {
// _products = await productService.getProducts();
//
// debugPrint(
// _products.map((p) => '${p.name}: ${p.stockQuantity}').join('\n'),
// );
// } catch (_) {
// _errorMessage = 'Could not load products.';
// } finally {
// _hasLoaded = true;
// _isLoading = false;
// notifyListeners();
// }
}
Future<void> addProduct({