mirror of
https://github.com/X1a0He/Adobe-Downloader.git
synced 2025-11-25 11:18:53 +08:00
refactor: Helper uninstallation and reinstallation logic
This commit is contained in:
@@ -49,6 +49,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
}
|
}
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PrivilegedHelperManager.shared.executeCommand("id -u") { _ in }
|
||||||
}
|
}
|
||||||
|
|
||||||
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
||||||
|
|||||||
@@ -228,21 +228,17 @@ class PrivilegedHelperManager: NSObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func reinstallHelper(completion: @escaping (Bool, String) -> Void) {
|
func reinstallHelper(completion: @escaping (Bool, String) -> Void) {
|
||||||
disconnectHelper()
|
uninstallHelperViaTerminal { [weak self] success, message in
|
||||||
|
|
||||||
removeInstallHelper()
|
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
|
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now()) {
|
||||||
let result = self.installHelperDaemon()
|
let result = self.installHelperDaemon()
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .success:
|
case .success:
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now()) { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
self.tryConnect(retryCount: 5, delay: 2.0, completion: completion)
|
self.tryConnect(retryCount: 3, delay: 1, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
case .authorizationFail:
|
case .authorizationFail:
|
||||||
@@ -254,17 +250,27 @@ class PrivilegedHelperManager: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func tryConnect(retryCount: Int, delay: TimeInterval = 2.0, completion: @escaping (Bool, String) -> Void) {
|
private func tryConnect(retryCount: Int, delay: TimeInterval = 2.0, completion: @escaping (Bool, String) -> Void) {
|
||||||
|
struct Static {
|
||||||
|
static var currentAttempt = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if retryCount == 3 {
|
||||||
|
Static.currentAttempt = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Static.currentAttempt += 1
|
||||||
|
|
||||||
guard retryCount > 0 else {
|
guard retryCount > 0 else {
|
||||||
completion(false, String(localized: "多次尝试连接失败"))
|
completion(false, String(localized: "多次尝试连接失败"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let connection = connectToHelper() else {
|
guard let connection = connectToHelper() else {
|
||||||
print("连接尝试失败,剩余重试次数: \(retryCount - 1)")
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
||||||
self?.tryConnect(retryCount: retryCount - 1, delay: delay, completion: completion)
|
self?.tryConnect(retryCount: retryCount - 1, delay: delay * 1, completion: completion)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -274,23 +280,29 @@ class PrivilegedHelperManager: NSObject {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
helper.executeCommand(type: .shellCommand, path1: "whoami", path2: "", permissions: 0) { result in
|
helper.executeCommand(type: .shellCommand, path1: "id -u", path2: "", permissions: 0) { result in
|
||||||
if result.contains("root") {
|
if result == "0" || result.contains("0") {
|
||||||
completion(true, String(localized: "Helper 重新安装成功"))
|
completion(true, String(localized: "Helper 重新安装成功"))
|
||||||
} else {
|
} else {
|
||||||
completion(false, String(localized: "Helper 安装失败"))
|
print("Helper验证失败,返回结果: \(result)")
|
||||||
|
completion(false, String(localized: "Helper 安装失败: \(result)"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeInstallHelper() {
|
func removeInstallHelper(completion: ((Bool) -> Void)? = nil) {
|
||||||
try? FileManager.default.removeItem(atPath: "/Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)")
|
if FileManager.default.fileExists(atPath: "/Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist") {
|
||||||
try? FileManager.default.removeItem(atPath: "/Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist")
|
try? FileManager.default.removeItem(atPath: "/Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist")
|
||||||
}
|
}
|
||||||
|
if FileManager.default.fileExists(atPath: "/Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)") {
|
||||||
|
try? FileManager.default.removeItem(atPath: "/Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)")
|
||||||
|
}
|
||||||
|
completion?(true)
|
||||||
|
}
|
||||||
|
|
||||||
func connectToHelper() -> NSXPCConnection? {
|
func connectToHelper() -> NSXPCConnection? {
|
||||||
return connectionQueue.sync {
|
return connectionQueue.sync {
|
||||||
createConnection()
|
return createConnection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,8 +346,8 @@ class PrivilegedHelperManager: NSObject {
|
|||||||
var isConnected = false
|
var isConnected = false
|
||||||
|
|
||||||
if let helper = newConnection.remoteObjectProxy as? HelperToolProtocol {
|
if let helper = newConnection.remoteObjectProxy as? HelperToolProtocol {
|
||||||
helper.executeCommand(type: .shellCommand, path1: "whoami", path2: "", permissions: 0) { [weak self] result in
|
helper.executeCommand(type: .shellCommand, path1: "id -u", path2: "", permissions: 0) { [weak self] result in
|
||||||
if result.contains("root") {
|
if result.contains("0") || result == "0" {
|
||||||
isConnected = true
|
isConnected = true
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self?.connection = newConnection
|
self?.connection = newConnection
|
||||||
@@ -344,8 +356,6 @@ class PrivilegedHelperManager: NSObject {
|
|||||||
}
|
}
|
||||||
semaphore.signal()
|
semaphore.signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = semaphore.wait(timeout: .now() + 1.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isConnected {
|
if !isConnected {
|
||||||
@@ -430,7 +440,7 @@ class PrivilegedHelperManager: NSObject {
|
|||||||
do {
|
do {
|
||||||
let helper = try self.getHelperProxy()
|
let helper = try self.getHelperProxy()
|
||||||
|
|
||||||
helper.executeCommand(type: .install, path1: "whoami", path2: "", permissions: 0) { result in
|
helper.executeCommand(type: .install, path1: "id -u", path2: "", permissions: 0) { result in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if result == "root" {
|
if result == "root" {
|
||||||
self.connectionState = .connected
|
self.connectionState = .connected
|
||||||
@@ -510,10 +520,13 @@ class PrivilegedHelperManager: NSObject {
|
|||||||
guard !isInitializing else { return }
|
guard !isInitializing else { return }
|
||||||
isInitializing = true
|
isInitializing = true
|
||||||
|
|
||||||
removeInstallHelper()
|
uninstallHelperViaTerminal { [weak self] success, _ in
|
||||||
notifyInstall()
|
guard let self = self else { return }
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||||
isInitializing = false
|
self.notifyInstall()
|
||||||
|
self.isInitializing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func disconnectHelper() {
|
func disconnectHelper() {
|
||||||
@@ -525,6 +538,59 @@ class PrivilegedHelperManager: NSObject {
|
|||||||
connectionState = .disconnected
|
connectionState = .disconnected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func uninstallHelperViaTerminal(completion: @escaping (Bool, String) -> Void) {
|
||||||
|
disconnectHelper()
|
||||||
|
let script = """
|
||||||
|
#!/bin/bash
|
||||||
|
sudo /bin/launchctl unload /Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist
|
||||||
|
sudo /bin/rm -f /Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist
|
||||||
|
sudo /bin/rm -f /Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)
|
||||||
|
sudo /usr/bin/killall -u root -9 \(PrivilegedHelperManager.machServiceName)
|
||||||
|
exit 0
|
||||||
|
"""
|
||||||
|
|
||||||
|
let tempDir = FileManager.default.temporaryDirectory
|
||||||
|
let scriptURL = tempDir.appendingPathComponent("uninstall_helper.sh")
|
||||||
|
|
||||||
|
do {
|
||||||
|
try script.write(to: scriptURL, atomically: true, encoding: .utf8)
|
||||||
|
try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: scriptURL.path)
|
||||||
|
|
||||||
|
let task = Process()
|
||||||
|
task.executableURL = URL(fileURLWithPath: "/usr/bin/osascript")
|
||||||
|
task.arguments = ["-e", "do shell script \"\(scriptURL.path)\" with administrator privileges"]
|
||||||
|
|
||||||
|
let outputPipe = Pipe()
|
||||||
|
let errorPipe = Pipe()
|
||||||
|
task.standardOutput = outputPipe
|
||||||
|
task.standardError = errorPipe
|
||||||
|
|
||||||
|
do {
|
||||||
|
try task.run()
|
||||||
|
task.waitUntilExit()
|
||||||
|
|
||||||
|
if task.terminationStatus == 0 {
|
||||||
|
UserDefaults.standard.removeObject(forKey: "InstalledHelperBuild")
|
||||||
|
|
||||||
|
connectionState = .disconnected
|
||||||
|
connection = nil
|
||||||
|
|
||||||
|
completion(true, String(localized: "Helper 已完全卸载"))
|
||||||
|
} else {
|
||||||
|
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
|
||||||
|
let errorString = String(data: errorData, encoding: .utf8) ?? "未知错误"
|
||||||
|
completion(false, String(localized: "卸载失败: \(errorString)"))
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
completion(false, String(localized: "执行卸载脚本失败: \(error.localizedDescription)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
try? FileManager.default.removeItem(at: scriptURL)
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
completion(false, String(localized: "准备卸载脚本失败: \(error.localizedDescription)"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PrivilegedHelperManager {
|
extension PrivilegedHelperManager {
|
||||||
|
|||||||
@@ -233,8 +233,6 @@ final class GeneralSettingsViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
PrivilegedHelperManager.shared.executeCommand("whoami") { _ in }
|
|
||||||
|
|
||||||
NotificationCenter.default.publisher(for: .storageDidChange)
|
NotificationCenter.default.publisher(for: .storageDidChange)
|
||||||
.receive(on: RunLoop.main)
|
.receive(on: RunLoop.main)
|
||||||
.sink { [weak self] _ in
|
.sink { [weak self] _ in
|
||||||
|
|||||||
@@ -339,6 +339,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Helper 安装失败" : {
|
"Helper 安装失败" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -347,6 +348,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Helper 安装失败: %@" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Helper 已完全卸载" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Helper 是一个具有管理员权限的辅助工具,用于执行需要管理员权限的操作,如修改系统文件等。没有 Helper 将无法正常使用软件的某些功能。" : {
|
"Helper 是一个具有管理员权限的辅助工具,用于执行需要管理员权限的操作,如修改系统文件等。没有 Helper 将无法正常使用软件的某些功能。" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -978,6 +985,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"准备卸载脚本失败: %@" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"准备安装..." : {
|
"准备安装..." : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -1098,6 +1108,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"卸载失败: %@" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"取消" : {
|
"取消" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -1713,6 +1726,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"执行卸载脚本失败: %@" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"执行成功" : {
|
"执行成功" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|||||||
Reference in New Issue
Block a user