From 2e0db3b90f300926284763dc38e7d7005ceb9432 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 27 Feb 2026 18:30:29 +0800 Subject: [PATCH] Add MinimumAppVersion support for plugins Introduced MinimumAppVersion property to PluginMetadata, enabling plugins to specify required Flow Launcher version. Plugin installation now checks this requirement and prompts users if unsatisfied. Minimum app version logic moved to PluginManager and applied to manifest updates. Added localized strings for user prompts. Refactored SameOrLesserPluginVersionExists to accept PluginMetadata. --- .../ExternalPlugins/PluginsManifest.cs | 28 +---------- Flow.Launcher.Core/Plugin/PluginManager.cs | 50 ++++++++++++++++--- Flow.Launcher.Plugin/PluginMetadata.cs | 5 ++ Flow.Launcher/Languages/en.xaml | 2 + 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs index 4fed10d25..ba332d0a4 100644 --- a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs +++ b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Flow.Launcher.Plugin; -using Flow.Launcher.Infrastructure; +using Flow.Launcher.Core.Plugin; namespace Flow.Launcher.Core.ExternalPlugins { @@ -41,11 +41,10 @@ namespace Flow.Launcher.Core.ExternalPlugins return false; var updatedPluginResults = new List(); - var appVersion = SemanticVersioning.Version.Parse(Constant.Version); for (int i = 0; i < results.Count; i++) { - if (IsMinimumAppVersionSatisfied(results[i], appVersion)) + if (PluginManager.IsMinimumAppVersionSatisfied(results[i].Name, results[i].MinimumAppVersion)) updatedPluginResults.Add(results[i]); } @@ -72,28 +71,5 @@ namespace Flow.Launcher.Core.ExternalPlugins return false; } - - private static bool IsMinimumAppVersionSatisfied(UserPlugin plugin, SemanticVersioning.Version appVersion) - { - if (string.IsNullOrEmpty(plugin.MinimumAppVersion)) - return true; - - try - { - if (appVersion >= SemanticVersioning.Version.Parse(plugin.MinimumAppVersion)) - return true; - } - catch (Exception e) - { - PublicApi.Instance.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. " - + "Plugin excluded from manifest", e); - return false; - } - - PublicApi.Instance.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, " - + $"but current version is {Constant.Version}. Plugin excluded from manifest."); - - return false; - } } } diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index b808e2a7f..5e5706656 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using System.Windows; using Flow.Launcher.Core.ExternalPlugins; using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; @@ -813,15 +814,13 @@ namespace Flow.Launcher.Core.Plugin return string.Empty; } - private static bool SameOrLesserPluginVersionExists(string metadataPath) + private static bool SameOrLesserPluginVersionExists(PluginMetadata metadata) { - var newMetadata = JsonSerializer.Deserialize(File.ReadAllText(metadataPath)); - - if (!Version.TryParse(newMetadata.Version, out var newVersion)) + if (!Version.TryParse(metadata.Version, out var newVersion)) return true; // If version is not valid, we assume it is lesser than any existing version // Get all plugins even if initialization failed so that we can check if the plugin with the same ID exists - return GetAllInitializedPlugins(includeFailed: true).Any(x => x.Metadata.ID == newMetadata.ID + return GetAllInitializedPlugins(includeFailed: true).Any(x => x.Metadata.ID == metadata.ID && Version.TryParse(x.Metadata.Version, out var version) && newVersion <= version); } @@ -897,13 +896,27 @@ namespace Flow.Launcher.Core.Plugin return false; } - if (SameOrLesserPluginVersionExists(metadataJsonFilePath)) + var newMetadata = JsonSerializer.Deserialize(File.ReadAllText(metadataJsonFilePath)); + + if (SameOrLesserPluginVersionExists(newMetadata)) { PublicApi.Instance.ShowMsgError(Localize.failedToInstallPluginTitle(plugin.Name), Localize.pluginExistAlreadyMessage()); return false; } + if (!IsMinimumAppVersionSatisfied(newMetadata.Name, newMetadata.MinimumAppVersion)) + { + // Ask users if they want to install the plugin that doesn't satisfy the minimum app version requirement + if (PublicApi.Instance.ShowMsgBox( + Localize.pluginMinimumAppVersionUnsatisfiedMessage(newMetadata.Name), + Localize.pluginMinimumAppVersionUnsatisfiedTitle(newMetadata.Name, newMetadata.MinimumAppVersion), + MessageBoxButton.YesNo) == MessageBoxResult.No) + { + return false; + } + } + var folderName = string.IsNullOrEmpty(plugin.Version) ? $"{plugin.Name}-{Guid.NewGuid()}" : $"{plugin.Name}-{plugin.Version}"; var defaultPluginIDs = new List @@ -1050,6 +1063,31 @@ namespace Flow.Launcher.Core.Plugin return true; } + internal static bool IsMinimumAppVersionSatisfied(string pluginName, string minimumAppVersion) + { + if (string.IsNullOrEmpty(minimumAppVersion)) + return true; + + var appVersion = Version.Parse(Constant.Version); + + try + { + if (appVersion >= Version.Parse(minimumAppVersion)) + return true; + } + catch (Exception e) + { + PublicApi.Instance.LogException(ClassName, $"Failed to parse the minimum app version {minimumAppVersion} for plugin {pluginName}. " + + "Plugin excluded from manifest", e); + return false; + } + + PublicApi.Instance.LogInfo(ClassName, $"Plugin {pluginName} requires minimum Flow Launcher version {minimumAppVersion}, " + + $"but current version is {Constant.Version}. Plugin excluded from manifest."); + + return false; + } + #endregion #endregion diff --git a/Flow.Launcher.Plugin/PluginMetadata.cs b/Flow.Launcher.Plugin/PluginMetadata.cs index 09803cbd7..253573910 100644 --- a/Flow.Launcher.Plugin/PluginMetadata.cs +++ b/Flow.Launcher.Plugin/PluginMetadata.cs @@ -137,6 +137,11 @@ namespace Flow.Launcher.Plugin [JsonIgnore] public int QueryCount { get; set; } + /// + /// The minimum Flow Launcher version required for this plugin. Default is "". + /// + public string MinimumAppVersion { get; set; } = string.Empty; + /// /// The path to the plugin settings directory which is not validated. /// It is used to store plugin settings files and data files. diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 145e1883d..a271ca484 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -232,6 +232,8 @@ Unable to find plugin.json from the extracted zip file, or this path {0} does not exist A plugin with the same ID and version already exists, or the version is greater than this downloaded plugin Error creating setting panel for plugin {0}:{1}{2} + {0} requires Flow {1}+ version to run + Flow does not meet the minimum version requirements for {0} to run. Do you want to continue installing it? Note that you'd better update Flow to the latest version to ensure that {0} works without issues Plugin Store