Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute AppleScript file in Mac app?

I'm looking for a way to execute an Applescript file from within a Mac App. I've made previous mac applications that use NSAppleScript *script = [[NSAppleScript alloc] initWithSource: @"MY_CODE"]];, but my applescript is quite lengthy and I'd like to just be able to reference that file as part of my project, and pipe in the contents of it (or just directly execute the file from within my app).

Thank you!

like image 233
Connor Avatar asked May 12 '13 01:05

Connor


2 Answers

To run user-supplied AppleScripts outside the sandbox (10.8+), use NSUserAppleScriptTask

To run .scpt files embedded in your application bundle, or user-supplied scripts in 10.7 or earlier, use NSAppleScript.

NSUserAppleScriptTask and NSAppleScript are both a bit lame, mind you. Neither provides automatic data conversion between Cocoa and AS types, which means a lot of manual mucking with NSAppleEventDescriptors to pass parameters and results. NSAppleScript instances provide partial persistency support: the script's properties retain state across multiple handlers calls, but there's no way to save the altered script back to disk so any changes are lost once it's dealloced. And NSUSerAppleScriptTask is a strictly one-shot affair, so script state doesn't persist at all between calls.

For deeper integration between embedded AppleScript and ObjC code within your app bundle, use AppleScriptObjC (10.6+):

  • 10.6 Release Notes
  • AppleScriptObjC Explored
  • MacScripter forum
  • applescript-objc

ASOC is a two-way bridge similar to PyObjC or RubyCocoa, allowing you write your AppleScript code within script objects that then appear to your ObjC code as regular Cocoa classes, allowing ObjC code to call AS handlers and AS code to call ObjC methods. Common ObjC and AS types (ints, doubles, NSStrings, NSArrays, etc) are automatically wrapped/converted when crossing the bridge, so requires no additional work other an occasional cast on the AS side.

ASOC is not perfect (Apple's own docs suck, bridging isn't toll-free, and glitches aren't unknown), but for interacting with scriptable apps from ObjC it is the best of an otherwise rather rubbish set of choices.

like image 183
foo Avatar answered Oct 17 '22 17:10

foo


Why not put your compiled script or script text within your package and then use NSAppleScript's initWithContentsOfURL:error: method?

For example:

NSError * error = NULL;
NSURL * resourceURL = [[NSBundle mainBundle] resourceURL];
NSURL * urlOfScript = [resourceURL URLByAppendingPathComponent: @"MyApplescript.scpt"];
NSAppleScript *script = [[NSAppleScript alloc] initWithContentsOfURL: urlOfScript error: &error];
if(script == NULL)
{
    NSLog( @"could not instantiate script at %@ - %@", [urlOfScript absolutePath], [error localizedDescription] );
}
like image 45
Michael Dautermann Avatar answered Oct 17 '22 17:10

Michael Dautermann