Files
世界 efa6088884 Fix widget toggle not disabling On Demand before stopping VPN
Store wasOnDemandEnabled flag in providerConfiguration so the widget
can restore On Demand state on next start. Clear the flag when On
Demand is explicitly disabled in settings or when starting from the
main app.
2026-03-09 13:20:53 +08:00

90 lines
3.0 KiB
Swift

import Foundation
import NetworkExtension
enum WidgetAppConfiguration {
static let packageName: String = {
guard let value = Bundle.main.object(forInfoDictionaryKey: "BasePackageIdentifier") as? String else {
fatalError("Missing BasePackageIdentifier in Info.plist")
}
return value
}()
static let appGroupID: String = {
guard let value = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String else {
fatalError("Missing AppGroupIdentifier in Info.plist")
}
return value
}()
static var widgetControlKind: String {
"\(packageName).widget.ServiceToggle"
}
}
extension NEVPNStatus {
var isStarted: Bool {
switch self {
case .connecting, .connected, .reasserting:
return true
default:
return false
}
}
}
enum WidgetTunnelControl {
static func currentIsStarted() async throws -> Bool {
guard let manager = try await loadManager() else {
return false
}
return manager.connection.status.isStarted
}
static func setStarted(_ started: Bool) async throws {
guard let manager = try await loadManager() else {
NSLog("[WidgetTunnelControl] No tunnel configuration found")
throw NSError(domain: "WidgetTunnelControl", code: 1, userInfo: [
NSLocalizedDescriptionKey: "Tunnel configuration not found",
])
}
if started {
if manager.isEnabled == false {
manager.isEnabled = true
}
if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol,
let config = proto.providerConfiguration,
config["wasOnDemandEnabled"] as? Bool == true
{
var newConfig = config
newConfig.removeValue(forKey: "wasOnDemandEnabled")
proto.providerConfiguration = newConfig
manager.isOnDemandEnabled = true
}
try await manager.saveToPreferences()
do {
try manager.connection.startVPNTunnel()
} catch {
NSLog("[WidgetTunnelControl] startVPNTunnel failed: \(error.localizedDescription)")
throw error
}
} else {
if manager.isOnDemandEnabled {
if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol {
var config = proto.providerConfiguration ?? [:]
config["wasOnDemandEnabled"] = true
proto.providerConfiguration = config
}
manager.isOnDemandEnabled = false
try await manager.saveToPreferences()
}
manager.connection.stopVPNTunnel()
}
}
private static func loadManager() async throws -> NETunnelProviderManager? {
let managers = try await NETunnelProviderManager.loadAllFromPreferences()
return managers.first
}
}