From 6a2b7274deba8c50b7128f809aff00bae11de292 Mon Sep 17 00:00:00 2001 From: yicheng <11733500+yichengchen@users.noreply.github.com> Date: Sat, 14 Oct 2023 19:33:05 +0800 Subject: [PATCH 1/7] fix: should request location permission on macOS14 --- ClashX.xcodeproj/project.pbxproj | 4 + ClashX/Basic/Logger.swift | 4 +- ClashX/General/Utils/Command.swift | 34 ++++++ .../General/Utils/NetworkChangeNotifier.swift | 4 - ClashX/General/Utils/SSIDSuspendTool.swift | 112 ++++++++++++++++-- ClashX/Info.plist | 4 + .../en.lproj/Localizable.strings | 3 + .../zh-Hans.lproj/Localizable.strings | 3 + .../zh-Hant.lproj/Localizable.strings | 3 + .../GeneralSettingViewController.swift | 3 + Gemfile | 2 +- Gemfile.lock | 68 +++++------ 12 files changed, 190 insertions(+), 54 deletions(-) create mode 100644 ClashX/General/Utils/Command.swift diff --git a/ClashX.xcodeproj/project.pbxproj b/ClashX.xcodeproj/project.pbxproj index 1212e630e..c116f1b05 100644 --- a/ClashX.xcodeproj/project.pbxproj +++ b/ClashX.xcodeproj/project.pbxproj @@ -100,6 +100,7 @@ 49D767742A6195C800830333 /* ConnectionsReq.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D767732A6195C800830333 /* ConnectionsReq.swift */; }; 49D767762A6195E600830333 /* StructedLogReq.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D767752A6195E600830333 /* StructedLogReq.swift */; }; 49D84AD32A56E9760074CCDB /* ConnectionStatusIconCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D84AD22A56E9760074CCDB /* ConnectionStatusIconCellView.swift */; }; + 49FEC6692AD9369C00BAD9F5 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FEC6682AD9369C00BAD9F5 /* Command.swift */; }; 8A2BBEA727A03ACB0081EBEF /* ProxySetting.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 8A2BBEA627A03ACB0081EBEF /* ProxySetting.sdef */; }; 8ACD21BB27A04C7800BC4632 /* ProxySettingCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ACD21BA27A04C7800BC4632 /* ProxySettingCommand.swift */; }; 8ACD21BD27A04ED500BC4632 /* ProxyModeChangeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ACD21BC27A04ED500BC4632 /* ProxyModeChangeCommand.swift */; }; @@ -269,6 +270,7 @@ 49D8276627E9B01700159D93 /* LoginKitWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoginKitWrapper.h; sourceTree = ""; }; 49D8276727E9B01700159D93 /* LoginKitWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoginKitWrapper.m; sourceTree = ""; }; 49D84AD22A56E9760074CCDB /* ConnectionStatusIconCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionStatusIconCellView.swift; sourceTree = ""; }; + 49FEC6682AD9369C00BAD9F5 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; 5217C006C5A22A1CEA24BFC1 /* Pods-ClashX.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClashX.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ClashX/Pods-ClashX.debug.xcconfig"; sourceTree = ""; }; 8A2BBEA627A03ACB0081EBEF /* ProxySetting.sdef */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = ProxySetting.sdef; sourceTree = ""; }; 8ACD21BA27A04C7800BC4632 /* ProxySettingCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxySettingCommand.swift; sourceTree = ""; }; @@ -361,6 +363,7 @@ 49D176A62355FE680093DD7B /* NetworkChangeNotifier.swift */, 49B445152457CDF000B27E3E /* ClashStatusTool.swift */, 49D223382A1DA5F10002FFCB /* SSIDSuspendTool.swift */, + 49FEC6682AD9369C00BAD9F5 /* Command.swift */, ); path = Utils; sourceTree = ""; @@ -962,6 +965,7 @@ 49722FF0211F338B00650A41 /* EventStream.swift in Sources */, 499A486522EEA3FD00F6C675 /* Array+Safe.swift in Sources */, F92D0B24236BC12000575E15 /* SavedProxyModel.swift in Sources */, + 49FEC6692AD9369C00BAD9F5 /* Command.swift in Sources */, F92D0B2A236C759100575E15 /* NSTextField+Vibrancy.swift in Sources */, 49CCDA302A54FC3300FF1E13 /* ConnectionLeftPannelView.swift in Sources */, 49D223392A1DA5F10002FFCB /* SSIDSuspendTool.swift in Sources */, diff --git a/ClashX/Basic/Logger.swift b/ClashX/Basic/Logger.swift index 38348eb1b..e4fd5d6b0 100644 --- a/ClashX/Basic/Logger.swift +++ b/ClashX/Basic/Logger.swift @@ -41,8 +41,8 @@ class Logger { } } - static func log(_ msg: String, level: ClashLogLevel = .info, function: String = #function) { - shared.logToFile(msg: "[\(level.rawValue)] \(function) \(msg)", level: level) + static func log(_ msg: String, level: ClashLogLevel = .info, file: String = #file, function: String = #function) { + shared.logToFile(msg: "[\(level.rawValue)] \(file) \(function) \(msg)", level: level) } func logFilePath() -> String { diff --git a/ClashX/General/Utils/Command.swift b/ClashX/General/Utils/Command.swift new file mode 100644 index 000000000..528bb5f8d --- /dev/null +++ b/ClashX/General/Utils/Command.swift @@ -0,0 +1,34 @@ +// +// Command.swift +// ClashX +// +// Created by yicheng on 2023/10/13. +// Copyright © 2023 west2online. All rights reserved. +// + +import Foundation + +struct Command { + let cmd: String + let args: [String] + + func run() -> String { + var output = "" + + let task = Process() + task.launchPath = cmd + task.arguments = args + + let outpipe = Pipe() + task.standardOutput = outpipe + + task.launch() + + task.waitUntilExit() + let outdata = outpipe.fileHandleForReading.readDataToEndOfFile() + if var string = String(data: outdata, encoding: .utf8) { + output = string.trimmingCharacters(in: .newlines) + } + return output + } +} diff --git a/ClashX/General/Utils/NetworkChangeNotifier.swift b/ClashX/General/Utils/NetworkChangeNotifier.swift index 655a774ed..e51162167 100644 --- a/ClashX/General/Utils/NetworkChangeNotifier.swift +++ b/ClashX/General/Utils/NetworkChangeNotifier.swift @@ -198,8 +198,4 @@ class NetworkChangeNotifier { } return allowIPV6 ? ipv6 : nil } - - static func getCurrentSSID() -> String? { - return CWWiFiClient.shared().interface()?.ssid() - } } diff --git a/ClashX/General/Utils/SSIDSuspendTool.swift b/ClashX/General/Utils/SSIDSuspendTool.swift index 467f4bf27..7e9ff48e7 100644 --- a/ClashX/General/Utils/SSIDSuspendTool.swift +++ b/ClashX/General/Utils/SSIDSuspendTool.swift @@ -6,24 +6,47 @@ // Copyright © 2023 west2online. All rights reserved. // +import CoreLocation +import CoreWLAN import Foundation import RxCocoa import RxSwift -class SSIDSuspendTool { +class SSIDSuspendTool: NSObject { static let shared = SSIDSuspendTool() - var disposeBag = DisposeBag() - func setup() { - NotificationCenter - .default - .rx - .notification(.systemNetworkStatusDidChange) - .observe(on: MainScheduler.instance) - .delay(.seconds(2), scheduler: MainScheduler.instance) - .bind { [weak self] _ in - self?.update() - }.disposed(by: disposeBag) + private var ssidChangePublisher = PublishSubject() + private var disposeBag = DisposeBag() + private lazy var locationManager = CLLocationManager() + var showNoticeOnNotPermission = false + + func setup() { + if AppVersionUtil.hasVersionChanged { + showNoticeOnNotPermission = true + } + requestPermissionIfNeed() + do { + try CWWiFiClient.shared().startMonitoringEvent(with: .ssidDidChange) + CWWiFiClient.shared().delegate = self + ssidChangePublisher + .observe(on: MainScheduler.instance) + .debounce(.seconds(1), scheduler: MainScheduler.instance) + .delay(.seconds(1), scheduler: MainScheduler.instance) + .bind { [weak self] _ in + self?.update() + }.disposed(by: disposeBag) + } catch let err { + Logger.log(String(describing: err), level: .warning) + NotificationCenter + .default + .rx + .notification(.systemNetworkStatusDidChange) + .observe(on: MainScheduler.instance) + .delay(.seconds(2), scheduler: MainScheduler.instance) + .bind { [weak self] _ in + self?.update() + }.disposed(by: disposeBag) + } ConfigManager.shared .proxyShouldPaused .asObservable() @@ -40,6 +63,27 @@ class SSIDSuspendTool { update() } + func requestPermissionIfNeed() { + defer { + showNoticeOnNotPermission = false + } + if #available(macOS 14, *) { + if Settings.disableSSIDList.isEmpty { return } + if locationManager.authorizationStatus == .notDetermined { + Logger.log("request location permission") + locationManager.desiredAccuracy = kCLLocationAccuracyReduced + locationManager.delegate = self + locationManager.requestAlwaysAuthorization() + } else if locationManager.authorizationStatus != .authorized { + if showNoticeOnNotPermission { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + self.openLocationSettings() + } + } + } + } + } + func update() { if shouldSuspend() { ConfigManager.shared.proxyShouldPaused.accept(true) @@ -49,10 +93,52 @@ class SSIDSuspendTool { } func shouldSuspend() -> Bool { - if let currentSSID = NetworkChangeNotifier.getCurrentSSID() { + if let currentSSID = getCurrentSSID() { return Settings.disableSSIDList.contains(currentSSID) } else { return false } } + + private func getCurrentSSID() -> String? { + if #available(macOS 14, *) { + if locationManager.authorizationStatus != .authorized { + let info = Command(cmd: "/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport", args: ["-I"]).run() + let ssid = info.components(separatedBy: "\n") + .lazy + .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) } + .first { $0.starts(with: "SSID:") }? + .components(separatedBy: ":") + .last?.trimmingCharacters(in: .whitespacesAndNewlines) + return ssid + } + } + return CWWiFiClient.shared().interface()?.ssid() + } + + private func openLocationSettings() { + NSWorkspace.shared.open(URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Location")!) + NSApp.activate(ignoringOtherApps: true) + NSAlert.alert(with: NSLocalizedString("Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services.", comment: "")) + } +} + +extension SSIDSuspendTool: CLLocationManagerDelegate { + func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + Logger.log("Location status: \(status.rawValue)") + if status != .authorized, showNoticeOnNotPermission { + openLocationSettings() + } + showNoticeOnNotPermission = false + } + + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {} + + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {} +} + +extension SSIDSuspendTool: CWEventDelegate { + func ssidDidChangeForWiFiInterface(withName interfaceName: String) { + ssidChangePublisher.onNext(interfaceName) + } } diff --git a/ClashX/Info.plist b/ClashX/Info.plist index 250d7cc46..c8b4d0bcd 100644 --- a/ClashX/Info.plist +++ b/ClashX/Info.plist @@ -2,6 +2,10 @@ + NSLocationAlwaysAndWhenInUseUsageDescription + ClashX use location info to detect your current WiFi network SSID name and provide the auto suspend services. + NSLocationWhenInUseUsageDescription + ClashX use location info to detect your current WiFi network SSID name and provide the auto suspend services. BETA CFBundleDevelopmentRegion diff --git a/ClashX/Support Files/en.lproj/Localizable.strings b/ClashX/Support Files/en.lproj/Localizable.strings index d45893548..913ba0e90 100644 --- a/ClashX/Support Files/en.lproj/Localizable.strings +++ b/ClashX/Support Files/en.lproj/Localizable.strings @@ -172,6 +172,9 @@ /* No comment provided by engineer. */ "Open System Login Item Setting" = "Open System Login Item Setting"; +/* No comment provided by engineer. */ +"Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services." = "Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services."; + /* No comment provided by engineer. */ "Ports Open Fail, Please try to restart ClashX" = "Ports Open Fail, Please try to restart ClashX"; diff --git a/ClashX/Support Files/zh-Hans.lproj/Localizable.strings b/ClashX/Support Files/zh-Hans.lproj/Localizable.strings index b3c874a76..b867ce1b5 100644 --- a/ClashX/Support Files/zh-Hans.lproj/Localizable.strings +++ b/ClashX/Support Files/zh-Hans.lproj/Localizable.strings @@ -172,6 +172,9 @@ /* No comment provided by engineer. */ "Open System Login Item Setting" = "打开系统登录项设置"; +/* No comment provided by engineer. */ +"Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services." = "请允许ClashX使用定位服务来获取当前所连接的WiFi名称从而提供按需暂停服务。"; + /* No comment provided by engineer. */ "Ports Open Fail, Please try to restart ClashX" = "端口打开失败,请尝试重启ClashX"; diff --git a/ClashX/Support Files/zh-Hant.lproj/Localizable.strings b/ClashX/Support Files/zh-Hant.lproj/Localizable.strings index 5e3089c1f..83bf3f97a 100644 --- a/ClashX/Support Files/zh-Hant.lproj/Localizable.strings +++ b/ClashX/Support Files/zh-Hant.lproj/Localizable.strings @@ -172,6 +172,9 @@ /* No comment provided by engineer. */ "Open System Login Item Setting" = "打開系統登錄項設定"; +/* No comment provided by engineer. */ +"Please enable the location service for ClashX to detect your current WiFi network's SSID name and provide the auto-suspend services." = "請允許 ClashX 使用定位服務,以獲取您目前連接的 WiFi 名稱,並提供按需暫停服務。"; + /* No comment provided by engineer. */ "Ports Open Fail, Please try to restart ClashX" = "端口打開失敗,請嘗試重啟ClashX"; diff --git a/ClashX/ViewControllers/Settings/GeneralSettingViewController.swift b/ClashX/ViewControllers/Settings/GeneralSettingViewController.swift index ef44eef9a..ee62ff637 100644 --- a/ClashX/ViewControllers/Settings/GeneralSettingViewController.swift +++ b/ClashX/ViewControllers/Settings/GeneralSettingViewController.swift @@ -127,6 +127,9 @@ class GeneralSettingViewController: NSViewController { if url.isUrlVaild() || url.isEmpty { Settings.benchMarkUrl = url } + SSIDSuspendTool.shared.showNoticeOnNotPermission = true + SSIDSuspendTool.shared.requestPermissionIfNeed() + SSIDSuspendTool.shared.update() } @IBAction func actionResetIgnoreList(_ sender: Any) { diff --git a/Gemfile b/Gemfile index e4b5be5c3..6a51e25e7 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,6 @@ source "https://rubygems.org" gem 'fastlane' gem 'cocoapods' - +gem "activesupport", "= 7.0.8" plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/Gemfile.lock b/Gemfile.lock index 082638597..e16815078 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,12 +3,12 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (7.0.5) + activesupport (7.0.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.4) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) @@ -16,27 +16,27 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.779.0) - aws-sdk-core (3.174.0) + aws-partitions (1.835.0) + aws-sdk-core (3.185.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.66.0) - aws-sdk-core (~> 3, >= 3.174.0) + aws-sdk-kms (1.72.0) + aws-sdk-core (~> 3, >= 3.184.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.124.0) - aws-sdk-core (~> 3, >= 3.174.0) + aws-sdk-s3 (1.136.0) + aws-sdk-core (~> 3, >= 3.181.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.2) + aws-sigv4 (~> 1.6) + aws-sigv4 (1.6.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) - cocoapods (1.12.1) + cocoapods (1.13.0) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.12.1) + cocoapods-core (= 1.13.0) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 1.6.0, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -50,8 +50,8 @@ GEM molinillo (~> 0.8.0) nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) - cocoapods-core (1.12.1) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.13.0) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -76,7 +76,7 @@ GEM highline (~> 2.0.0) concurrent-ruby (1.2.2) declarative (0.0.20) - digest-crc (0.6.4) + digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) @@ -85,7 +85,7 @@ GEM escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - excon (0.100.0) + excon (0.104.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -115,7 +115,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.7) - fastlane (2.213.0) + fastlane (2.216.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -136,6 +136,7 @@ GEM google-apis-playcustomapp_v1 (~> 0.1) google-cloud-storage (~> 1.31) highline (~> 2.0) + http-cookie (~> 1.0.5) json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) @@ -147,23 +148,23 @@ GEM security (= 0.1.3) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) - terminal-table (>= 1.4.5, < 2.0.0) + terminal-table (~> 3) tty-screen (>= 0.6.3, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - fastlane-plugin-appcenter (2.1.0) + fastlane-plugin-appcenter (2.1.1) fastlane-plugin-update_xcodeproj (1.0.1) - fastlane-plugin-versioning (0.5.1) - ffi (1.15.5) + fastlane-plugin-versioning (0.5.2) + ffi (1.16.3) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.43.0) + google-apis-androidpublisher_v3 (0.50.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.0) + google-apis-core (0.11.1) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -192,10 +193,9 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.5.2) + googleauth (1.8.1) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) @@ -208,10 +208,9 @@ GEM jmespath (1.6.2) json (2.6.3) jwt (2.7.1) - memoist (0.16.2) mini_magick (4.12.0) - mini_mime (1.1.2) - minitest (5.18.0) + mini_mime (1.1.5) + minitest (5.20.0) molinillo (0.8.0) multi_json (1.15.0) multipart-post (2.3.0) @@ -229,13 +228,13 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.5) + rexml (3.2.6) rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.17.0) + signet (0.18.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) @@ -244,8 +243,8 @@ GEM CFPropertyList naturally terminal-notifier (2.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) trailblazer-option (0.1.2) tty-cursor (0.7.1) tty-screen (0.8.1) @@ -259,10 +258,10 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.8.2) - unicode-display_width (1.8.0) + unicode-display_width (2.5.0) webrick (1.8.1) word_wrap (1.0.0) - xcodeproj (1.22.0) + xcodeproj (1.23.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) @@ -278,6 +277,7 @@ PLATFORMS ruby DEPENDENCIES + activesupport (= 7.0.8) cocoapods fastlane fastlane-plugin-appcenter From 1528477fb149113871abcd3d9076fc24e1d68d73 Mon Sep 17 00:00:00 2001 From: yicheng <11733500+yichengchen@users.noreply.github.com> Date: Tue, 26 Sep 2023 11:11:37 +0800 Subject: [PATCH 2/7] feat: use custom jsbridge, remove WebViewJavascriptBridge for xcode 15 issue --- ClashX.xcodeproj/project.pbxproj | 4 + ClashX/General/Utils/JSBridge.swift | 81 +++++++++++++++++++ ClashX/General/Utils/JSBridgeHandler.swift | 31 ++++--- .../ClashWebViewContoller.swift | 22 +---- Podfile | 1 - Podfile.lock | 6 +- 6 files changed, 104 insertions(+), 41 deletions(-) create mode 100644 ClashX/General/Utils/JSBridge.swift diff --git a/ClashX.xcodeproj/project.pbxproj b/ClashX.xcodeproj/project.pbxproj index c116f1b05..b0be7d541 100644 --- a/ClashX.xcodeproj/project.pbxproj +++ b/ClashX.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 4905A2C82A2058D400AEDA2E /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = 4905A2C72A2058D400AEDA2E /* KeyboardShortcuts */; }; 4905A2CA2A20841B00AEDA2E /* NSView+Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4905A2C92A20841B00AEDA2E /* NSView+Layout.swift */; }; 4908087B29F8F405007A4944 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4908087A29F8F3FF007A4944 /* libresolv.tbd */; }; + 490C8A102AC26E67007140F2 /* JSBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490C8A0F2AC26E67007140F2 /* JSBridge.swift */; }; 4913C82321157D0200F6B87C /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4913C82221157D0200F6B87C /* Notification.swift */; }; 491E6203258A424D00313AEF /* CommonUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 491E61FD258A424500313AEF /* CommonUtils.m */; }; 49228457270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49228456270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift */; }; @@ -170,6 +171,7 @@ 4905A2C42A2058B000AEDA2E /* GlobalShortCutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalShortCutViewController.swift; sourceTree = ""; }; 4905A2C92A20841B00AEDA2E /* NSView+Layout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSView+Layout.swift"; sourceTree = ""; }; 4908087A29F8F3FF007A4944 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; }; + 490C8A0F2AC26E67007140F2 /* JSBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSBridge.swift; sourceTree = ""; }; 4913C82221157D0200F6B87C /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 491E61FC258A424500313AEF /* CommonUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonUtils.h; sourceTree = ""; }; 491E61FD258A424500313AEF /* CommonUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommonUtils.m; sourceTree = ""; }; @@ -359,6 +361,7 @@ isa = PBXGroup; children = ( 4960A6DA2136529200B940C9 /* JSBridgeHandler.swift */, + 490C8A0F2AC26E67007140F2 /* JSBridge.swift */, 493AEAE2221AE3420016FE98 /* AppVersionUtil.swift */, 49D176A62355FE680093DD7B /* NetworkChangeNotifier.swift */, 49B445152457CDF000B27E3E /* ClashStatusTool.swift */, @@ -927,6 +930,7 @@ F935B2FC23085515009E4D33 /* SystemProxyManager.swift in Sources */, 0AD7506D2A5B9B26001FFBBD /* ConnectionLeftTextCellView.swift in Sources */, 495A44D320D267D000888A0A /* LaunchAtLogin.swift in Sources */, + 490C8A102AC26E67007140F2 /* JSBridge.swift in Sources */, 4991D2322A565E6A00978143 /* Combine+Ext.swift in Sources */, 49281C802A1F01FA00F60935 /* DebugSettingViewController.swift in Sources */, 49D767762A6195E600830333 /* StructedLogReq.swift in Sources */, diff --git a/ClashX/General/Utils/JSBridge.swift b/ClashX/General/Utils/JSBridge.swift new file mode 100644 index 000000000..6daf29662 --- /dev/null +++ b/ClashX/General/Utils/JSBridge.swift @@ -0,0 +1,81 @@ +// +// JSBridge.swift +// ClashX +// +// Created by yicheng on 2023/9/26. +// Copyright © 2023 west2online. All rights reserved. +// + +import Foundation +import WebKit + +class JSBridge: NSObject { + typealias ResponseCallback = (Any?) -> Void + typealias BridgeHandler = (Any?, @escaping ResponseCallback) -> Void + + private weak var webView: WKWebView? + private var handlers = [String: BridgeHandler]() + init(_ webView: WKWebView) { + self.webView = webView + super.init() + setup() + } + + deinit { + webView?.configuration.userContentController.removeAllUserScripts() + webView?.configuration.userContentController.removeScriptMessageHandler(forName: "jsBridge") + } + + private func setup() { + addScriptMessageHandler() + } + + private func addScriptMessageHandler() { + let scriptMessageHandler = ClashScriptMessageHandler(delegate: self) + webView?.configuration.userContentController.add(scriptMessageHandler, name: "jsBridge") + } + + private func sendBackMessage(data: Any?, eventID: String) { + let data = ["id": eventID, "data": data, "type": "jsBridge"] as [String: Any?] + do { + let jsonData = try JSONSerialization.data(withJSONObject: data, options: []) + let jsonString = String(data: jsonData, encoding: .utf8)! + let str = "window.postMessage(\(jsonString), window.origin);" + webView?.evaluateJavaScript(str) + } catch let err { + Logger.log(err.localizedDescription, level: .warning) + } + } + + func registerHandler(_ name: String, handler: @escaping BridgeHandler) { + handlers[name] = handler + } +} + +extension JSBridge: WKScriptMessageHandler { + func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + if + let body = message.body as? [String: Any], + let handlerName = body["name"] as? String, + let handler = handlers[handlerName], + let eventID = body["id"] as? String { + let data = body["data"] + handler(data) { [weak self] res in + self?.sendBackMessage(data: res, eventID: eventID) + } + } + } +} + +private class ClashScriptMessageHandler: NSObject, WKScriptMessageHandler { + weak var delegate: WKScriptMessageHandler? + + public init(delegate: WKScriptMessageHandler) { + self.delegate = delegate + super.init() + } + + public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { + delegate?.userContentController(userContentController, didReceive: message) + } +} diff --git a/ClashX/General/Utils/JSBridgeHandler.swift b/ClashX/General/Utils/JSBridgeHandler.swift index 6cf0c6c11..0877fa154 100644 --- a/ClashX/General/Utils/JSBridgeHandler.swift +++ b/ClashX/General/Utils/JSBridgeHandler.swift @@ -8,16 +8,14 @@ import Alamofire import SwiftyJSON -import WebViewJavascriptBridge +import WebKit class JsBridgeUtil { - static func initJSbridge(webview: Any, delegate: Any) -> WebViewJavascriptBridge { - let bridge = WebViewJavascriptBridge(webview)! - - bridge.setWebViewDelegate(delegate) + static func initJSbridge(webview: WKWebView, delegate: Any) -> JSBridge { + let bridge = JSBridge(webview) bridge.registerHandler("isSystemProxySet") { _, responseCallback in - responseCallback?(ConfigManager.shared.proxyPortAutoSet) + responseCallback(ConfigManager.shared.proxyPortAutoSet) } bridge.registerHandler("setSystemProxy") { anydata, responseCallback in @@ -29,22 +27,22 @@ class JsBridgeUtil { } else { SystemProxyManager.shared.disableProxy() } - responseCallback?(true) + responseCallback(true) } else { - responseCallback?(false) + responseCallback(false) } } bridge.registerHandler("getStartAtLogin") { _, responseCallback in - responseCallback?(LaunchAtLogin.shared.isEnabled) + responseCallback(LaunchAtLogin.shared.isEnabled) } bridge.registerHandler("setStartAtLogin") { anydata, responseCallback in if let enable = anydata as? Bool { LaunchAtLogin.shared.isEnabled = enable - responseCallback?(true) + responseCallback(true) } else { - responseCallback?(false) + responseCallback(false) } } @@ -57,10 +55,10 @@ class JsBridgeUtil { } else { resp = delay } - responseCallback?(resp) + responseCallback(resp) } } else { - responseCallback?(nil) + responseCallback(nil) } } @@ -77,13 +75,12 @@ class JsBridgeUtil { "port": port, "secret": ConfigManager.shared.overrideSecret ?? ConfigManager.shared.apiSecret ] - callback?(data) + callback(data) } // ping-pong - bridge.registerHandler("ping") { [weak bridge] _, responseCallback in - bridge?.callHandler("pong") - responseCallback?(true) + bridge.registerHandler("ping") { _, responseCallback in + responseCallback("pong") } return bridge } diff --git a/ClashX/ViewControllers/ClashWebViewContoller.swift b/ClashX/ViewControllers/ClashWebViewContoller.swift index 63ab61024..ba3723613 100644 --- a/ClashX/ViewControllers/ClashWebViewContoller.swift +++ b/ClashX/ViewControllers/ClashWebViewContoller.swift @@ -10,7 +10,6 @@ import Cocoa import RxCocoa import RxSwift import WebKit -import WebViewJavascriptBridge enum WebCacheCleaner { static func clean() { @@ -27,7 +26,7 @@ enum WebCacheCleaner { class ClashWebViewContoller: NSViewController { let webview: CustomWKWebView = .init() - var bridge: WebViewJavascriptBridge? + var bridge: JSBridge? let disposeBag = DisposeBag() let minSize = NSSize(width: 920, height: 580) @@ -53,15 +52,9 @@ class ClashWebViewContoller: NSViewController { webview.configuration.userContentController.addUserScript(script) bridge = JsBridgeUtil.initJSbridge(webview: webview, delegate: self) - registerExtenalJSBridgeFunction() webview.configuration.preferences.setValue(true, forKey: "developerExtrasEnabled") - NotificationCenter.default.rx.notification(.configFileChange).bind { - [weak self] _ in - self?.bridge?.callHandler("onConfigChange") - }.disposed(by: disposeBag) - NotificationCenter.default.rx.notification(.reloadDashboard).bind { [weak self] _ in self?.webview.reload() @@ -113,17 +106,10 @@ class ClashWebViewContoller: NSViewController { } Logger.log("load dashboard url fail", level: .error) } -} -extension ClashWebViewContoller { - func registerExtenalJSBridgeFunction() { - bridge?.registerHandler("setDragAreaHeight") { - [weak self] anydata, responseCallback in - if let height = anydata as? CGFloat { - self?.webview.dragableAreaHeight = height - } - responseCallback?(nil) - } + func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { + NSAlert.alert(with: message) + completionHandler() } } diff --git a/Podfile b/Podfile index 9f9050b28..03f8981a2 100644 --- a/Podfile +++ b/Podfile @@ -24,7 +24,6 @@ target 'ClashX' do pod 'RxSwift' pod 'RxCocoa' pod 'CocoaLumberjack/Swift' - pod 'WebViewJavascriptBridge' pod 'Starscream','3.1.1' pod 'AppCenter/Analytics' pod 'AppCenter/Crashes' diff --git a/Podfile.lock b/Podfile.lock index 3d45e8a2b..6f45af63b 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -22,7 +22,6 @@ PODS: - SwiftFormat/CLI (0.52.3) - SwiftLint (0.52.4) - SwiftyJSON (5.0.1) - - WebViewJavascriptBridge (6.0.3) DEPENDENCIES: - Alamofire (~> 5.0) @@ -39,7 +38,6 @@ DEPENDENCIES: - SwiftFormat/CLI (~> 0.49) - SwiftLint - SwiftyJSON - - WebViewJavascriptBridge SPEC REPOS: trunk: @@ -57,7 +55,6 @@ SPEC REPOS: - SwiftFormat - SwiftLint - SwiftyJSON - - WebViewJavascriptBridge SPEC CHECKSUMS: Alamofire: 0e92e751b3e9e66d7982db43919d01f313b8eb91 @@ -74,8 +71,7 @@ SPEC CHECKSUMS: SwiftFormat: 5de81c42f043741a16e17ae2da012bbddc7c0b58 SwiftLint: 1cc5cd61ba9bacb2194e340aeb47a2a37fda00b3 SwiftyJSON: 2f33a42c6fbc52764d96f13368585094bfd8aa5e - WebViewJavascriptBridge: 7f5bc4d3581e672e8f32bd0f812d54bc69bb8e29 -PODFILE CHECKSUM: d3e952c889c7931151a654c076812b3b3294aa59 +PODFILE CHECKSUM: f3a6ebd40f44d7184ef9437d24b1979389395820 COCOAPODS: 1.12.1 From 233bc80b399982e31233a8f00ef32f89ae771e58 Mon Sep 17 00:00:00 2001 From: yicheng <11733500+yichengchen@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:59:30 +0800 Subject: [PATCH 3/7] misc: update deps --- ClashX/goClash/go.mod | 2 +- ClashX/goClash/go.sum | 4 ++-- Podfile | 4 ++-- Podfile.lock | 42 +++++++++++++++++++++--------------------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/ClashX/goClash/go.mod b/ClashX/goClash/go.mod index 46fc2f8e2..45a7c6663 100644 --- a/ClashX/goClash/go.mod +++ b/ClashX/goClash/go.mod @@ -5,7 +5,7 @@ go 1.21 toolchain go1.21.0 require ( - github.com/Dreamacro/clash v1.18.1-0.20230902125642-db2b5db2c6e2 + github.com/Dreamacro/clash v1.18.1-0.20230911035213-d034a408be42 github.com/oschwald/geoip2-golang v1.9.0 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 ) diff --git a/ClashX/goClash/go.sum b/ClashX/goClash/go.sum index e3038263d..2250a336a 100644 --- a/ClashX/goClash/go.sum +++ b/ClashX/goClash/go.sum @@ -1,5 +1,5 @@ -github.com/Dreamacro/clash v1.18.1-0.20230902125642-db2b5db2c6e2 h1:M1xQyDbW0SA+uHrTxGbrf04GGbF/08vrWrW+Q5hLaf4= -github.com/Dreamacro/clash v1.18.1-0.20230902125642-db2b5db2c6e2/go.mod h1:r//xe/2pA3Zl+3fjIiI/o6RjIVd+z87drCD58dpRnFg= +github.com/Dreamacro/clash v1.18.1-0.20230911035213-d034a408be42 h1:1gOoRDxOn2wF5u+ku5rfpX5z0vuw1lS4NW0aGvjXnZE= +github.com/Dreamacro/clash v1.18.1-0.20230911035213-d034a408be42/go.mod h1:r//xe/2pA3Zl+3fjIiI/o6RjIVd+z87drCD58dpRnFg= github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158 h1:JFnwKplz9hj8ubqYjm8HkgZS1Rvz9yW+u/XCNNTxr0k= github.com/Dreamacro/protobytes v0.0.0-20230617041236-6500a9f4f158/go.mod h1:QvmEZ/h6KXszPOr2wUFl7Zn3hfFNYdfbXwPVDTyZs6k= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= diff --git a/Podfile b/Podfile index 03f8981a2..243b43b68 100644 --- a/Podfile +++ b/Podfile @@ -8,8 +8,8 @@ post_install do |installer| config.build_settings['SWIFT_VERSION'] = '5' end end - if config.build_settings['MACOSX_DEPLOYMENT_TARGET'] == '' || Gem::Version.new(config.build_settings['MACOSX_DEPLOYMENT_TARGET']) < Gem::Version.new("10.13") - config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '10.13' + if config.build_settings['MACOSX_DEPLOYMENT_TARGET'] == '' || Gem::Version.new(config.build_settings['MACOSX_DEPLOYMENT_TARGET']) < Gem::Version.new("10.14") + config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '10.14' end end end diff --git a/Podfile.lock b/Podfile.lock index 6f45af63b..b117f5aed 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,9 +1,9 @@ PODS: - Alamofire (5.8.0) - - AppCenter/Analytics (5.0.3): + - AppCenter/Analytics (5.0.4): - AppCenter/Core - - AppCenter/Core (5.0.3) - - AppCenter/Crashes (5.0.3): + - AppCenter/Core (5.0.4) + - AppCenter/Crashes (5.0.4): - AppCenter/Core - CocoaLumberjack/Core (3.8.1) - CocoaLumberjack/Swift (3.8.1): @@ -11,16 +11,16 @@ PODS: - FlexibleDiff (0.0.9) - GzipSwift (5.1.1) - LetsMove (1.25) - - RxCocoa (6.5.0): - - RxRelay (= 6.5.0) - - RxSwift (= 6.5.0) - - RxRelay (6.5.0): - - RxSwift (= 6.5.0) - - RxSwift (6.5.0) - - Sparkle (2.4.2) + - RxCocoa (6.6.0): + - RxRelay (= 6.6.0) + - RxSwift (= 6.6.0) + - RxRelay (6.6.0): + - RxSwift (= 6.6.0) + - RxSwift (6.6.0) + - Sparkle (2.5.1) - Starscream (3.1.1) - - SwiftFormat/CLI (0.52.3) - - SwiftLint (0.52.4) + - SwiftFormat/CLI (0.52.7) + - SwiftLint (0.53.0) - SwiftyJSON (5.0.1) DEPENDENCIES: @@ -58,20 +58,20 @@ SPEC REPOS: SPEC CHECKSUMS: Alamofire: 0e92e751b3e9e66d7982db43919d01f313b8eb91 - AppCenter: a4070ec3d4418b5539067a51f57155012e486ebd + AppCenter: 85c92db0759d2792a65eb61d6842d2e86611a49a CocoaLumberjack: 5c7e64cdb877770859bddec4d3d5a0d7c9299df9 FlexibleDiff: b9ee9b8305b42c784f5dd40589203c97c55bbaa0 GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa LetsMove: 7b9fe44737707d984fbd3f47af46609a9a07b461 - RxCocoa: 94f817b71c07517321eb4f9ad299112ca8af743b - RxRelay: 1de1523e604c72b6c68feadedd1af3b1b4d0ecbd - RxSwift: 5710a9e6b17f3c3d6e40d6e559b9fa1e813b2ef8 - Sparkle: 5ef7097e655c60f4aeb23fd1658fc3e8dd50f4ec + RxCocoa: 44a80de90e25b739b5aeaae3c8c371a32e3343cc + RxRelay: 45eaa5db8ee4fb50e5ebd57deec0159e97fa51e6 + RxSwift: a4b44f7d24599f674deebd1818eab82e58410632 + Sparkle: ce9957501a2655dd4c8264312c6134ff478a777c Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0 - SwiftFormat: 5de81c42f043741a16e17ae2da012bbddc7c0b58 - SwiftLint: 1cc5cd61ba9bacb2194e340aeb47a2a37fda00b3 + SwiftFormat: 2c4785ad647322b41e027b9d4df160aef526a656 + SwiftLint: 5ce4d6a8ff83f1b5fd5ad5dbf30965d35af65e44 SwiftyJSON: 2f33a42c6fbc52764d96f13368585094bfd8aa5e -PODFILE CHECKSUM: f3a6ebd40f44d7184ef9437d24b1979389395820 +PODFILE CHECKSUM: 8c6ef0c5999141047a530cd8b74a41d2161ae11b -COCOAPODS: 1.12.1 +COCOAPODS: 1.13.0 From e5b191c9e7344341a192f1796836d70e7cfff4aa Mon Sep 17 00:00:00 2001 From: yicheng <11733500+yichengchen@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:47:37 +0800 Subject: [PATCH 4/7] feat: mark proxy group speedtestable --- ClashX/Models/ClashProxy.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ClashX/Models/ClashProxy.swift b/ClashX/Models/ClashProxy.swift index 0a1748b25..3b8166884 100644 --- a/ClashX/Models/ClashProxy.swift +++ b/ClashX/Models/ClashProxy.swift @@ -114,7 +114,7 @@ class ClashProxy: Codable { guard let resp = enclosingResp, let allProxys = all else { return [] } var proxys = [SpeedtestAbleItem]() for proxy in allProxys { - if let p = resp.proxiesMap[proxy], !ClashProxyType.isProxyGroup(p) { + if let p = resp.proxiesMap[proxy] { if let provider = p.enclosingProvider { proxys.append(.provider(name: p.name, provider: provider.name)) } else { From b3234a4cc7b3d487eccabce215b41633280311f8 Mon Sep 17 00:00:00 2001 From: yicheng <11733500+yichengchen@users.noreply.github.com> Date: Wed, 18 Oct 2023 11:12:22 +0800 Subject: [PATCH 5/7] fix: macos 14 connection dashboard overlap issue --- .../Connections/Views/Cell/ConnectionTextCellView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/ClashX/ViewControllers/Connections/Views/Cell/ConnectionTextCellView.swift b/ClashX/ViewControllers/Connections/Views/Cell/ConnectionTextCellView.swift index 9f8004f97..e377be807 100644 --- a/ClashX/ViewControllers/Connections/Views/Cell/ConnectionTextCellView.swift +++ b/ClashX/ViewControllers/Connections/Views/Cell/ConnectionTextCellView.swift @@ -24,6 +24,7 @@ class ConnectionTextCellView: NSView, ConnectionCellProtocol { } func setupUI() { + clipsToBounds = true addSubview(label) label.font = NSFont.systemFont(ofSize: 12) label.makeConstraints { From 498c6d79b8bf0ee534457062318c1e168674aee4 Mon Sep 17 00:00:00 2001 From: yicheng <11733500+yichengchen@users.noreply.github.com> Date: Wed, 18 Oct 2023 11:28:00 +0800 Subject: [PATCH 6/7] misc: sometimes dashboard won't popup to front, recall activate command --- ClashX/ClashWindowController.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ClashX/ClashWindowController.swift b/ClashX/ClashWindowController.swift index a983af73f..ffc9d66c1 100644 --- a/ClashX/ClashWindowController.swift +++ b/ClashX/ClashWindowController.swift @@ -71,6 +71,8 @@ class ClashWindowController: NSWindowController, NSWindowDe } window?.makeKeyAndOrderFront(self) window?.delegate = self + NSApp.activate(ignoringOtherApps: true) + window?.makeKeyAndOrderFront(nil) } func windowWillClose(_ notification: Notification) { From 6e66c63c108333ce259fed6ee5ed9eee1dc5526b Mon Sep 17 00:00:00 2001 From: mrFq1 <1xxbx0il0@mozmail.com> Date: Thu, 2 Nov 2023 16:06:11 +0800 Subject: [PATCH 7/7] misc: merge --- ClashX.xcodeproj/project.pbxproj | 9 +-- ClashX/General/Utils/JSBridge.swift | 81 ---------------------- ClashX/General/Utils/SSIDSuspendTool.swift | 1 + 3 files changed, 3 insertions(+), 88 deletions(-) delete mode 100644 ClashX/General/Utils/JSBridge.swift diff --git a/ClashX.xcodeproj/project.pbxproj b/ClashX.xcodeproj/project.pbxproj index e4c592ed8..89f0631ac 100644 --- a/ClashX.xcodeproj/project.pbxproj +++ b/ClashX.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0106179F2AF38EFA005C7877 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FEC6682AD9369C00BAD9F5 /* Command.swift */; }; 015B976A2A4F2F4500F9FA4D /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 015B97692A4F2F4500F9FA4D /* Alamofire */; }; 015B976D2A4F2F6C00F9FA4D /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 015B976C2A4F2F6C00F9FA4D /* RxCocoa */; }; 015B976F2A4F2F6C00F9FA4D /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 015B976E2A4F2F6C00F9FA4D /* RxSwift */; }; @@ -156,7 +157,6 @@ 4905A2C82A2058D400AEDA2E /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = 4905A2C72A2058D400AEDA2E /* KeyboardShortcuts */; }; 4905A2CA2A20841B00AEDA2E /* NSView+Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4905A2C92A20841B00AEDA2E /* NSView+Layout.swift */; }; 4908087B29F8F405007A4944 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4908087A29F8F3FF007A4944 /* libresolv.tbd */; }; - 490C8A102AC26E67007140F2 /* JSBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 490C8A0F2AC26E67007140F2 /* JSBridge.swift */; }; 4913C82321157D0200F6B87C /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4913C82221157D0200F6B87C /* Notification.swift */; }; 491E6203258A424D00313AEF /* CommonUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 491E61FD258A424500313AEF /* CommonUtils.m */; }; 49228457270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49228456270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift */; }; @@ -222,9 +222,6 @@ 49D223392A1DA5F10002FFCB /* SSIDSuspendTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D223382A1DA5F10002FFCB /* SSIDSuspendTool.swift */; }; 49D6A45229AEEC15006487EF /* StatusItemTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D6A45129AEEC15006487EF /* StatusItemTool.swift */; }; 49D6A45629AEEC55006487EF /* StatusItemViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D6A45529AEEC55006487EF /* StatusItemViewProtocol.swift */; }; - 49D767742A6195C800830333 /* ConnectionsReq.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D767732A6195C800830333 /* ConnectionsReq.swift */; }; - 49D767762A6195E600830333 /* StructedLogReq.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D767752A6195E600830333 /* StructedLogReq.swift */; }; - 49D84AD32A56E9760074CCDB /* ConnectionStatusIconCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49D84AD22A56E9760074CCDB /* ConnectionStatusIconCellView.swift */; }; 49FEC6692AD9369C00BAD9F5 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49FEC6682AD9369C00BAD9F5 /* Command.swift */; }; 8A2BBEA727A03ACB0081EBEF /* ProxySetting.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 8A2BBEA627A03ACB0081EBEF /* ProxySetting.sdef */; }; 8ACD21BB27A04C7800BC4632 /* ProxySettingCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ACD21BA27A04C7800BC4632 /* ProxySettingCommand.swift */; }; @@ -327,7 +324,6 @@ 4905A2C42A2058B000AEDA2E /* GlobalShortCutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalShortCutViewController.swift; sourceTree = ""; }; 4905A2C92A20841B00AEDA2E /* NSView+Layout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSView+Layout.swift"; sourceTree = ""; }; 4908087A29F8F3FF007A4944 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; }; - 490C8A0F2AC26E67007140F2 /* JSBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSBridge.swift; sourceTree = ""; }; 4913C82221157D0200F6B87C /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 491E61FC258A424500313AEF /* CommonUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonUtils.h; sourceTree = ""; }; 491E61FD258A424500313AEF /* CommonUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommonUtils.m; sourceTree = ""; }; @@ -405,7 +401,6 @@ 49D6A45529AEEC55006487EF /* StatusItemViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusItemViewProtocol.swift; sourceTree = ""; }; 49D8276627E9B01700159D93 /* LoginKitWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoginKitWrapper.h; sourceTree = ""; }; 49D8276727E9B01700159D93 /* LoginKitWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoginKitWrapper.m; sourceTree = ""; }; - 49D84AD22A56E9760074CCDB /* ConnectionStatusIconCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionStatusIconCellView.swift; sourceTree = ""; }; 49FEC6682AD9369C00BAD9F5 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; 8A2BBEA627A03ACB0081EBEF /* ProxySetting.sdef */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = ProxySetting.sdef; sourceTree = ""; }; 8ACD21BA27A04C7800BC4632 /* ProxySettingCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxySettingCommand.swift; sourceTree = ""; }; @@ -1028,6 +1023,7 @@ 01F335E82AD10D0B0048AF77 /* AlphaMetaDownloader.swift in Sources */, 01F335E92AD10D0B0048AF77 /* NetworkChangeNotifier.swift in Sources */, 01F335EA2AD10D0B0048AF77 /* GlobalShortCutViewController.swift in Sources */, + 0106179F2AF38EFA005C7877 /* Command.swift in Sources */, 01F335EB2AD10D0B0048AF77 /* Notification.swift in Sources */, 01F335EC2AD10D0B0048AF77 /* ClashMetaConfig.swift in Sources */, 01F335ED2AD10D0B0048AF77 /* ProxyModeChangeCommand.swift in Sources */, @@ -1107,7 +1103,6 @@ 495340B320DE68C300B0D3FF /* StatusItemView.swift in Sources */, F935B2FC23085515009E4D33 /* SystemProxyManager.swift in Sources */, 495A44D320D267D000888A0A /* LaunchAtLogin.swift in Sources */, - 490C8A102AC26E67007140F2 /* JSBridge.swift in Sources */, 4991D2322A565E6A00978143 /* Combine+Ext.swift in Sources */, 49281C802A1F01FA00F60935 /* DebugSettingViewController.swift in Sources */, 49CCDA2A2A54F9AC00FF1E13 /* ClashWindowController.swift in Sources */, diff --git a/ClashX/General/Utils/JSBridge.swift b/ClashX/General/Utils/JSBridge.swift deleted file mode 100644 index 6daf29662..000000000 --- a/ClashX/General/Utils/JSBridge.swift +++ /dev/null @@ -1,81 +0,0 @@ -// -// JSBridge.swift -// ClashX -// -// Created by yicheng on 2023/9/26. -// Copyright © 2023 west2online. All rights reserved. -// - -import Foundation -import WebKit - -class JSBridge: NSObject { - typealias ResponseCallback = (Any?) -> Void - typealias BridgeHandler = (Any?, @escaping ResponseCallback) -> Void - - private weak var webView: WKWebView? - private var handlers = [String: BridgeHandler]() - init(_ webView: WKWebView) { - self.webView = webView - super.init() - setup() - } - - deinit { - webView?.configuration.userContentController.removeAllUserScripts() - webView?.configuration.userContentController.removeScriptMessageHandler(forName: "jsBridge") - } - - private func setup() { - addScriptMessageHandler() - } - - private func addScriptMessageHandler() { - let scriptMessageHandler = ClashScriptMessageHandler(delegate: self) - webView?.configuration.userContentController.add(scriptMessageHandler, name: "jsBridge") - } - - private func sendBackMessage(data: Any?, eventID: String) { - let data = ["id": eventID, "data": data, "type": "jsBridge"] as [String: Any?] - do { - let jsonData = try JSONSerialization.data(withJSONObject: data, options: []) - let jsonString = String(data: jsonData, encoding: .utf8)! - let str = "window.postMessage(\(jsonString), window.origin);" - webView?.evaluateJavaScript(str) - } catch let err { - Logger.log(err.localizedDescription, level: .warning) - } - } - - func registerHandler(_ name: String, handler: @escaping BridgeHandler) { - handlers[name] = handler - } -} - -extension JSBridge: WKScriptMessageHandler { - func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - if - let body = message.body as? [String: Any], - let handlerName = body["name"] as? String, - let handler = handlers[handlerName], - let eventID = body["id"] as? String { - let data = body["data"] - handler(data) { [weak self] res in - self?.sendBackMessage(data: res, eventID: eventID) - } - } - } -} - -private class ClashScriptMessageHandler: NSObject, WKScriptMessageHandler { - weak var delegate: WKScriptMessageHandler? - - public init(delegate: WKScriptMessageHandler) { - self.delegate = delegate - super.init() - } - - public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - delegate?.userContentController(userContentController, didReceive: message) - } -} diff --git a/ClashX/General/Utils/SSIDSuspendTool.swift b/ClashX/General/Utils/SSIDSuspendTool.swift index 7e9ff48e7..0c88dba22 100644 --- a/ClashX/General/Utils/SSIDSuspendTool.swift +++ b/ClashX/General/Utils/SSIDSuspendTool.swift @@ -11,6 +11,7 @@ import CoreWLAN import Foundation import RxCocoa import RxSwift +import AppKit class SSIDSuspendTool: NSObject { static let shared = SSIDSuspendTool()