After a couple hours playing around with SecurityFoundation
, I found it to be too complex for my taste. Plus, the documentation is outdated. Inspired by this question. You can do it via AppleScript.
You need to divide your uninstaller into 2 parts: a default target
to delete user files and a helper to delete system files (with escalated privileges of course).
Option 1
You can write that helper as a shell script and include that as a resource:
File delete_system_file.sh
:
#!/bin/bash
rm -f /usr/local/dummy.txt
In your app:
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")
}
Option 2
You can do this entirely in Swift by adding a new target to your project. Assuming your first target is called MyUninstaller
.
Add a new target
- Click
File > New > Target...
- Under OS X, select
Application > Command Line Tool
- Give your new target a name, say
DeleteSystemFile
In the Project Navigator on the left, expand the DeleteSystemFile
group and click on the main.swift
file. To delete the dummy.txt
file:
do {
try NSFileManager.defaultManager().removeItemAtPath("/usr/local/dummy.txt")
} catch {
print(error)
}
Back to the first target
Now go back to the first target (MyUninstaller
) and add DeleteSystemFile
as a Target Dependancy.

You can run the second target with escalated privileges by calling it through 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")
}
Option 3
Use SMJobBless
, which is the Apple's recommended way of running privileged helper:
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])
This involves some setup, which you can read about in the documentation for SMJobBless
. There's also a sample project in ObjC.
Disclaimer: I could not test this all the way as I don't have a personal signing key. I could do away with section 2 from above, but included it here for completeness--that's how the sample project does it.