import 'dart:convert'; import 'dart:io'; 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'; import 'package:url_launcher/url_launcher.dart'; /// Détecte une version plus récente (`/version`) et l'installe **in-app** : /// télécharge l'APK dans le stockage de l'app puis lance l'installeur système /// (un seul tap « Installer »). Fallback navigateur si l'install directe échoue. class UpdateService { UpdateService(this._baseUrl); final Future _baseUrl; Future check() async { try { final base = await _baseUrl; final res = await http.get(Uri.parse('$base/version')).timeout(const Duration(seconds: 6)); if (res.statusCode != 200) return null; final data = jsonDecode(res.body) as Map; final remote = data['version_code'] as int? ?? 0; final info = await PackageInfo.fromPlatform(); final current = int.tryParse(info.buildNumber) ?? 0; if (remote > current) { return UpdateInfo( version: data['version'] as String? ?? '?', apkUrl: data['apk_url'] as String? ?? '$base/download/apk', notes: data['notes'] as String? ?? '', ); } } catch (_) {/* pas de réseau / pas d'update → on ignore */} return null; } /// Télécharge l'APK puis lance l'installeur. `onProgress` : 0.0 → 1.0 /// (ou null si la taille est inconnue). Renvoie true si l'installeur s'ouvre. Future apply(UpdateInfo info, {void Function(double?)? onProgress}) async { try { final dir = await getExternalStorageDirectory() ?? await getTemporaryDirectory(); final file = File('${dir.path}/gamemanager-update.apk'); final req = http.Request('GET', Uri.parse(info.apkUrl)); final resp = await req.send().timeout(const Duration(seconds: 30)); if (resp.statusCode != 200) return _fallback(info); final total = resp.contentLength ?? 0; var received = 0; final sink = file.openWrite(); await for (final chunk in resp.stream) { sink.add(chunk); received += chunk.length; onProgress?.call(total > 0 ? received / total : null); } await sink.close(); final result = await OpenFilex.open( file.path, type: 'application/vnd.android.package-archive', ); if (result.type == ResultType.done) return true; return _fallback(info); // l'installeur n'a pas pris → navigateur } catch (_) { return _fallback(info); } } Future _fallback(UpdateInfo info) async { final uri = Uri.parse(info.apkUrl); if (!await canLaunchUrl(uri)) return false; return launchUrl(uri, mode: LaunchMode.externalApplication); } } class UpdateInfo { UpdateInfo({required this.version, required this.apkUrl, required this.notes}); final String version; final String apkUrl; final String notes; }