I've got a Swift app that looks at a timeline of occurences. I'd like to be able pop up the Calendar.app, focused on the date a user has selected within the app.
Nothing fancy -- no data comes back from Calendar...
Using ScriptingBridge, I could imagine just running [on the CalendarApplication that is returned from let calendarApp = SBApplication(url: url)]
the method:
- (void) viewCalendarAtDate:(NSDate *)at;
or perhaps passing a string to the following script:
on showDateInCalendar(s as string)
tell application "Calendar"
view calendar at date s
end tell
end showDateInCalendar
There seem to be lebenty different ways to approach this problem, but they all seem documented in the style of you-have-to-have-understood-this-once-before-you-can-understand-it-again.
Any suggestions, or am I doomed to the command line and Python scripts?
Richard
You’re right that there’s a bunch of different ways to do this. The two that I recommend are:
, if you want to make a general script attachment mechanismNSUserScriptTask
, if you want lots of controlNSAppleScript
The former has the advantage that it’s compatible with the App Sandbox.
Implementing the latter is a bit tricky if you’re not deeply familiar with the whole history of Apple events and AppleScript. Here’s some snippets to get you started.
First, here’s how to construct an
NSAppleScript
from source.
var script: NSAppleScript = {
let script = NSAppleScript(source: """
on displayMessage(message)
tell application "Finder"
activate
display dialog message buttons {"OK"} default button "OK"
end tell
end displayMessage
"""
)!
let success = script.compileAndReturnError(nil)
assert(success)
return script
}()
Note that I’m storing this in a property. I do this because compiling scripts is relatively expensive, so it’s best to do it once and cache the results.
Here’s how how run that the
displayMessage
handler in that script, passing it a parameter.
let parameters = NSAppleEventDescriptor.list()
parameters.insert(NSAppleEventDescriptor(string: "Hello Cruel World!"), at: 0)
let event = NSAppleEventDescriptor(
eventClass: AEEventClass(kASAppleScriptSuite),
eventID: AEEventID(kASSubroutineEvent),
targetDescriptor: nil,
returnID: AEReturnID(kAutoGenerateReturnID),
transactionID: AETransactionID(kAnyTransactionID)
)
event.setDescriptor(NSAppleEventDescriptor(string: "displayMessage"), forKeyword: AEKeyword(keyASSubroutineName))
event.setDescriptor(parameters, forKeyword: AEKeyword(keyDirectObject))
var error: NSDictionary? = nil
let result = self.script.executeAppleEvent(event, error: &error) as NSAppleEventDescriptor?
There’s some tricky things to note here:
In line 2 I pass 0 to the
parameter, which indicates that the value should be added to the end of the list.at
There are lots of type conversions (lines 5, 6, 8 and 9) because Swift is importing the constants with the wrong type (because they’re anonymous enums in the Objective-C header).
In line 15 I cast the result of
toexecuteAppleEvent(_:error:)
because of an annotation bug in the Objective-C header. The method is documented to returnNSAppleEventDescriptor?
on error but the header doesn’t indicate that (r. 38702068).nil
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"