swift - 如何使用 Swift 2 在 OS X 上删除系统域文件?

标签 swift macos swift2

对于一个开源项目,我们想要创建一个 OS X 卸载程序,它应该能够删除用户系统域 文件。目标是只用 Swift 编写卸载程序。

在我的研究过程中,我发现了使用 NSTask 发送 rm 命令的示例, 或其他人建议使用 SMJobBlessHelperTool 进行身份验证。两者对我来说似乎都不是正确的方法。我是 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

添加新目标

  1. 单击文件 > 新建 > 目标...
  2. 在 OS X 下,选择Application > Command Line Tool
  3. 给你的新目标起个名字,比如 DeleteSystemFile

在左侧的Project Navigator 中,展开DeleteSystemFile 组并单击main.swift 文件。要删除 dummy.txt 文件:

do {
    try NSFileManager.defaultManager().removeItemAtPath("/usr/local/dummy.txt")
} catch {
    print(error)
}

回到第一个目标

现在回到第一个目标 (MyUninstaller) 并添加 DeleteSystemFile 作为目标依赖。

enter image description here

您可以通过 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/

相关文章:

ios - 优先级和背景在 iOS 8 中被弃用

ios媒体选择器仅显示白屏/卡住

swift - 如何在swift中比较CGPoints?

macos - 如何将 NSObjectController 与 Core Data 结合使用?

swift - 对成员 'close()' 的引用不明确

ios - 使其透明后恢复默认导航栏

swift - 在 Swift 2 中连接字符串的最快方法

arrays - 如何使用 Swift 将 Array.count 结果移动 -1?

swift - NSButton 以编程方式推上推下类型

ios - 使用 UIPanGestureRecognizer 计算轻弹后 UIView 的最终位置