import 'package:dio/dio.dart'; import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; /// Bridges to MainActivity.kt's MethodChannel for the Android /// PackageInstaller intent (#397). Web / iOS don't support self- /// install; this class is Android-only at v1. class UpdateInstaller { UpdateInstaller(this._dio); final Dio _dio; static const _channel = MethodChannel('com.fabledsword.minstrel/installer'); static const _filename = 'minstrel-update.apk'; /// Streams the APK from `apkUrl` into the cache directory. `onProgress` /// receives 0..1 fractions; emits 1.0 once when the download completes. /// Returns the local path the install intent will read from. Future download( String apkUrl, { void Function(double progress)? onProgress, }) async { final cacheDir = await getApplicationCacheDirectory(); final path = '${cacheDir.path}/$_filename'; await _dio.download( apkUrl, path, onReceiveProgress: (received, total) { if (total > 0 && onProgress != null) { onProgress(received / total); } }, ); return path; } /// Hands the downloaded APK to Android's PackageInstaller via a /// FileProvider content:// URI. The system shows the install confirm /// dialog; user must tap Install. App restarts on the new version. /// /// First-ever install attempt prompts the user to flip "Install /// unknown apps" for Minstrel in Settings → Apps → Special access. /// One-time grant; persists across updates. Future install(String apkPath) async { await _channel.invokeMethod('install', {'path': apkPath}); } }