import 'dart:convert'; import 'package:flutter/cupertino.dart'; import 'package:http/http.dart' as http; import 'package:package_info_plus/package_info_plus.dart'; class UpdateInfo { final bool update; final String version; final String notes; final bool mandatory; final String sha256; final String download; UpdateInfo({ required this.update, required this.version, required this.notes, required this.mandatory, required this.sha256, required this.download, }); factory UpdateInfo.fromJson(Map json) { return UpdateInfo( update: json["update"] ?? false, version: json["version"] ?? "", notes: json["notes"] ?? "", mandatory: json["mandatory"] ?? false, sha256: json["sha256"] ?? "", download: json["download"] ?? "", ); } @override bool operator ==(Object other) => identical(this, other) || other is UpdateInfo && update == other.update && version == other.version && notes == other.notes && mandatory == other.mandatory && sha256 == other.sha256 && download == other.download; @override int get hashCode => Object.hash(update, version, notes, mandatory, sha256, download); } class AppUpdateUtil { final String serverUrl; AppUpdateUtil({required this.serverUrl}); /// Gets the installed app version Future currentVersion() async { final info = await PackageInfo.fromPlatform(); debugPrint("Current app version: ${info.version}"); return info.version; } /// Checks the update server Future checkForUpdate() async { final version = await currentVersion(); final url = Uri.parse("$serverUrl/api/update?version=$version"); final response = await http.get(url); debugPrint("Response from update server: ${response.body}"); if (response.statusCode != 200) { throw Exception("Update server unavailable"); } final data = jsonDecode(response.body); if (data["update"] != true) { return null; } return UpdateInfo.fromJson(data); } // /// Downloads the APK // Future downloadApk( // UpdateInfo update, { // // Function(double progress)? onProgress, // }) async { // final url = update.download.startsWith("http") // ? update.download // : "$serverUrl${update.download}"; // // final request = http.Request("GET", Uri.parse(url)); // // final response = await request.send(); // // if (response.statusCode != 200) { // throw Exception("APK download failed"); // } // // final total = response.contentLength ?? 0; // // int received = 0; // // final directory = await getTemporaryDirectory(); // // final file = File("${directory.path}/update.apk"); // // final sink = file.openWrite(); // // await for (final chunk in response.stream) { // sink.add(chunk); // // received += chunk.length; // // if (total > 0 && onProgress != null) { // onProgress(received / total); // } // } // // await sink.close(); // // return file; // } // // /// Verifies APK checksum // Future verifySha256(File file, String expectedHash) async { // final bytes = await file.readAsBytes(); // // final digest = sha256.convert(bytes); // // return digest.toString().toLowerCase() == expectedHash.toLowerCase(); // } // // /// Opens Android APK installer // Future installApk(File file) async { // final result = // await OpenFilex.open( // file.path, // ); // // if(result.type == ResultType.done) { // debugPrint("APK installer opened successfully"); // } // // // if (result.type != ResultType.done) { // throw Exception( // "Could not open APK installer", // ); // } // } // // /// Full update flow // /// // /// Returns: // /// - null if no update exists // /// - UpdateInfo if update is available // /// // Future update({Function(double progress)? onProgress}) async { // final info = await checkForUpdate(); // // if (info == null) { // return null; // } // // final apk = await downloadApk(info, onProgress: onProgress); // // final valid = await verifySha256(apk, info.sha256); // // if (!valid) { // throw Exception("APK checksum mismatch"); // } // // await installApk(apk); // // return info; // } }