From fec6fa166c023859bb192d9a745d2199f137639a Mon Sep 17 00:00:00 2001 From: Umbrix Developer Date: Tue, 20 Jan 2026 17:38:49 +0300 Subject: [PATCH] feat: v1.7.6 - Split Tunneling (Per-App Proxy) for Desktop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flutter integration: - Update SingboxConfigOption with per-app proxy fields - Add perAppProxyMode, includedApplications, excludedApplications - Read per-app settings from SharedPreferences - Pass settings to libcore via HiddifyOptions libcore backend: - Implement ProcessName routing rules for desktop platforms - Support include mode (whitelist) and exclude mode (blacklist) - Only Chrome/Firefox/etc. specified by name use VPN Version bump: 1.7.5 → 1.7.6 Update libcore submodule to include per-app proxy support --- .../data/config_option_repository.dart | 30 +++++++++++++++++++ lib/singbox/model/singbox_config_option.dart | 3 ++ libcore | 2 +- pubspec.yaml | 2 +- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/features/config_option/data/config_option_repository.dart b/lib/features/config_option/data/config_option_repository.dart index 0ab05be3..80d96777 100644 --- a/lib/features/config_option/data/config_option_repository.dart +++ b/lib/features/config_option/data/config_option_repository.dart @@ -334,6 +334,32 @@ abstract class ConfigOptions { "", ); + // Per-App Proxy Settings (Desktop platforms) + static final perAppProxyMode = PreferencesNotifier.create( + "per-app-proxy-mode", + "off", + ); + + static final perAppProxyIncludeList = PreferencesNotifier.create, String>( + "per-app-proxy-include-list", + [], + mapFrom: (value) { + if (value.isEmpty) return []; + return value.split(',').map((e) => e.trim()).where((e) => e.isNotEmpty).toList(); + }, + mapTo: (value) => value.join(','), + ); + + static final perAppProxyExcludeList = PreferencesNotifier.create, String>( + "per-app-proxy-exclude-list", + [], + mapFrom: (value) { + if (value.isEmpty) return []; + return value.split(',').map((e) => e.trim()).where((e) => e.isNotEmpty).toList(); + }, + mapTo: (value) => value.join(','), + ); + static final hasExperimentalFeatures = Provider.autoDispose( (ref) { final mode = ref.watch(serviceMode); @@ -557,6 +583,10 @@ abstract class ConfigOptions { noiseSize: ref.watch(warpNoiseSize), noiseDelay: ref.watch(warpNoiseDelay), ), + // Per-App Proxy + perAppProxyMode: ref.watch(perAppProxyMode), + includedApplications: ref.watch(perAppProxyMode) == 'include' ? ref.watch(perAppProxyIncludeList) : [], + excludedApplications: ref.watch(perAppProxyMode) == 'exclude' ? ref.watch(perAppProxyExcludeList) : [], // geoipPath: ref.watch(geoAssetPathResolverProvider).relativePath( // geoAssets.geoip.providerName, // geoAssets.geoip.fileName, diff --git a/lib/singbox/model/singbox_config_option.dart b/lib/singbox/model/singbox_config_option.dart index 3f7cebe0..cca59424 100644 --- a/lib/singbox/model/singbox_config_option.dart +++ b/lib/singbox/model/singbox_config_option.dart @@ -52,6 +52,9 @@ class SingboxConfigOption with _$SingboxConfigOption { required SingboxTlsTricks tlsTricks, required SingboxWarpOption warp, required SingboxWarpOption warp2, + @JsonKey(name: 'per-app-proxy-mode') @Default('off') String perAppProxyMode, + @JsonKey(name: 'included-applications') @Default([]) List includedApplications, + @JsonKey(name: 'excluded-applications') @Default([]) List excludedApplications, }) = _SingboxConfigOption; String format() { diff --git a/libcore b/libcore index 6dfe63ea..85db0efc 160000 --- a/libcore +++ b/libcore @@ -1 +1 @@ -Subproject commit 6dfe63ea767730442dc30a5856d71c7386e298f5 +Subproject commit 85db0efc59a007f5f78aa13918ff673b64d0ff1b diff --git a/pubspec.yaml b/pubspec.yaml index d976eb4d..74117dca 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: umbrix description: Cross Platform Multi Protocol Proxy Frontend. publish_to: "none" -version: 1.7.5+175 +version: 1.7.6+176 environment: sdk: ">=3.3.0 <4.0.0"