From 20c693004a9e09b0daa30fc0b636a327cbff9031 Mon Sep 17 00:00:00 2001 From: Gergely Hegedus Date: Fri, 17 Jan 2025 21:54:22 +0200 Subject: [PATCH] Make manual shorebird update actually work Restarting just the activity doesn't seem to work. To work around this, I finished the process and started the activity via alarm manager. This is inspired from ProcessPhoenix --- android/app/src/main/AndroidManifest.xml | 7 ++ .../experiment_shorebird/MainActivity.kt | 52 +++++++++++- .../flutter/experiment_shorebird/Methods.kt | 7 ++ lib/main.dart | 83 +++++++++++++------ pubspec.yaml | 2 +- 5 files changed, 123 insertions(+), 28 deletions(-) create mode 100644 android/app/src/main/kotlin/org/fnives/flutter/experiment_shorebird/Methods.kt diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4e84368..d448357 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -17,6 +17,13 @@ the Android process has started. This theme is visible to the user while the Flutter UI initializes. After that, this theme continues to determine the Window background behind the Flutter UI. --> + + + + + + + + when (call.method) { + Methods.RESTART.methodName -> { + val pendingIntent = PendingIntent.getActivity( + context, + 4201, + if (isHomeApp()) Intent(intent.action).apply { + flags = Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + intent.categories.forEach { + addCategory(it) + } + } else Intent(this, this::class.java).apply { + flags = Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + }, + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + val alarmManager = context.getSystemService(ALARM_SERVICE) as AlarmManager + alarmManager[AlarmManager.RTC, System.currentTimeMillis() + 100] = + pendingIntent + if (context is Activity) { + (context as Activity).finishAndRemoveTask() + } + Runtime.getRuntime().exit(0) + result.success(Unit) + } + } + } + } + + private fun isHomeApp(): Boolean { + val intent = Intent(Intent.ACTION_MAIN) + intent.addCategory(Intent.CATEGORY_HOME) + val res = packageManager.resolveActivity(intent, 0) + return res?.activityInfo != null && (packageName == res.activityInfo.packageName) + } +} diff --git a/android/app/src/main/kotlin/org/fnives/flutter/experiment_shorebird/Methods.kt b/android/app/src/main/kotlin/org/fnives/flutter/experiment_shorebird/Methods.kt new file mode 100644 index 0000000..7f934ff --- /dev/null +++ b/android/app/src/main/kotlin/org/fnives/flutter/experiment_shorebird/Methods.kt @@ -0,0 +1,7 @@ +package org.fnives.flutter.experiment_shorebird + +enum class Methods(val methodName: String) { + RESTART("restart"); + + +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 70ff854..2fbbeef 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,15 +1,16 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:shorebird_code_push/shorebird_code_push.dart'; -import 'package:restart_app/restart_app.dart'; - void main() { runApp(const MyApp()); } class ShorebirdPatch extends StatefulWidget { + const ShorebirdPatch({super.key}); + @override State createState() => _ShorebirdPatchState(); } @@ -20,39 +21,65 @@ enum PatchState { updateReady; } +enum MainChannelMethods { + restart(methodName: "restart"); + + final String methodName; + + const MainChannelMethods({required this.methodName}); +} + class _ShorebirdPatchState extends State { final shorebird = ShorebirdCodePush(); late Timer timer; PatchState patchState = PatchState.noUpdate; + final methodChannel = const MethodChannel("MainChannel"); @override void initState() { - timer = Timer.periodic(const Duration(minutes: 5), (timer) async { - if (!shorebird.isShorebirdAvailable()) { - timer.cancel(); - return; - } - if (!await shorebird.isNewPatchAvailableForDownload()) { - setState(() { - patchState = PatchState.noUpdate; - }); - return; - } - final download = shorebird.downloadUpdateIfAvailable(); - setState(() { - patchState = PatchState.loading; - }); - await download; - if (await shorebird.isNewPatchReadyToInstall()) { - setState(() { - patchState = PatchState.updateReady; - }); - return; - } + timer = Timer.periodic(const Duration(minutes: 1), (timer) async { + checkForPatch(timer); }); + checkForPatch(timer); super.initState(); } + Future checkForPatch(Timer timer) async { + print('timer activated'); + if (await shorebird.isNewPatchReadyToInstall()) { + print('timer await shorebird.isNewPatchReadyToInstall()'); + setState(() { + patchState = PatchState.updateReady; + }); + return; + } + if (!shorebird.isShorebirdAvailable()) { + print('timer !shorebird.isShorebirdAvailable()'); + timer.cancel(); + return; + } + if (!await shorebird.isNewPatchAvailableForDownload()) { + print('timer !await shorebird.isNewPatchAvailableForDownload()'); + setState(() { + patchState = PatchState.noUpdate; + }); + return; + } + final download = shorebird.downloadUpdateIfAvailable(); + setState(() { + patchState = PatchState.loading; + }); + await download; + if (await shorebird.isNewPatchReadyToInstall()) { + print('timer await shorebird.isNewPatchReadyToInstall()'); + setState(() { + patchState = PatchState.updateReady; + }); + return; + } + print('timer end'); + } + @override void dispose() { timer.cancel(); @@ -70,7 +97,7 @@ class _ShorebirdPatchState extends State { return InkWell( child: const SizedBox.square(dimension: 48, child: Icon(Icons.update, size: 24)), onTap: () { - Restart.restartApp(); + methodChannel.invokeMethod(MainChannelMethods.restart.methodName); }, ); } @@ -117,12 +144,16 @@ class _MyHomePageState extends State { appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title), - actions: [ShorebirdPatch()], + actions: const [ShorebirdPatch()], ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ + const Text( + 'This is a release 1.9.1', + // 'You have times:', + ), const Text( 'You have pushed the button this many times:', // 'You have times:', diff --git a/pubspec.yaml b/pubspec.yaml index 96810d2..153908d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.1+1 +version: 1.9.1+191 environment: sdk: '>=3.4.3 <4.0.0'