fix: deps and auto-update check
This commit is contained in:
+2
-1
@@ -21,12 +21,13 @@ class _KoolTabAppState extends State<KoolTabApp> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _checkForUpdates() async {
|
Future<void> _checkForUpdates() async {
|
||||||
final updater = AppUpdateUtil(serverUrl: "http://localhost:3000/");
|
final updater = AppUpdateUtil(serverUrl: "http://localhost:3000");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final update = await updater.checkForUpdate();
|
final update = await updater.checkForUpdate();
|
||||||
|
|
||||||
if (update == null) {
|
if (update == null) {
|
||||||
|
debugPrint("No update available: ");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
-111
@@ -2,13 +2,13 @@ import 'dart:convert';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:http/http.dart' as http;
|
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';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
|
||||||
class UpdateInfo {
|
class UpdateInfo {
|
||||||
final bool update;
|
final bool update;
|
||||||
final String version;
|
final String version;
|
||||||
@@ -17,7 +17,6 @@ class UpdateInfo {
|
|||||||
final String sha256;
|
final String sha256;
|
||||||
final String download;
|
final String download;
|
||||||
|
|
||||||
|
|
||||||
UpdateInfo({
|
UpdateInfo({
|
||||||
required this.update,
|
required this.update,
|
||||||
required this.version,
|
required this.version,
|
||||||
@@ -27,7 +26,6 @@ class UpdateInfo {
|
|||||||
required this.download,
|
required this.download,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
factory UpdateInfo.fromJson(Map<String, dynamic> json) {
|
factory UpdateInfo.fromJson(Map<String, dynamic> json) {
|
||||||
return UpdateInfo(
|
return UpdateInfo(
|
||||||
update: json["update"] ?? false,
|
update: json["update"] ?? false,
|
||||||
@@ -40,111 +38,66 @@ class UpdateInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AppUpdateUtil {
|
class AppUpdateUtil {
|
||||||
|
|
||||||
|
|
||||||
final String serverUrl;
|
final String serverUrl;
|
||||||
|
|
||||||
|
AppUpdateUtil({required this.serverUrl});
|
||||||
AppUpdateUtil({
|
|
||||||
required this.serverUrl,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/// Gets the installed app version
|
/// Gets the installed app version
|
||||||
Future<String> currentVersion() async {
|
Future<String> currentVersion() async {
|
||||||
// final info =
|
final info = await PackageInfo.fromPlatform();
|
||||||
// await PackageInfo.fromPlatform();
|
debugPrint("Current app version: ${info.version}");
|
||||||
|
return info.version;
|
||||||
return "test";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Checks the update server
|
/// Checks the update server
|
||||||
Future<UpdateInfo?> checkForUpdate() async {
|
Future<UpdateInfo?> checkForUpdate() async {
|
||||||
final version =
|
final version = await currentVersion();
|
||||||
await currentVersion();
|
|
||||||
|
|
||||||
|
final url = Uri.parse("$serverUrl/api/update?version=$version");
|
||||||
|
|
||||||
final url = Uri.parse(
|
final response = await http.get(url);
|
||||||
"$serverUrl/api/update?version=$version",
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
final response =
|
|
||||||
await http.get(url);
|
|
||||||
|
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
throw Exception(
|
throw Exception("Update server unavailable");
|
||||||
"Update server unavailable",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
final data =
|
|
||||||
jsonDecode(response.body);
|
|
||||||
|
|
||||||
|
|
||||||
if (data["update"] != true) {
|
if (data["update"] != true) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return UpdateInfo.fromJson(data);
|
return UpdateInfo.fromJson(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Downloads the APK
|
/// Downloads the APK
|
||||||
Future<File> downloadApk(UpdateInfo update, {
|
Future<File> downloadApk(
|
||||||
|
UpdateInfo update, {
|
||||||
|
|
||||||
Function(double progress)? onProgress,
|
Function(double progress)? onProgress,
|
||||||
|
|
||||||
}) async {
|
}) async {
|
||||||
final url =
|
final url = update.download.startsWith("http")
|
||||||
update.download.startsWith("http")
|
|
||||||
? update.download
|
? update.download
|
||||||
: "$serverUrl${update.download}";
|
: "$serverUrl${update.download}";
|
||||||
|
|
||||||
|
final request = http.Request("GET", Uri.parse(url));
|
||||||
|
|
||||||
final request =
|
final response = await request.send();
|
||||||
http.Request(
|
|
||||||
"GET",
|
|
||||||
Uri.parse(url),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
final response =
|
|
||||||
await request.send();
|
|
||||||
|
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
throw Exception(
|
throw Exception("APK download failed");
|
||||||
"APK download failed",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final total = response.contentLength ?? 0;
|
||||||
final total =
|
|
||||||
response.contentLength ?? 0;
|
|
||||||
|
|
||||||
|
|
||||||
int received = 0;
|
int received = 0;
|
||||||
|
|
||||||
|
final directory = await getTemporaryDirectory();
|
||||||
|
|
||||||
final directory =
|
final file = File("${directory.path}/update.apk");
|
||||||
await getTemporaryDirectory();
|
|
||||||
|
|
||||||
|
final sink = file.openWrite();
|
||||||
final file =
|
|
||||||
File(
|
|
||||||
"${directory.path}/update.apk",
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
final sink =
|
|
||||||
file.openWrite();
|
|
||||||
|
|
||||||
await for (final chunk in response.stream) {
|
await for (final chunk in response.stream) {
|
||||||
sink.add(chunk);
|
sink.add(chunk);
|
||||||
@@ -152,9 +105,7 @@ class AppUpdateUtil {
|
|||||||
received += chunk.length;
|
received += chunk.length;
|
||||||
|
|
||||||
if (total > 0 && onProgress != null) {
|
if (total > 0 && onProgress != null) {
|
||||||
onProgress(
|
onProgress(received / total);
|
||||||
received / total,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,25 +114,17 @@ class AppUpdateUtil {
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Verifies APK checksum
|
/// Verifies APK checksum
|
||||||
Future<bool> verifySha256(File file,
|
Future<bool> verifySha256(File file, String expectedHash) async {
|
||||||
String expectedHash,) async {
|
final bytes = await file.readAsBytes();
|
||||||
final bytes =
|
|
||||||
await file.readAsBytes();
|
|
||||||
|
|
||||||
final digest =
|
final digest = sha256.convert(bytes);
|
||||||
sha256.convert(bytes);
|
|
||||||
|
|
||||||
return digest.toString()
|
return digest.toString().toLowerCase() == expectedHash.toLowerCase();
|
||||||
.toLowerCase()
|
|
||||||
==
|
|
||||||
expectedHash.toLowerCase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Opens Android APK installer
|
/// Opens Android APK installer
|
||||||
Future<void> installApk(File file,) async {
|
Future<void> installApk(File file) async {
|
||||||
// final result =
|
// final result =
|
||||||
// await OpenFilex.open(
|
// await OpenFilex.open(
|
||||||
// file.path,
|
// file.path,
|
||||||
@@ -195,48 +138,29 @@ class AppUpdateUtil {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Full update flow
|
/// Full update flow
|
||||||
///
|
///
|
||||||
/// Returns:
|
/// Returns:
|
||||||
/// - null if no update exists
|
/// - null if no update exists
|
||||||
/// - UpdateInfo if update is available
|
/// - UpdateInfo if update is available
|
||||||
///
|
///
|
||||||
Future<UpdateInfo?> update({
|
Future<UpdateInfo?> update({Function(double progress)? onProgress}) async {
|
||||||
|
final info = await checkForUpdate();
|
||||||
Function(double progress)? onProgress,
|
|
||||||
|
|
||||||
}) async {
|
|
||||||
final info =
|
|
||||||
await checkForUpdate();
|
|
||||||
|
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final apk =
|
final apk = await downloadApk(info, onProgress: onProgress);
|
||||||
await downloadApk(
|
|
||||||
info,
|
|
||||||
onProgress: onProgress,
|
|
||||||
);
|
|
||||||
|
|
||||||
final valid =
|
final valid = await verifySha256(apk, info.sha256);
|
||||||
await verifySha256(
|
|
||||||
apk,
|
|
||||||
info.sha256,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw Exception(
|
throw Exception("APK checksum mismatch");
|
||||||
"APK checksum mismatch",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await installApk(
|
await installApk(apk);
|
||||||
apk,
|
|
||||||
);
|
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -57,19 +57,19 @@ class ProductListViewModel extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
// try {
|
||||||
_products = await productService.getProducts();
|
// _products = await productService.getProducts();
|
||||||
|
//
|
||||||
debugPrint(
|
// debugPrint(
|
||||||
_products.map((p) => '${p.name}: ${p.stockQuantity}').join('\n'),
|
// _products.map((p) => '${p.name}: ${p.stockQuantity}').join('\n'),
|
||||||
);
|
// );
|
||||||
} catch (_) {
|
// } catch (_) {
|
||||||
_errorMessage = 'Could not load products.';
|
// _errorMessage = 'Could not load products.';
|
||||||
} finally {
|
// } finally {
|
||||||
_hasLoaded = true;
|
// _hasLoaded = true;
|
||||||
_isLoading = false;
|
// _isLoading = false;
|
||||||
notifyListeners();
|
// notifyListeners();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addProduct({
|
Future<void> addProduct({
|
||||||
|
|||||||
+53
-29
@@ -225,6 +225,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.0"
|
||||||
|
ffi_leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffi_leak_tracker
|
||||||
|
sha256: "4093d4ef9ca06ffe2786e73bfb25e22aa92112b9bb4ec941f11e3e6b61489a97"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.2"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -298,50 +306,50 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage
|
name: flutter_secure_storage
|
||||||
sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea"
|
sha256: "7686b1d6a29985dcbb808c59518226e603e3bfa7c0ddfd1a0d00e4cda77c868e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.2.4"
|
version: "10.3.1"
|
||||||
|
flutter_secure_storage_darwin:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_secure_storage_darwin
|
||||||
|
sha256: "82329fa5cdf343773b1b6897dea959105a29f092454259edff92f9f6637e8149"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.2"
|
||||||
flutter_secure_storage_linux:
|
flutter_secure_storage_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage_linux
|
name: flutter_secure_storage_linux
|
||||||
sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688
|
sha256: a5f35ddab43cf5c8215d2feb4ce1957851f28c5c37e6f04335066a0602087bf5
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.3"
|
version: "3.0.1"
|
||||||
flutter_secure_storage_macos:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_secure_storage_macos
|
|
||||||
sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.3"
|
|
||||||
flutter_secure_storage_platform_interface:
|
flutter_secure_storage_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage_platform_interface
|
name: flutter_secure_storage_platform_interface
|
||||||
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
|
sha256: "06686df417f34fe9f963ed217b7fdce250e2f637ddd6c374d7eb054549770633"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "2.0.2"
|
||||||
flutter_secure_storage_web:
|
flutter_secure_storage_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage_web
|
name: flutter_secure_storage_web
|
||||||
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
|
sha256: "073a62b3aeb866ab4ce795f960413948e51e5a42a9b0c8333b6daf5bb3208a1c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "2.1.1"
|
||||||
flutter_secure_storage_windows:
|
flutter_secure_storage_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage_windows
|
name: flutter_secure_storage_windows
|
||||||
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
|
sha256: "471951813a97006d899db4948acc654a4f28c440083ea08178935ce20b173ec1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "4.2.2"
|
||||||
flutter_slidable:
|
flutter_slidable:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -393,7 +401,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.2"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
||||||
@@ -512,14 +520,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
js:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: js
|
|
||||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.6.7"
|
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -624,6 +624,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.4.1"
|
version: "9.4.1"
|
||||||
|
open_filex:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: open_filex
|
||||||
|
sha256: "9976da61b6a72302cf3b1efbce259200cd40232643a467aac7370addf94d6900"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.7.0"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -632,6 +640,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.0"
|
||||||
|
package_info_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: package_info_plus
|
||||||
|
sha256: "127e1751e37ffb2ff4658beeaca77bad0c27bf5f932bd3a501c2296926d4b481"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.2.1"
|
||||||
|
package_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus_platform_interface
|
||||||
|
sha256: db762cb2f4f25ee60fb6359773861b0f199e00b90d237bd85a76a1e806b46ef4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
path:
|
path:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -937,10 +961,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e
|
sha256: ba6f4bba816c8d7e3c1580e170f3786d216951cc6b94babc3b814c08d2cb2738
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.15.0"
|
version: "6.3.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
+4
-4
@@ -44,11 +44,11 @@ dependencies:
|
|||||||
path: ^1.9.1
|
path: ^1.9.1
|
||||||
flutter_slidable: ^4.0.3
|
flutter_slidable: ^4.0.3
|
||||||
intl: ^0.20.3
|
intl: ^0.20.3
|
||||||
flutter_secure_storage: ^9.0.0
|
flutter_secure_storage: 10.3.1
|
||||||
crypto: ^3.0.0
|
crypto: ^3.0.0
|
||||||
# http: ^1.6.0
|
http: ^1.6.0
|
||||||
# package_info_plus: ^10.2.1
|
package_info_plus: ^10.1.0
|
||||||
# open_filex: ^4.7.0
|
open_filex: ^4.7.0
|
||||||
# permission_handler: ^12.0.3
|
# permission_handler: ^12.0.3
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user