对于一个开源项目,我们想要创建一个 OS X 卸载程序,它应该能够删除用户 和系统域 文件。目标是只用 Swift 编写卸载程序。
在我的研究过程中,我发现了使用 NSTask
发送 rm
命令的示例,
或其他人建议使用 SMJobBless
和 HelperTool
进行身份验证。两者对我来说似乎都不是正确的方法。我是 OS X 开发的新手,所以我很难说哪种方法是完成任务的正确方法。
我正在寻找 Swift 2 中的示例,它允许用户验证和删除用户 和系统域 文件。如果有人能帮助我,我将不胜感激。
最佳答案
在试用了几个小时 SecurityFoundation
之后,我发现它对我来说太复杂了。另外,文档已过时。灵感来自 this question .您可以通过 AppleScript 完成。
您需要将卸载程序分为两部分:默认目标 删除用户文件和一个助手删除系统文件(当然有升级的权限)。
选项1
您可以将该帮助程序编写为 shell 脚本并将其作为资源包括在内:
文件delete_system_file.sh
:
#!/bin/bash
rm -f /usr/local/dummy.txt
在您的应用中:
let helper = NSBundle.mainBundle().pathForResource("delete_system_file", ofType: "sh")!
let script = "do shell script \"\(helper)\" with administrator privileges"
if let appleScript = NSAppleScript(source: script) {
var error: NSDictionary? = nil
appleScript.executeAndReturnError(&error)
if error != nil {
print(error!)
} else {
print("Deleted /usr/local/dummy.txt")
}
} else {
print("Cannot create the AppleScript object")
}
选项 2
您可以通过向您的项目添加一个新目标来完全在 Swift 中完成此操作。假设您的第一个目标名为 MyUninstaller
。
添加新目标
- 单击
文件 > 新建 > 目标...
- 在 OS X 下,选择
Application > Command Line Tool
- 给你的新目标起个名字,比如
DeleteSystemFile
在左侧的Project Navigator 中,展开DeleteSystemFile
组并单击main.swift
文件。要删除 dummy.txt
文件:
do {
try NSFileManager.defaultManager().removeItemAtPath("/usr/local/dummy.txt")
} catch {
print(error)
}
回到第一个目标
现在回到第一个目标 (MyUninstaller
) 并添加 DeleteSystemFile
作为目标依赖。
您可以通过 AppleScript 调用以升级权限运行第二个目标:
let helper = NSBundle.mainBundle().pathForAuxiliaryExecutable("DeleteSystemFile")!
let script = "do shell script \"\(helper)\" with administrator privileges"
if let appleScript = NSAppleScript(source: script) {
var error: NSDictionary? = nil
appleScript.executeAndReturnError(&error)
if error != nil {
print(error!)
} else {
print("Deleted /usr/local/dummy.txt")
}
} else {
print("Cannot create the AppleScript object")
}
选项3
使用 SMJobBless
,这是 Apple 推荐的运行特权助手的方式:
import SecurityFoundation
import ServiceManagement
// 1. Obtain an Authorization Reference
// You can do this at the beginning of the app. It has no extra rights until later
var authRef: AuthorizationRef = nil
let status = AuthorizationCreate(nil, nil, [.Defaults], &authRef)
// There's really no reason for this to fail, but we should check or completeness
guard status == errAuthorizationSuccess else {
fatalError("Cannot create AuthorizationRef: \(status)")
}
// 2. Ask user for admin privilege
var authItem = AuthorizationItem(name: kSMRightBlessPrivilegedHelper, valueLength: 0, value: nil, flags: 0)
var authRights = AuthorizationRights(count: 1, items: &authItem)
let flags: AuthorizationFlags = [.Defaults, .InteractionAllowed, .ExtendRights]
let status2 = AuthorizationCopyRights(authRef, &authRights, nil, flags, nil)
if status2 != errAuthorizationSuccess {
// Can't obtain admin privilege, handle error
print("Cannot obtain admin privilege")
}
// 3. Run the privileged helper
// This label must be globally unique and matches the product name of your helper
let label = "com.myCompany.myApp.myAppPrivilgedHelper"
var error: CFError? = nil
let result = withUnsafeMutablePointer(&error) {
SMJobBless(kSMDomainSystemLaunchd, label, authRef, UnsafeMutablePointer($0))
}
if !result {
print(error!)
}
// 4. Release the Authorization Reference
AuthorizationFree(authRef, [.Defaults])
这涉及一些设置,您可以在 SMJobBless
的文档中阅读相关信息.还有一个 sample project in ObjC .
免责声明:由于我没有个人签名 key ,因此无法一直进行测试。我可以去掉上面的第 2 节,但为了完整起见将其包含在此处——示例项目就是这样做的。
关于swift - 如何使用 Swift 2 在 OS X 上删除系统域文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36957837/