From add2e1762d5d7fe6c916069b769c385aec2a7a45 Mon Sep 17 00:00:00 2001 From: Hui Yu Neo Date: Tue, 12 May 2026 09:27:35 +0800 Subject: [PATCH] feat: add immediate update installation API --- README-ZH.md | 4 +++ README.md | 4 +++ .../auto_updater/lib/src/auto_updater.dart | 13 ++++---- .../macos/Classes/AutoUpdater.swift | 17 +++++++++++ .../Classes/AutoUpdaterMacosPlugin.swift | 12 +++++++- .../lib/src/auto_updater_method_channel.dart | 13 ++++---- .../src/auto_updater_platform_interface.dart | 5 ++++ .../auto_updater_method_channel_test.dart | 30 +++++++++++++++++++ .../windows/auto_updater.cpp | 5 ++++ .../windows/auto_updater_windows_plugin.cpp | 4 +++ 10 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 packages/auto_updater_platform_interface/test/auto_updater_method_channel_test.dart diff --git a/README-ZH.md b/README-ZH.md index 9747070..c8cd9b7 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -72,6 +72,10 @@ 设置检查时间间隔,默认 86400,最少 3600, 0 不更新 +##### installUpdateNow + +当原生 updater 已准备好下载的更新时,立即安装更新。 + ## 相关链接 diff --git a/README.md b/README.md index 3c37183..cb0b821 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ Asks the server whether there is an update. You must call setFeedURL before usin Sets the auto update check interval, default 86400, minimum 3600, 0 to disable update +##### installUpdateNow + +Installs the downloaded update immediately when the native updater has one ready. + ## Related Links diff --git a/packages/auto_updater/lib/src/auto_updater.dart b/packages/auto_updater/lib/src/auto_updater.dart index 4f4bb2c..e489094 100644 --- a/packages/auto_updater/lib/src/auto_updater.dart +++ b/packages/auto_updater/lib/src/auto_updater.dart @@ -27,9 +27,7 @@ class AutoUpdater { if (event['data'] != null) { data = event['data'] as Map; if (data['error'] != null) { - updaterError = UpdaterError( - data['error'].toString(), - ); + updaterError = UpdaterError(data['error'].toString()); } if (data['appcast'] != null) { appcast = Appcast.fromJson( @@ -87,15 +85,18 @@ class AutoUpdater { /// Asks the server whether there is an update. You must call setFeedURL before using this API. Future checkForUpdates({bool? inBackground}) { - return _platform.checkForUpdates( - inBackground: inBackground, - ); + return _platform.checkForUpdates(inBackground: inBackground); } /// Sets the auto update check interval, default 86400, minimum 3600, 0 to disable update Future setScheduledCheckInterval(int interval) { return _platform.setScheduledCheckInterval(interval); } + + /// Installs the downloaded update immediately when the native updater has one ready. + Future installUpdateNow() { + return _platform.installUpdateNow(); + } } final autoUpdater = AutoUpdater.instance; diff --git a/packages/auto_updater_macos/macos/Classes/AutoUpdater.swift b/packages/auto_updater_macos/macos/Classes/AutoUpdater.swift index 1525b32..63ef83e 100644 --- a/packages/auto_updater_macos/macos/Classes/AutoUpdater.swift +++ b/packages/auto_updater_macos/macos/Classes/AutoUpdater.swift @@ -43,6 +43,7 @@ public class AutoUpdater: NSObject, SPUUpdaterDelegate { var _userDriver: SPUStandardUserDriver? var _updater: SPUUpdater? var feedURL: URL? + var immediateInstallHandler: (() -> Void)? public var onEvent:((String, NSDictionary) -> Void)? override init() { @@ -80,6 +81,21 @@ public class AutoUpdater: NSObject, SPUUpdaterDelegate { public func setScheduledCheckInterval(_ interval: Int) { _updater?.updateCheckInterval = TimeInterval(interval) } + + public func installUpdateImmediately() -> Bool { + guard let immediateInstallHandler = immediateInstallHandler else { + let data: NSDictionary = [ + "error": "No downloaded update is ready to install immediately.", + ] + _emitEvent("error", data) + return false + } + + DispatchQueue.main.async { + immediateInstallHandler() + } + return true + } // SPUUpdaterDelegate @@ -119,6 +135,7 @@ public class AutoUpdater: NSObject, SPUUpdaterDelegate { } public func updater(_ updater: SPUUpdater, willInstallUpdateOnQuit item: SUAppcastItem, immediateInstallationBlock immediateInstallHandler: @escaping () -> Void) -> Bool { + self.immediateInstallHandler = immediateInstallHandler let data: NSDictionary = [ "appcastItem": item.toDictionary() ] diff --git a/packages/auto_updater_macos/macos/Classes/AutoUpdaterMacosPlugin.swift b/packages/auto_updater_macos/macos/Classes/AutoUpdaterMacosPlugin.swift index ddd2870..c61eb52 100644 --- a/packages/auto_updater_macos/macos/Classes/AutoUpdaterMacosPlugin.swift +++ b/packages/auto_updater_macos/macos/Classes/AutoUpdaterMacosPlugin.swift @@ -58,9 +58,19 @@ public class AutoUpdaterMacosPlugin: NSObject, FlutterPlugin,FlutterStreamHandle autoUpdater.setScheduledCheckInterval(interval) result(true) break + case "installUpdateImmediately": + if autoUpdater.installUpdateImmediately() { + result(true) + } else { + result(FlutterError( + code: "UPDATE_NOT_READY", + message: "No downloaded update is ready to install immediately.", + details: nil + )) + } + break default: result(FlutterMethodNotImplemented) } } } - diff --git a/packages/auto_updater_platform_interface/lib/src/auto_updater_method_channel.dart b/packages/auto_updater_platform_interface/lib/src/auto_updater_method_channel.dart index 9af60b9..46d1ede 100644 --- a/packages/auto_updater_platform_interface/lib/src/auto_updater_method_channel.dart +++ b/packages/auto_updater_platform_interface/lib/src/auto_updater_method_channel.dart @@ -23,9 +23,7 @@ class MethodChannelAutoUpdater extends AutoUpdaterPlatform { @override Future setFeedURL(String feedUrl) async { - final Map arguments = { - 'feedURL': feedUrl, - }; + final Map arguments = {'feedURL': feedUrl}; await methodChannel.invokeMethod('setFeedURL', arguments); } @@ -39,9 +37,12 @@ class MethodChannelAutoUpdater extends AutoUpdaterPlatform { @override Future setScheduledCheckInterval(int interval) async { - final Map arguments = { - 'interval': interval, - }; + final Map arguments = {'interval': interval}; await methodChannel.invokeMethod('setScheduledCheckInterval', arguments); } + + @override + Future installUpdateNow() async { + await methodChannel.invokeMethod('installUpdateImmediately'); + } } diff --git a/packages/auto_updater_platform_interface/lib/src/auto_updater_platform_interface.dart b/packages/auto_updater_platform_interface/lib/src/auto_updater_platform_interface.dart index cec1ac6..a54c143 100644 --- a/packages/auto_updater_platform_interface/lib/src/auto_updater_platform_interface.dart +++ b/packages/auto_updater_platform_interface/lib/src/auto_updater_platform_interface.dart @@ -42,4 +42,9 @@ abstract class AutoUpdaterPlatform extends PlatformInterface { 'setScheduledCheckInterval() has not been implemented.', ); } + + /// Installs the downloaded update immediately when the native updater has one ready. + Future installUpdateNow() async { + throw UnimplementedError('installUpdateNow() has not been implemented.'); + } } diff --git a/packages/auto_updater_platform_interface/test/auto_updater_method_channel_test.dart b/packages/auto_updater_platform_interface/test/auto_updater_method_channel_test.dart new file mode 100644 index 0000000..7a4edd1 --- /dev/null +++ b/packages/auto_updater_platform_interface/test/auto_updater_method_channel_test.dart @@ -0,0 +1,30 @@ +import 'package:auto_updater_platform_interface/auto_updater_platform_interface.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('MethodChannelAutoUpdater', () { + test('installUpdateNow invokes native immediate install method', () async { + final updater = MethodChannelAutoUpdater(); + final calls = []; + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(updater.methodChannel, (call) async { + calls.add(call); + return true; + }); + addTearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(updater.methodChannel, null); + }); + + await updater.installUpdateNow(); + + expect(calls, hasLength(1)); + expect(calls.single.method, 'installUpdateImmediately'); + expect(calls.single.arguments, isNull); + }); + }); +} diff --git a/packages/auto_updater_windows/windows/auto_updater.cpp b/packages/auto_updater_windows/windows/auto_updater.cpp index d5ea5f3..39f41d3 100644 --- a/packages/auto_updater_windows/windows/auto_updater.cpp +++ b/packages/auto_updater_windows/windows/auto_updater.cpp @@ -32,6 +32,7 @@ class AutoUpdater { void AutoUpdater::CheckForUpdates(); void AutoUpdater::CheckForUpdatesWithoutUI(); void AutoUpdater::SetScheduledCheckInterval(int interval); + void AutoUpdater::InstallUpdateNow(); void AutoUpdater::RegisterEventSink( std::unique_ptr> ptr); @@ -89,6 +90,10 @@ void AutoUpdater::SetScheduledCheckInterval(int interval) { win_sparkle_set_update_check_interval(interval); } +void AutoUpdater::InstallUpdateNow() { + win_sparkle_check_update_with_ui_and_install(); +} + void AutoUpdater::RegisterEventSink( std::unique_ptr> ptr) { event_sink_ = std::move(ptr); diff --git a/packages/auto_updater_windows/windows/auto_updater_windows_plugin.cpp b/packages/auto_updater_windows/windows/auto_updater_windows_plugin.cpp index 593eec3..b42ea8b 100644 --- a/packages/auto_updater_windows/windows/auto_updater_windows_plugin.cpp +++ b/packages/auto_updater_windows/windows/auto_updater_windows_plugin.cpp @@ -86,6 +86,10 @@ void AutoUpdaterWindowsPlugin::HandleMethodCall( auto_updater.SetScheduledCheckInterval(interval); result->Success(flutter::EncodableValue(true)); + } else if (method_name.compare("installUpdateImmediately") == 0) { + auto_updater.InstallUpdateNow(); + result->Success(flutter::EncodableValue(true)); + } else { result->NotImplemented(); }