188 lines
4.6 KiB
Dart
188 lines
4.6 KiB
Dart
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:package_info_plus/package_info_plus.dart';
|
|
import 'package:path_provider/path_provider.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<String, dynamic> 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<String> currentVersion() async {
|
|
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 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<File> 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<bool> 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<void> 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<UpdateInfo?> 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;
|
|
// }
|
|
}
|