On this page
Background
I’ve been working on a small Mac app that runs an AppleScript to pull data out of OmniFocus and visualize it. Problem: it kept coming back with no data.
The cause
The key step — running the AppleScript that actually fetches the data — was returning nothing.
set theProgressDetail to ""
tell application "OmniFocus"
tell front document
set theModifiedProjects to every flattened project
repeat with a from 1 to length of theModifiedProjects
set theCompletedTasks to (every flattened task of (item a of theModifiedProjects) where its number of tasks = 0)
if theCompletedTasks is not equal to {} then
repeat with b from 1 to length of theCompletedTasks
set theProgressDetail to theProgressDetail & completion date of (item b of theCompletedTasks) & return
end repeat
end if
end repeat
set theInboxCompletedTasks to (every inbox task where its number of tasks = 0)
repeat with d from 1 to length of theInboxCompletedTasks
set theProgressDetail to theProgressDetail & completion date of (item d of theInboxCompletedTasks) & return
end repeat
end tell
end tell
display dialog theProgressDetail
return theProgressDetail
In Cocoa, the script is executed like this:
let myAppleScript = "I am a piece of applescript"
if let scriptObject = NSAppleScript(source: myAppleScript) {
var error: NSDictionary?
let output = scriptObject.executeAndReturnError(&error)
}
Whether I ran the app in Debug from Xcode or archived and ran the built executable, the script always failed. The error:
"NSAppleScriptErrorMessage" : "Not authorized to send Apple events to OmniFocus."
Clearly: the app didn’t have permission to send Apple events to OmniFocus.
Permission gating for Apple events was introduced in macOS Mojave. Apple tightened the permission model and now requires developers to explicitly tell the user what their app intends to do. iOS devs will know the drill — accessing the camera, the photo library, or FaceID all require explicit declarations in Info.plist.
On macOS Mojave, the equivalent for Apple events is a new key — NSAppleEventsUsageDescription — which you have to add to your plist with a clear description of why the app needs to send Apple events. This was covered in WWDC 2018 session “Your Apps and the Future of macOS Security”: every Cocoa app that sends Apple events to other apps is affected. This is what’s called AppleEvent sandboxing. If you don’t add the key, the app silently lacks permission and the user is never prompted — which is exactly the symptom I hit.
So: add NSAppleEventsUsageDescription to Info.plist with an actual usage description.

Launch the app again and you get a permission prompt:

The AppleScript-running API blocks synchronously waiting for the authorization result. Once the user grants permission, the app gets its data.
