Take the 2-minute tour ×

so I'm working on my little Mac app, and I want control Adium with it. AppleScript is very cool:

tell application "Adium"
    go away with message "Zoned in for Maths."
end tell

(If you're wondering what this is supposed to be. In order to actually start studying I need to create application that will change my IM status, of course ... )

I tried it in Script Editor, it worked, and I'm pretty sure that calling AppleScript from Cocoa application is gonna be trivial.


Is AppleScript the only way? I don't mind using AppleScript, but it looks like programming for noobs.

Is there any way to do the same thing as above code does without AppleScript, in plain Objective-C somehow?

Would someone point me to relevant documentation? I tried Google but it was like I don't even know what I'm looking for.


share|improve this question
add comment

3 Answers

up vote 10 down vote accepted

Interprocess communication in Mac OS X is done by something called Apple Events. AppleScript is one way to send and receive Apple Events to other applications.

Therefore, you just need to construct Apple Events directly and send it to the other app, from Objective-C or whatever other language.

Honestly, if you just want to change the status of Adium, it's easiest to use NSAppleScript and pass what you just wrote, from inside Objective-C.

If you want to do more complicated stuff, Scripting Bridge is the way to go. This mechanism maps Apple Events' object hierarchy to Objective-C's object hierarchy.

If you think that's still a newbie's way, you should directly create Apple Events via NSAppleEventDescriptor.

Well, some of us old timers think using Objective-C is a sissy's way. If you think so, you should directly deal with C structs called AEDesc and such. See Apple Events programming guide and the corresponding reference.

However, I think people who use OS X are all noobs. Real people use Linux.

My dad would say people who use GUI are just too spoiled.

The point is, you don't have to care whether it is a newbie's way or not. The important thing is whether you can achieve what you want. In fact, AppleScript is a very powerful, dynamical language, whose power is not well appreciated by many people. Read AppleScript language guide and be surprised.

share|improve this answer
That's one amazing answer. I'm not exactly this hacker-wannabe who's ashamed of using GUI. Maybe I made it sound like that. Actually, the reason why I didn't want to use AppleScript is because it hides things that I'm interested in. It hides how it works inside and that's what I'm very curious about. Thanks for the links, I think this is exactly what I was looking for! –  Vojto Dec 11 '10 at 11:14
AppleScript is in fact a very, very powerful language. It's just that most people don't notice. Read developer.apple.com/library/mac/#documentation/AppleScript/… . –  Yuji Dec 11 '10 at 11:17
AppleScript is compiled down to byte codes. Do you know how AppleScript Editor do the syntax coloring? It first compiles it, and then it de-compiles the resulting byte code, and then the syntax coloring is trivial. In any case, most of the time is spent by the heavy machinery of the inter-process communication when you drive other apps. I don't think the choice of programming language matters here. –  Yuji Dec 11 '10 at 11:59
Also, don't be excited that ObjC is a compiled language... that shows how young you are. Methods are dispatched at run time in Objective-C, in contrast to C++ where it's mostly determined at the compile time. So Objective-C was thought of as a slow, scripting-like language! –  Yuji Dec 11 '10 at 12:03
Everyone should trust @Philip ... I don't really use AppleScript in full. How do you think of ObjC-AppScript appscript.sourceforge.net/objc-appscript/index.html ? –  Yuji Dec 13 '10 at 14:44
show 5 more comments

The simplest way would be to use NSAppleScript

NSAppleScript *script = [[NSAppleScript alloc] 
    initWithSource:@"tell application \"Adium\" to go away with message \"Zoned in for Maths.\""

For a more powerful way of accessing scripting, use Scripting Bridge. Scripting Bridge requires at least the 10.5 SDK. You first need to prepare your app.

  1. Use the sdef and sdp command line utilities to generating header files for the applications you wish to control (see "Preparing to Code" for details).
  2. Add the generated header to your project.
  3. Add the ScriptingBridge framework to your project. After that, you can use Objective-C calls to control the other application.

After that, you can use Objective-C to send scripting commands to the application.

AdiumApplication *adium = [SBApplication applicationWithBundleIdentifier:@"com.adiumX.adiumX"];
for (AdiumAccount* acct in [adium accounts]) {
    [acct goAwayWithMessage:(AdiumRichText *)@"Zoned in for Maths."];

Status messages are Adium's rich text type (which is NSTextStorage under the hood), but it's convertable from plain text, so passing an NSString rather than a true AdiumRichText should work fine.

There are a few hoops to jump through. For example, you can't create scripting objects in the target application by using its ObjC classes directly; you must use classForScriptingClass: to get the class, which you can then use to create objects as normal (i.e. alloc and init, initWithProperties &c.).

// creating an AdiumContactGroup
NSDictionary *props = [NSDictionary 
AdiumContactGroup *mathies= [[[[adium classForScriptingClass:@"contact group"] alloc] 
if (mathies) {
    [[adium contactGroups] addObject:mathies];

Note that other languages (such as Python and Ruby) also have Scripting bindings.

share|improve this answer
+1 for noting the hoops that Scripting Bridge has. The show-stopping problem of Scripting Bridge comes in [[adium contactGroups] addObject:mathies];: If an application doesn't have a public container (SBElementArray) in which to place the newly created object, you can't use it. All truly useful functionality comes with there being a public container. A lot of applications are not built this way (Adobe Photoshop, which I script regularly, comes to mind here), and runs completely against how Applescript works in its native form. –  Philip Regan Dec 13 '10 at 15:04
add comment

Others have mentioned sending full Applescript or using the Scripting Bridge. A third choice is to use Appscript which is also available for Python and Ruby. It is a little cleaner (IMO) than using the Scripting Bridge in some ways. And definitely easier. Although in other ways Scripting Bridge is better. It also has the advantage of an application called ASTranslate which will translate most Applescript calls into Appscript. Here's the Appscript for your little Applescript example.

ADApplication *adium = [ADApplication applicationWithName: @"Adium"];
ADGoAwayCommand *cmd = [[adium goAway] withMessage: @"Zoned in for Maths."];
id result = [cmd send];
share|improve this answer
Just a note since I saw something in the other comments. There's an XCode project that comes with Appscript. Just select your OS, build, and then copy Appscript.framework to ~/Library/Frameworks. –  Clark Dec 15 '10 at 0:51
add comment

Your Answer


