feat: Add Helper to solve permission issues.

This commit is contained in:
X1a0He
2024-11-13 08:37:50 +08:00
parent fc231243d1
commit 1546dd6af4
11 changed files with 541 additions and 3 deletions

View File

@@ -7,10 +7,34 @@
objects = {
/* Begin PBXBuildFile section */
3C60E1C32CE3AA1B00600C07 /* com.x1a0he.macOS.Adobe-Downloader.helper in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3C60E16D2CE3A6CB00600C07 /* com.x1a0he.macOS.Adobe-Downloader.helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
3CB9FF092CDBAEF200D7A58B /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 3CB9FF082CDBAEF200D7A58B /* Sparkle */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
3C60E16B2CE3A6CB00600C07 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
3C60E1C22CE3AA0B00600C07 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = Contents/Library/LaunchServices;
dstSubfolderSpec = 1;
files = (
3C60E1C32CE3AA1B00600C07 /* com.x1a0he.macOS.Adobe-Downloader.helper in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
3C60E16D2CE3A6CB00600C07 /* com.x1a0he.macOS.Adobe-Downloader.helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "com.x1a0he.macOS.Adobe-Downloader.helper"; sourceTree = BUILT_PRODUCTS_DIR; };
3CCC3AE02CC67B8F006E22B4 /* Adobe Downloader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Adobe Downloader.app"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@@ -25,6 +49,11 @@
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
3C60E16E2CE3A6CB00600C07 /* AdobeDownloaderHelperTool */ = {
isa = PBXFileSystemSynchronizedRootGroup;
path = AdobeDownloaderHelperTool;
sourceTree = "<group>";
};
3CCC3AE22CC67B8F006E22B4 /* Adobe Downloader */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
@@ -41,6 +70,13 @@
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */
3C60E16A2CE3A6CB00600C07 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
3CCC3ADD2CC67B8F006E22B4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -56,6 +92,7 @@
isa = PBXGroup;
children = (
3CCC3AE22CC67B8F006E22B4 /* Adobe Downloader */,
3C60E16E2CE3A6CB00600C07 /* AdobeDownloaderHelperTool */,
3CCC3AE12CC67B8F006E22B4 /* Products */,
3CCC3B112CC67F7A006E22B4 /* Localizables */,
);
@@ -65,6 +102,7 @@
isa = PBXGroup;
children = (
3CCC3AE02CC67B8F006E22B4 /* Adobe Downloader.app */,
3C60E16D2CE3A6CB00600C07 /* com.x1a0he.macOS.Adobe-Downloader.helper */,
);
name = Products;
sourceTree = "<group>";
@@ -72,6 +110,28 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
3C60E16C2CE3A6CB00600C07 /* AdobeDownloaderHelperTool */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3C60E1732CE3A6CB00600C07 /* Build configuration list for PBXNativeTarget "AdobeDownloaderHelperTool" */;
buildPhases = (
3C60E1692CE3A6CB00600C07 /* Sources */,
3C60E16A2CE3A6CB00600C07 /* Frameworks */,
3C60E16B2CE3A6CB00600C07 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
3C60E16E2CE3A6CB00600C07 /* AdobeDownloaderHelperTool */,
);
name = AdobeDownloaderHelperTool;
packageProductDependencies = (
);
productName = AdobeDownloaderHelperTool;
productReference = 3C60E16D2CE3A6CB00600C07 /* com.x1a0he.macOS.Adobe-Downloader.helper */;
productType = "com.apple.product-type.tool";
};
3CCC3ADF2CC67B8F006E22B4 /* Adobe Downloader */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3CCC3B052CC67B91006E22B4 /* Build configuration list for PBXNativeTarget "Adobe Downloader" */;
@@ -79,6 +139,7 @@
3CCC3ADC2CC67B8F006E22B4 /* Sources */,
3CCC3ADD2CC67B8F006E22B4 /* Frameworks */,
3CCC3ADE2CC67B8F006E22B4 /* Resources */,
3C60E1C22CE3AA0B00600C07 /* CopyFiles */,
);
buildRules = (
);
@@ -106,6 +167,9 @@
LastSwiftUpdateCheck = 1610;
LastUpgradeCheck = 1610;
TargetAttributes = {
3C60E16C2CE3A6CB00600C07 = {
CreatedOnToolsVersion = 16.1;
};
3CCC3ADF2CC67B8F006E22B4 = {
CreatedOnToolsVersion = 16.0;
};
@@ -129,6 +193,7 @@
projectRoot = "";
targets = (
3CCC3ADF2CC67B8F006E22B4 /* Adobe Downloader */,
3C60E16C2CE3A6CB00600C07 /* AdobeDownloaderHelperTool */,
);
};
/* End PBXProject section */
@@ -144,6 +209,13 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
3C60E1692CE3A6CB00600C07 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
3CCC3ADC2CC67B8F006E22B4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -154,6 +226,63 @@
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
3C60E1712CE3A6CB00600C07 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = AdobeDownloaderHelperTool/AdobeDownloaderHelperTool.entitlements;
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = AdobeDownloaderHelperTool/Info.plist;
LOCALIZATION_PREFERS_STRING_CATALOGS = NO;
MACOSX_DEPLOYMENT_TARGET = 15.1;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = (
"-sectcreate",
__TEXT,
__info_plist,
"$(SRCROOT)/AdobeDownloaderHelperTool/Info.plist",
"-sectcreate",
__TEXT,
__launchd_plist,
"$(SRCROOT)/AdobeDownloaderHelperTool/Launchd.plist",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.x1a0he.macOS.Adobe-Downloader.helper";
PRODUCT_NAME = "com.x1a0he.macOS.Adobe-Downloader.helper";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
3C60E1722CE3A6CB00600C07 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = AdobeDownloaderHelperTool/AdobeDownloaderHelperTool.entitlements;
CODE_SIGN_STYLE = Automatic;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = AdobeDownloaderHelperTool/Info.plist;
LOCALIZATION_PREFERS_STRING_CATALOGS = NO;
MACOSX_DEPLOYMENT_TARGET = 15.1;
OTHER_LDFLAGS = (
"-sectcreate",
__TEXT,
__info_plist,
"$(SRCROOT)/AdobeDownloaderHelperTool/Info.plist",
"-sectcreate",
__TEXT,
__launchd_plist,
"$(SRCROOT)/AdobeDownloaderHelperTool/Launchd.plist",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.x1a0he.macOS.Adobe-Downloader.helper";
PRODUCT_NAME = "com.x1a0he.macOS.Adobe-Downloader.helper";
SWIFT_VERSION = 5.0;
};
name = Release;
};
3CCC3B032CC67B91006E22B4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -316,7 +445,6 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_ENTITLEMENTS = "Adobe Downloader/Adobe Downloader.entitlements";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 120;
@@ -345,6 +473,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
3C60E1732CE3A6CB00600C07 /* Build configuration list for PBXNativeTarget "AdobeDownloaderHelperTool" */ = {
isa = XCConfigurationList;
buildConfigurations = (
3C60E1712CE3A6CB00600C07 /* Debug */,
3C60E1722CE3A6CB00600C07 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
3CCC3ADB2CC67B8F006E22B4 /* Build configuration list for PBXProject "Adobe Downloader" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@@ -14,6 +14,11 @@
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>AdobeDownloaderHelperTool.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>

View File

@@ -50,6 +50,7 @@ struct Adobe_DownloaderApp: App {
UserDefaults.standard.set(downloadsURL.path, forKey: "defaultDirectory")
}
}
PrivilegedHelperManager.shared.checkInstall()
}
var body: some Scene {

View File

@@ -0,0 +1,241 @@
//
// Untitled.swift
// Adobe Downloader
//
// Created by X1a0He on 11/12/24.
//
import AppKit
import Cocoa
import ServiceManagement
@objcMembers
class PrivilegedHelperManager: NSObject {
enum HelperStatus {
case installed
case noFound
case needUpdate
}
static let shared = PrivilegedHelperManager()
static let machServiceName = "com.x1a0he.macOS.Adobe-Downloader.helper"
var connectionSuccessBlock: (() -> Void)?
private var useLegacyInstall = false
override init() {
super.init()
initAuthorizationRef()
}
func checkInstall() {
getHelperStatus { [weak self] status in
guard let self = self else {return}
switch status {
case .noFound:
if #available(macOS 13, *) {
let url = URL(string: "/Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist")!
let status = SMAppService.statusForLegacyPlist(at: url)
if status == .requiresApproval {
let alert = NSAlert()
let notice = "Adobe Downloader 需要通过后台Daemon进程来安装与移动文件请在\"系统偏好设置->登录项->允许在后台 中\"允许当前App"
let addition = "如果在设置里没找到当前App可以尝试重置守护程序"
alert.messageText = notice + "\n" + addition
alert.addButton(withTitle: "打开系统登录项设置")
alert.addButton(withTitle: "重置守护程序")
if alert.runModal() == .alertFirstButtonReturn {
SMAppService.openSystemSettingsLoginItems()
} else {
self.removeInstallHelper()
}
}
}
fallthrough
case .needUpdate:
if Thread.isMainThread {
self.notifyInstall()
} else {
DispatchQueue.main.async {
self.notifyInstall()
}
}
case .installed:
self.connectionSuccessBlock?()
}
}
}
private func initAuthorizationRef() {
var authRef: AuthorizationRef?
let status = AuthorizationCreate(nil, nil, AuthorizationFlags(), &authRef)
if status != OSStatus(errAuthorizationSuccess) {
return
}
}
private func installHelperDaemon() -> DaemonInstallResult {
defer {
}
var authRef: AuthorizationRef?
var authStatus = AuthorizationCreate(nil, nil, [], &authRef)
guard authStatus == errAuthorizationSuccess else {
return .authorizationFail
}
var authItem = AuthorizationItem(name: (kSMRightBlessPrivilegedHelper as NSString).utf8String!, valueLength: 0, value: nil, flags: 0)
var authRights = withUnsafeMutablePointer(to: &authItem) { pointer in
AuthorizationRights(count: 1, items: pointer)
}
let flags: AuthorizationFlags = [[], .interactionAllowed, .extendRights, .preAuthorize]
authStatus = AuthorizationCreate(&authRights, nil, flags, &authRef)
defer {
if let ref = authRef {
AuthorizationFree(ref, [])
}
}
guard authStatus == errAuthorizationSuccess else {
return .getAdminFail
}
var error: Unmanaged<CFError>?
let helperURL = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LaunchServices/" + PrivilegedHelperManager.machServiceName)
if SMJobBless(kSMDomainSystemLaunchd, PrivilegedHelperManager.machServiceName as CFString, authRef, &error) == false {
if let blessError = error?.takeRetainedValue() {
let nsError = blessError as Error as NSError
NSAlert.alert(with: "SMJobBless failed with error: \(blessError)\nError domain: \(nsError.domain)\nError code: \(nsError.code)\nError description: \(nsError.localizedDescription)\nError user info: \(nsError.userInfo)")
return .blessError(nsError.code)
}
}
return .success
}
private func getHelperStatus(callback: @escaping ((HelperStatus) -> Void)) {
var called = false
let reply: ((HelperStatus) -> Void) = {
status in
if called {return}
called = true
callback(status)
}
let helperURL = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LaunchServices/" + PrivilegedHelperManager.machServiceName)
guard
let helperBundleInfo = CFBundleCopyInfoDictionaryForURL(helperURL as CFURL) as? [String: Any],
let helperVersion = helperBundleInfo["CFBundleShortVersionString"] as? String else {
reply(.noFound)
return
}
let helperFileExists = FileManager.default.fileExists(atPath: "/Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)")
if !helperFileExists {
reply(.noFound)
return
}
reply(.installed)
}
}
extension PrivilegedHelperManager {
private func notifyInstall() {
if useLegacyInstall {
useLegacyInstall = false
legacyInstallHelper()
checkInstall()
return
}
let result = installHelperDaemon()
if case .success = result {
checkInstall()
return
}
result.alertAction()
let ret = result.shouldRetryLegacyWay()
useLegacyInstall = ret.0
let isCancle = ret.1
if !isCancle, useLegacyInstall {
checkInstall()
} else if isCancle, !useLegacyInstall {
NSAlert.alert(with: "获取管理员授权失败,用户主动取消授权!")
}
}
}
private enum DaemonInstallResult {
case success
case authorizationFail
case getAdminFail
case blessError(Int)
var alertContent: String {
switch self {
case .success:
return ""
case .authorizationFail: return "Failed to create authorization!"
case .getAdminFail: return "The user actively cancels the authorization, Failed to get admin authorization! "
case let .blessError(code):
switch code {
case kSMErrorInternalFailure: return "blessError: kSMErrorInternalFailure"
case kSMErrorInvalidSignature: return "blessError: kSMErrorInvalidSignature"
case kSMErrorAuthorizationFailure: return "blessError: kSMErrorAuthorizationFailure"
case kSMErrorToolNotValid: return "blessError: kSMErrorToolNotValid"
case kSMErrorJobNotFound: return "blessError: kSMErrorJobNotFound"
case kSMErrorServiceUnavailable: return "blessError: kSMErrorServiceUnavailable"
case kSMErrorJobMustBeEnabled: return "Adobe Downloader Helper is disabled by other process. Please run \"sudo launchctl enable system/\(PrivilegedHelperManager.machServiceName)\" in your terminal. The command has been copied to your pasteboard"
case kSMErrorInvalidPlist: return "blessError: kSMErrorInvalidPlist"
default:
return "bless unknown error:\(code)"
}
}
}
func shouldRetryLegacyWay() -> (Bool, Bool) {
switch self {
case .success: return (false, false)
case let .blessError(code):
switch code {
case kSMErrorJobMustBeEnabled:
return (false, false)
default:
return (true, false)
}
case .authorizationFail:
return (true, false)
case .getAdminFail:
return (false, true)
}
}
func alertAction() {
switch self {
case let .blessError(code):
switch code {
case kSMErrorJobMustBeEnabled:
NSPasteboard.general.clearContents()
NSPasteboard.general.setString("sudo launchctl enable system/\(PrivilegedHelperManager.machServiceName)", forType: .string)
default:
break
}
default:
break
}
}
}
extension NSAlert {
static func alert(with text: String) {
let alert = NSAlert()
alert.messageText = text
alert.alertStyle = .warning
alert.addButton(withTitle: NSLocalizedString("OK", comment: ""))
alert.runModal()
}
}

View File

@@ -0,0 +1,95 @@
//
// PrivilegedHelperManagerLegacy.swift
// Adobe Downloader
//
// Created by X1a0He on 11/13/24.
//
import Cocoa
extension PrivilegedHelperManager {
func getInstallScript() -> String {
let appPath = Bundle.main.bundlePath
let bash = """
#!/bin/bash
set -e
plistPath=/Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist
rm -rf /Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)
if [ -e ${plistPath} ]; then
launchctl unload -w ${plistPath}
rm ${plistPath}
fi
launchctl remove \(PrivilegedHelperManager.machServiceName) || true
mkdir -p /Library/PrivilegedHelperTools/
rm -f /Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)
cp "\(appPath)/Contents/Library/LaunchServices/\(PrivilegedHelperManager.machServiceName)" "/Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)"
echo '
<?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>
<key>Label</key>
<string>\(PrivilegedHelperManager.machServiceName)</string>
<key>MachServices</key>
<dict>
<key>\(PrivilegedHelperManager.machServiceName)</key>
<true/>
</dict>
<key>Program</key>
<string>/Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)</string>
<key>ProgramArguments</key>
<array>
<string>/Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)</string>
</array>
</dict>
</plist>
' > ${plistPath}
launchctl load -w ${plistPath}
"""
return bash
}
func runScriptWithRootPermission(script: String) {
let tmpPath = FileManager.default.temporaryDirectory.appendingPathComponent(NSUUID().uuidString).appendingPathExtension("sh")
do {
try script.write(to: tmpPath, atomically: true, encoding: .utf8)
let appleScriptStr = "do shell script \"bash \(tmpPath.path) \" with administrator privileges"
let appleScript = NSAppleScript(source: appleScriptStr)
var dict: NSDictionary?
if appleScript?.executeAndReturnError(&dict) == nil {
} else {
}
} catch let err {
print("legacyInstallHelper create script fail: \(err)")
}
try? FileManager.default.removeItem(at: tmpPath)
}
func legacyInstallHelper() {
defer {
Thread.sleep(forTimeInterval: 1)
}
let script = getInstallScript()
runScriptWithRootPermission(script: script)
}
func removeInstallHelper() {
defer {
Thread.sleep(forTimeInterval: 5)
}
let script = """
/bin/launchctl remove \(PrivilegedHelperManager.machServiceName) || true
/usr/bin/killall -u root -9 \(PrivilegedHelperManager.machServiceName)
/bin/rm -rf /Library/LaunchDaemons/\(PrivilegedHelperManager.machServiceName).plist
/bin/rm -rf /Library/PrivilegedHelperTools/\(PrivilegedHelperManager.machServiceName)
"""
runScriptWithRootPermission(script: script)
}
}

View File

@@ -2,17 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>SMPrivilegedExecutables</key>
<dict>
<key>com.x1a0he.macOS.Adobe-Downloader.helper</key>
<string>identifier "com.x1a0he.macOS.Adobe-Downloader.helper" and anchor apple generic</string>
</dict>
<key>SUFeedURL</key>
<string>https://raw.githubusercontent.com/X1a0He/Adobe-Downloader/refs/heads/main/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>gYylad3ybfiyK5ZTS3xRrw+3c/8063mpXdQnPpMB86Q=</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>

View File

@@ -0,0 +1,5 @@
<?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/>
</plist>

View File

@@ -0,0 +1,20 @@
<?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>
<key>CFBundleIdentifier</key>
<string>com.x1a0he.macOS.Adobe-Downloader.helper</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>1.0</string>
<key>CFBundleName</key>
<string>com.x1a0he.macOS.Adobe-Downloader.helper</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>100</string>
<key>SMAuthorizedClients</key>
<array>
<string>identifier "com.x1a0he.macOS.Adobe-Downloader" and anchor apple generic</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,15 @@
<?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>
<key>Label</key>
<string>com.x1a0he.macOS.Adobe-Downloader.helper</string>
<key>MachServices</key>
<dict>
<key>com.x1a0he.macOS.Adobe-Downloader.helper</key>
<true/>
</dict>
<key>AssociatedBundleIdentifiers</key>
<string>com.x1a0he.macOS.Adobe-Downloader</string>
</dict>
</plist>

View File

@@ -0,0 +1,11 @@
//
// main.swift
// AdobeDownloaderHelperTool
//
// Created by X1a0He on 11/12/24.
//
import Foundation
print("Hello, World!")

View File

@@ -151,6 +151,9 @@
}
}
}
},
"OK" : {
},
"Setup 组件未处理" : {
"localizations" : {