Restart service when settings change

This commit is contained in:
世界
2025-12-07 10:28:51 +08:00
parent bd5e5f3a79
commit 39338ab133
10 changed files with 77 additions and 22 deletions
@@ -243,7 +243,7 @@ import SwiftUI
@ToolbarContentBuilder private var toolbar: some ToolbarContent {
#if os(tvOS)
ToolbarItemGroup(placement: .topBarLeading) {
ToolbarItemGroup(placement: .topBarLeading) {
navigationButtons
}
#endif
@@ -143,7 +143,7 @@ import SwiftUI
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
TVToolbarButton(title: String(localized: "Reset")) {
TVToolbarButton(title: String(localized: "Reset")) {
Task {
await configuration.resetToDefault()
}
@@ -139,7 +139,7 @@ struct ProfilePickerSheet: View {
.environment(\.editMode, $editMode)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
TVToolbarButton(title: editMode.isEditing ? String(localized: "Done"): String(localized: "Edit")) {
TVToolbarButton(title: editMode.isEditing ? String(localized: "Done") : String(localized: "Edit")) {
withAnimation {
if editMode.isEditing {
movingProfileID = nil
@@ -32,17 +32,7 @@ public final class OverviewViewModel: BaseViewModel {
try LibboxNewStandaloneCommandClient()!.setSystemProxyEnabled(enabled)
} else {
await MainActor.run { reasserting = true }
try await profile.stop()
var waitSeconds = 0
while await profile.status != .disconnected {
try await Task.sleep(nanoseconds: NSEC_PER_SEC)
waitSeconds += 1
if waitSeconds >= 5 {
throw NSError(domain: "Restart service timeout", code: 0)
}
}
try await profile.start()
try await profile.restart()
await MainActor.run { reasserting = false }
}
} catch {
@@ -3,7 +3,9 @@ import Library
import SwiftUI
public struct OnDemandRulesView: View {
@EnvironmentObject private var environments: ExtensionEnvironments
@State private var isLoading = true
@State private var alert: AlertState?
@State private var alwaysOn = false
public init() {}
@@ -23,11 +25,13 @@ public struct OnDemandRulesView: View {
This should not be an intended use of the API, so you cannot disable VPN in system settings. To stop the service manually, use the in-app interface or simply delete the VPN profile.
""", $alwaysOn) { newValue in
await SharedPreferences.alwaysOn.set(newValue)
await restartService()
}
FormButton {
Task {
await SharedPreferences.resetOnDemandRules()
await restartService()
isLoading = true
}
} label: {
@@ -38,11 +42,23 @@ public struct OnDemandRulesView: View {
}
}
.navigationTitle("On Demand Rules")
.alert($alert)
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
}
private func restartService() async {
guard let profile = environments.extensionProfile, profile.status.isConnected else {
return
}
do {
try await profile.restart()
} catch {
alert = AlertState(error: error)
}
}
private func loadSettings() async {
alwaysOn = await SharedPreferences.alwaysOn.get()
isLoading = false
@@ -2,7 +2,9 @@ import Library
import SwiftUI
struct PacketTunnelView: View {
@EnvironmentObject private var environments: ExtensionEnvironments
@State private var isLoading = true
@State private var alert: AlertState?
@State private var ignoreMemoryLimit = false
@@ -27,6 +29,7 @@ struct PacketTunnelView: View {
Do not enforce memory limits on sing-box. Will cause OOM on non-jailbroken iOS and tvOS devices.
""", $ignoreMemoryLimit) { newValue in
await SharedPreferences.ignoreMemoryLimit.set(newValue)
await restartService()
}
#if !os(tvOS)
@@ -38,6 +41,7 @@ struct PacketTunnelView: View {
[Apple Documentation](https://developer.apple.com/documentation/networkextension/nevpnprotocol/3131931-includeallnetworks)
""", $includeAllNetworks) { newValue in
await SharedPreferences.includeAllNetworks.set(newValue)
await restartService()
}
FormToggle("excludeAPNs", """
@@ -46,14 +50,16 @@ struct PacketTunnelView: View {
[Apple Documentation](https://developer.apple.com/documentation/networkextension/nevpnprotocol/4140516-excludeapns)
""", $excludeAPNs) { newValue in
await SharedPreferences.excludeAPNs.set(newValue)
await restartService()
}
FormToggle("excludeCellularServices", """
If this property is true, the system excludes cellular services — such as Wi-Fi Calling, MMS, SMS, and Visual Voicemail — but only when the **includeAllNetworks** property is also true. This property doesnt impact services that use the cellular network only — such as VoLTE — which the system automatically excludes.
If this property is true, the system excludes cellular services — such as Wi-Fi Calling, MMS, SMS, and Visual Voicemail — but only when the **includeAllNetworks** property is also true. This property doesn't impact services that use the cellular network only — such as VoLTE — which the system automatically excludes.
[Apple Documentation](https://developer.apple.com/documentation/networkextension/nevpnprotocol/4140517-excludecellularservices)
""", $excludeCellularServices) { newValue in
await SharedPreferences.excludeCellularServices.set(newValue)
await restartService()
}
FormToggle("excludeLocalNetworks", """
@@ -62,6 +68,7 @@ struct PacketTunnelView: View {
[Apple Documentation](https://developer.apple.com/documentation/networkextension/nevpnprotocol/3143658-excludelocalnetworks)
""", $excludeLocalNetworks) { newValue in
await SharedPreferences.excludeLocalNetworks.set(newValue)
await restartService()
}
FormToggle("enforceRoutes", """
@@ -72,6 +79,7 @@ struct PacketTunnelView: View {
[Apple Documentation](https://developer.apple.com/documentation/networkextension/nevpnprotocol/3689459-enforceroutes)
""", $enforceRoutes) { newValue in
await SharedPreferences.enforceRoutes.set(newValue)
await restartService()
}
#endif
@@ -79,6 +87,7 @@ struct PacketTunnelView: View {
FormButton {
Task {
await SharedPreferences.resetPacketTunnel()
await restartService()
isLoading = true
}
} label: {
@@ -89,11 +98,23 @@ struct PacketTunnelView: View {
}
}
.navigationTitle("Packet Tunnel")
.alert($alert)
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
}
private func restartService() async {
guard let profile = environments.extensionProfile, profile.status.isConnected else {
return
}
do {
try await profile.restart()
} catch {
alert = AlertState(error: error)
}
}
private func loadSettings() async {
ignoreMemoryLimit = await SharedPreferences.ignoreMemoryLimit.get()
#if !os(tvOS)
@@ -1,8 +1,11 @@
import Libbox
import Library
import SwiftUI
public struct ProfileOverrideView: View {
@EnvironmentObject private var environments: ExtensionEnvironments
@State private var isLoading = true
@State private var alert: AlertState?
@State private var excludeDefaultRoute = false
@State private var autoRouteUseSubRangesByDefault = false
@State private var excludeAPNsRoute = false
@@ -20,6 +23,7 @@ public struct ProfileOverrideView: View {
FormView {
FormToggle("Hide VPN Icon", "Append `0.0.0.0/31` and `::/127` to `route_exclude_address` if not exists.", $excludeDefaultRoute) { newValue in
await SharedPreferences.excludeDefaultRoute.set(newValue)
await reloadService()
}
FormToggle("No Default Route", """
@@ -27,15 +31,18 @@ public struct ProfileOverrideView: View {
If `<route_address/route_exclude_address>` exists in the configuration, this item will not take effect on the corresponding network (commonly used to resolve HomeKit compatibility issues).
""", $autoRouteUseSubRangesByDefault) { newValue in
await SharedPreferences.autoRouteUseSubRangesByDefault.set(newValue)
await reloadService()
}
FormToggle("Exclude APNs Route", "Append `push.apple.com` to `bypass_domain`, and `17.0.0.0/8` to `route_exclude_address`.", $excludeAPNsRoute) { newValue in
await SharedPreferences.excludeAPNsRoute.set(newValue)
await reloadService()
}
FormButton {
Task {
await SharedPreferences.resetProfileOverride()
await reloadService()
isLoading = true
}
} label: {
@@ -46,11 +53,23 @@ public struct ProfileOverrideView: View {
}
}
.navigationTitle("Profile Override")
.alert($alert)
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
}
private func reloadService() async {
guard let profile = environments.extensionProfile, profile.status.isConnected else {
return
}
do {
try LibboxNewStandaloneCommandClient()?.serviceReload()
} catch {
alert = AlertState(error: error)
}
}
private func loadSettings() async {
excludeDefaultRoute = await SharedPreferences.excludeDefaultRoute.get()
autoRouteUseSubRangesByDefault = await SharedPreferences.autoRouteUseSubRangesByDefault.get()
+2 -6
View File
@@ -38,9 +38,7 @@ struct StartServiceIntent: AppIntent {
}
try LibboxNewStandaloneCommandClient()!.serviceReload()
} else if extensionProfile.status.isConnected {
try await extensionProfile.stop()
try await Task.sleep(nanoseconds: UInt64(100 * Double(NSEC_PER_MSEC)))
try await extensionProfile.start()
try await extensionProfile.restart()
} else {
try await extensionProfile.start()
}
@@ -65,9 +63,7 @@ struct RestartServiceIntent: AppIntent {
if extensionProfile.status == .connected {
try LibboxNewStandaloneCommandClient()!.serviceReload()
} else if extensionProfile.status.isConnected {
try await extensionProfile.stop()
try await Task.sleep(nanoseconds: UInt64(100 * Double(NSEC_PER_MSEC)))
try await extensionProfile.start()
try await extensionProfile.restart()
} else {
try await extensionProfile.start()
}
+13
View File
@@ -108,6 +108,19 @@ public class ExtensionProfile: ObservableObject {
manager.connection.stopVPNTunnel()
}
public func restart() async throws {
try await stop()
var waitSeconds = 0
while await MainActor.run(body: { status }) != .disconnected {
try await Task.sleep(nanoseconds: NSEC_PER_SEC)
waitSeconds += 1
if waitSeconds >= 5 {
throw NSError(domain: "Restart service timeout", code: 0)
}
}
try await start()
}
public static func load() async throws -> ExtensionProfile? {
let managers = try await NETunnelProviderManager.loadAllFromPreferences()
if managers.isEmpty {
+1 -1
View File
@@ -923,7 +923,7 @@
"If this property is true, the system excludes Apple Push Notification services (APNs) traffic, but only when the **includeAllNetworks** property is also true.\n\n[Apple Documentation](https://developer.apple.com/documentation/networkextension/nevpnprotocol/4140516-excludeapns)" : {
"shouldTranslate" : false
},
"If this property is true, the system excludes cellular services — such as Wi-Fi Calling, MMS, SMS, and Visual Voicemail — but only when the **includeAllNetworks** property is also true. This property doesnt impact services that use the cellular network only — such as VoLTE — which the system automatically excludes.\n\n[Apple Documentation](https://developer.apple.com/documentation/networkextension/nevpnprotocol/4140517-excludecellularservices)" : {
"If this property is true, the system excludes cellular services — such as Wi-Fi Calling, MMS, SMS, and Visual Voicemail — but only when the **includeAllNetworks** property is also true. This property doesn't impact services that use the cellular network only — such as VoLTE — which the system automatically excludes.\n\n[Apple Documentation](https://developer.apple.com/documentation/networkextension/nevpnprotocol/4140517-excludecellularservices)" : {
"shouldTranslate" : false
},
"If this property is true, the system excludes network connections to hosts on the local network — such as AirPlay, AirDrop, and CarPlay — but only when the **includeAllNetworks** or **enforceRoutes** property is also true.\n\n[Apple Documentation](https://developer.apple.com/documentation/networkextension/nevpnprotocol/3143658-excludelocalnetworks)" : {