mirror of
https://github.com/X1a0He/Adobe-Downloader.git
synced 2025-11-25 03:14:57 +08:00
feat: 调整 Helper
This commit is contained in:
@@ -39,6 +39,7 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
case connected
|
||||
case disconnected
|
||||
case connecting
|
||||
case needsApproval
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
@@ -48,6 +49,8 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
return String(localized: "未连接")
|
||||
case .connecting:
|
||||
return String(localized: "正在连接")
|
||||
case .needsApproval:
|
||||
return String(localized: "需要批准")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,9 +114,10 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
}
|
||||
|
||||
private func setupAutoReconnect() {
|
||||
Timer.scheduledTimer(withTimeInterval: 3.0, repeats: true) { [weak self] _ in
|
||||
Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
if self.connectionState == .disconnected && self.shouldAutoReconnect {
|
||||
if self.connectionState == .disconnected && self.shouldAutoReconnect && !self.isInitializing {
|
||||
self.logger.info("尝试自动重连Helper...")
|
||||
Task {
|
||||
await self.attemptConnection()
|
||||
}
|
||||
@@ -122,6 +126,7 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
}
|
||||
|
||||
func checkAndInstallHelper() async {
|
||||
isInitializing = true
|
||||
logger.info("开始检查 Helper 状态")
|
||||
|
||||
let status = await getHelperStatus()
|
||||
@@ -135,6 +140,7 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
registerHelper()
|
||||
break
|
||||
case .needsApproval:
|
||||
self.connectionState = .needsApproval
|
||||
showApprovalGuidance()
|
||||
break
|
||||
case .requiresUpdate:
|
||||
@@ -142,8 +148,17 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
break
|
||||
case .installed:
|
||||
Task {
|
||||
await attemptConnection()
|
||||
connectionSuccessBlock?()
|
||||
let connectionResult = await attemptConnection()
|
||||
if connectionResult {
|
||||
logger.info("Helper 连接成功")
|
||||
connectionSuccessBlock?()
|
||||
} else {
|
||||
logger.warning("Helper 安装成功但连接失败,可能存在权限问题")
|
||||
await MainActor.run {
|
||||
self.connectionState = .disconnected
|
||||
}
|
||||
}
|
||||
self.isInitializing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,6 +187,7 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
return .installed
|
||||
|
||||
case .requiresApproval:
|
||||
logger.info("Helper需要用户批准")
|
||||
return .needsApproval
|
||||
|
||||
case .notFound:
|
||||
@@ -179,7 +195,7 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
|
||||
@unknown default:
|
||||
logger.warning("未知的 SMAppService 状态: \(status.rawValue)")
|
||||
return .notInstalled
|
||||
return .needsApproval
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,15 +215,57 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||
Task {
|
||||
await self.attemptConnection()
|
||||
await self.tryEnableHelper()
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
logger.error("Helper 注册失败: \(error)")
|
||||
handleRegistrationError(error)
|
||||
isInitializing = false
|
||||
}
|
||||
}
|
||||
|
||||
private func tryEnableHelper() async {
|
||||
guard let appService = appService else { return }
|
||||
|
||||
let currentStatus = appService.status
|
||||
logger.info("尝试启用Helper,当前状态: \(currentStatus.rawValue)")
|
||||
|
||||
if currentStatus != .enabled {
|
||||
do {
|
||||
logger.info("尝试重新注册Helper以启用")
|
||||
try appService.register()
|
||||
|
||||
try await Task.sleep(nanoseconds: 2_000_000_000)
|
||||
|
||||
let newStatus = appService.status
|
||||
logger.info("重新注册后状态: \(newStatus.rawValue)")
|
||||
|
||||
if newStatus == .enabled {
|
||||
logger.info("Helper成功启用")
|
||||
let connectionResult = await attemptConnection()
|
||||
if connectionResult {
|
||||
logger.info("Helper连接成功")
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
logger.error("重新注册失败: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
let connectionResult = await attemptConnection()
|
||||
if !connectionResult {
|
||||
logger.warning("Helper 注册成功但连接失败,需要用户批准")
|
||||
await MainActor.run {
|
||||
self.connectionState = .needsApproval
|
||||
self.showApprovalGuidance()
|
||||
}
|
||||
}
|
||||
|
||||
self.isInitializing = false
|
||||
}
|
||||
|
||||
private func updateHelper() {
|
||||
registerHelper()
|
||||
@@ -286,17 +344,33 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
var isConnected = false
|
||||
|
||||
if let helper = newConnection.remoteObjectProxy as? HelperToolProtocol {
|
||||
helper.executeCommand(type: .shellCommand, path1: "id -u", path2: "", permissions: 0) { [weak self] result in
|
||||
if result.contains("0") || result == "0" {
|
||||
helper.executeCommand(type: .shellCommand, path1: "whoami", path2: "", permissions: 0) { [weak self] result in
|
||||
let trimmedResult = result.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
self?.logger.info("Helper 响应: \(trimmedResult)")
|
||||
|
||||
if trimmedResult == "root" {
|
||||
isConnected = true
|
||||
DispatchQueue.main.async {
|
||||
self?.connection = newConnection
|
||||
self?.connectionState = .connected
|
||||
self?.logger.info("Helper 权限验证成功,当前用户: \(trimmedResult)")
|
||||
}
|
||||
} else if !trimmedResult.starts(with: "Error:") && !trimmedResult.isEmpty {
|
||||
isConnected = true
|
||||
DispatchQueue.main.async {
|
||||
self?.connection = newConnection
|
||||
self?.connectionState = .connected
|
||||
self?.logger.warning("Helper 连接成功但权限可能不足,当前用户: \(trimmedResult)")
|
||||
}
|
||||
} else {
|
||||
self?.logger.error("Helper 连接失败或权限不足: \(trimmedResult)")
|
||||
}
|
||||
semaphore.signal()
|
||||
}
|
||||
_ = semaphore.wait(timeout: .now() + 1.0)
|
||||
let waitResult = semaphore.wait(timeout: .now() + 8.0)
|
||||
if waitResult == .timedOut {
|
||||
logger.warning("Helper 连接超时")
|
||||
}
|
||||
}
|
||||
|
||||
if !isConnected {
|
||||
@@ -335,7 +409,7 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
}
|
||||
|
||||
func getHelperProxy() throws -> HelperToolProtocol {
|
||||
if connectionState != .connected {
|
||||
if connectionState != .connected || connection == nil {
|
||||
guard let newConnection = connectionQueue.sync(execute: { createConnection() }) else {
|
||||
throw HelperError.connectionFailed
|
||||
}
|
||||
@@ -344,7 +418,9 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
|
||||
guard let helper = connection?.remoteObjectProxyWithErrorHandler({ [weak self] error in
|
||||
self?.logger.error("XPC 代理错误: \(error)")
|
||||
self?.connectionState = .disconnected
|
||||
DispatchQueue.main.async {
|
||||
self?.connectionState = .disconnected
|
||||
}
|
||||
}) as? HelperToolProtocol else {
|
||||
throw HelperError.proxyError
|
||||
}
|
||||
@@ -375,8 +451,11 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
connectionState = .disconnected
|
||||
completion("Error: \(error.localizedDescription)")
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.connectionState = .disconnected
|
||||
self?.logger.error("执行命令失败: \(error.localizedDescription)")
|
||||
completion("Error: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,10 +514,13 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
}
|
||||
|
||||
private func updateConnectionState(from result: String) {
|
||||
if result.starts(with: "Error:") {
|
||||
connectionState = .disconnected
|
||||
} else {
|
||||
connectionState = .connected
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
if result.starts(with: "Error:") {
|
||||
self?.connectionState = .disconnected
|
||||
self?.logger.warning("命令执行失败,连接状态设为断开: \(result)")
|
||||
} else {
|
||||
self?.connectionState = .connected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,8 +636,20 @@ class ModernPrivilegedHelperManager: NSObject, ObservableObject {
|
||||
|
||||
private func showApprovalGuidance() {
|
||||
let alert = NSAlert()
|
||||
alert.messageText = String(localized: "需要在系统设置中允许 Helper")
|
||||
alert.informativeText = String(localized: "Adobe Downloader 需要通过后台服务来安装与移动文件。请在\"系统设置 → 通用 → 登录项与扩展\"中允许此应用的后台项目。")
|
||||
alert.messageText = String(localized: "Helper服务需要批准")
|
||||
alert.informativeText = String(localized: """
|
||||
Adobe Downloader需要后台Helper服务来执行安装和文件操作。
|
||||
|
||||
解决方法:
|
||||
1. 点击下方「打开系统设置」按钮
|
||||
2. 在「登录项与扩展」中找到 Adobe Downloader
|
||||
3. 确保应用已被允许,并检查是否有任何需要启用的后台项目
|
||||
4. 如果看不到相关选项,请尝试:
|
||||
- 重启 Adobe Downloader
|
||||
- 或重启系统后再试
|
||||
|
||||
注意:macOS可能需要重启才能完全激活Helper服务。
|
||||
""")
|
||||
alert.addButton(withTitle: String(localized: "打开系统设置"))
|
||||
alert.addButton(withTitle: String(localized: "稍后设置"))
|
||||
|
||||
|
||||
@@ -181,6 +181,8 @@ class PrivilegedHelperAdapter: NSObject, ObservableObject {
|
||||
return .disconnected
|
||||
case .connecting:
|
||||
return .connecting
|
||||
case .needsApproval:
|
||||
return .disconnected
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,13 @@
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>SMPrivilegedExecutables</key>
|
||||
<key>SMAppService</key>
|
||||
<dict>
|
||||
<key>com.x1a0he.macOS.Adobe-Downloader.helper</key>
|
||||
<string>identifier "com.x1a0he.macOS.Adobe-Downloader.helper" and anchor apple generic and certificate leaf[subject.CN] = "Apple Development: x1a0he@outlook.com (LFN2762T4F)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */</string>
|
||||
<key>com.x1a0he.macOS.Adobe-Downloader.helper</key>
|
||||
<dict>
|
||||
<key>PlistName</key>
|
||||
<string>com.x1a0he.macOS.Adobe-Downloader.helper.plist</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SUFeedURL</key>
|
||||
<string>https://raw.githubusercontent.com/X1a0He/Adobe-Downloader/refs/heads/main/appcast.xml</string>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import SwiftUI
|
||||
import Sparkle
|
||||
import Combine
|
||||
import ServiceManagement
|
||||
|
||||
|
||||
private enum AboutViewConstants {
|
||||
@@ -267,6 +268,7 @@ final class GeneralSettingsViewModel: ObservableObject {
|
||||
case connecting
|
||||
case disconnected
|
||||
case checking
|
||||
case needsApproval
|
||||
}
|
||||
|
||||
init(updater: SPUUpdater) {
|
||||
@@ -287,6 +289,8 @@ final class GeneralSettingsViewModel: ObservableObject {
|
||||
self?.helperConnectionStatus = .disconnected
|
||||
case .connecting:
|
||||
self?.helperConnectionStatus = .connecting
|
||||
case .needsApproval:
|
||||
self?.helperConnectionStatus = .needsApproval
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
@@ -966,8 +970,11 @@ struct HelperStatusRow: View {
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
if helperStatus == .installed &&
|
||||
viewModel.helperConnectionStatus != .connected {
|
||||
if viewModel.helperConnectionStatus == .needsApproval {
|
||||
// 打开系统设置让用户批准Helper
|
||||
SMAppService.openSystemSettingsLoginItems()
|
||||
} else if helperStatus == .installed &&
|
||||
viewModel.helperConnectionStatus != .connected {
|
||||
Task {
|
||||
do {
|
||||
try await ModernPrivilegedHelperManager.shared.reconnectHelper()
|
||||
@@ -987,9 +994,9 @@ struct HelperStatusRow: View {
|
||||
}
|
||||
}) {
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "network")
|
||||
Image(systemName: viewModel.helperConnectionStatus == .needsApproval ? "gear" : "network")
|
||||
.font(.system(size: 12))
|
||||
Text("重新连接")
|
||||
Text(viewModel.helperConnectionStatus == .needsApproval ? "打开设置" : "重新连接")
|
||||
.font(.system(size: 13))
|
||||
}
|
||||
.frame(minWidth: 90)
|
||||
@@ -997,7 +1004,7 @@ struct HelperStatusRow: View {
|
||||
.buttonStyle(BeautifulButtonStyle(baseColor: shouldDisableReconnectButton ? Color.gray.opacity(0.6) : Color.blue.opacity(0.8)))
|
||||
.foregroundColor(shouldDisableReconnectButton ? Color.white.opacity(0.8) : .white)
|
||||
.disabled(shouldDisableReconnectButton)
|
||||
.help("尝试重新连接到已安装的 Helper")
|
||||
.help(viewModel.helperConnectionStatus == .needsApproval ? "打开系统设置批准Helper" : "尝试重新连接到已安装的 Helper")
|
||||
}
|
||||
}
|
||||
.task {
|
||||
@@ -1011,13 +1018,13 @@ struct HelperStatusRow: View {
|
||||
case .connecting: return .orange
|
||||
case .disconnected: return .red
|
||||
case .checking: return .orange
|
||||
case .needsApproval: return .yellow
|
||||
}
|
||||
}
|
||||
|
||||
private var shouldDisableReconnectButton: Bool {
|
||||
return helperStatus != .installed ||
|
||||
viewModel.helperConnectionStatus == .connected ||
|
||||
isReinstallingHelper
|
||||
// 只在重新安装Helper时禁用按钮,其他情况都允许用户点击
|
||||
return isReinstallingHelper
|
||||
}
|
||||
|
||||
private var helperStatusBackgroundColor: Color {
|
||||
@@ -1026,6 +1033,7 @@ struct HelperStatusRow: View {
|
||||
case .connecting: return Color.orange.opacity(0.1)
|
||||
case .disconnected: return Color.red.opacity(0.1)
|
||||
case .checking: return Color.orange.opacity(0.1)
|
||||
case .needsApproval: return Color.yellow.opacity(0.1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1035,6 +1043,7 @@ struct HelperStatusRow: View {
|
||||
case .connecting: return String(localized: "正在连接")
|
||||
case .disconnected: return String(localized: "连接断开")
|
||||
case .checking: return String(localized: "检查中")
|
||||
case .needsApproval: return String(localized: "需要批准")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.x1a0he.macOS.Adobe-Downloader.helper</string>
|
||||
<key>MachServices</key>
|
||||
@@ -19,5 +19,5 @@
|
||||
<string>/tmp/com.x1a0he.macOS.Adobe-Downloader.helper.err</string>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/com.x1a0he.macOS.Adobe-Downloader.helper.out</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
Reference in New Issue
Block a user