Embedding Applescript in Cocoa/Objective-C applications

Discussion in 'Mac Programming' started by NSNick, Jul 18, 2008.

  1. NSNick macrumors regular

    Joined:
    Jun 27, 2008
    Location:
    Washington D.C.
    #1
    Has anyone embedded Applescript in Cocoa/Objective-C applications using NSAppleScript. This seems extremely powerful as it can be used to write a program that controls other programs. Is there a way to control other applications without Applescript?
     
  2. whooleytoo macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #2
    You can also do it via sending AppleEvents.

    Some applications also respond to certain NSNotifications, if they are documented you can use these too.
     
  3. NSNick thread starter macrumors regular

    Joined:
    Jun 27, 2008
    Location:
    Washington D.C.
  4. cMacSW macrumors regular

    Joined:
    Mar 20, 2006
    #4
    I've done this. Basically, you add your applescript to your cocoa project in the resources folder. Then when you want to use in you load it from your bundle like this:

    Code:
     NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithContentsOfURL:scriptURL error:&errorDict];
    Then add your script arguments then call this:

    Code:
    returnDescriptor= [scriptObject executeAppleEvent:event error:&errorDict];
    K
     
  5. cMacSW macrumors regular

    Joined:
    Mar 20, 2006
    #5
    Also I forgot to mention, with Leopard you can use scripting Bridge and communicate with scriptable apps with cocoa calls
     
  6. NSNick thread starter macrumors regular

    Joined:
    Jun 27, 2008
    Location:
    Washington D.C.
    #6
    How would one write this application using script bridges and then without using any Applescript at all?

    Also, how would one retrieve the name of the song that is currently playing from iTunes in the form of an NSString?

    Code:
    #import <Cocoa/Cocoa.h>
    
    
    @interface AppController : NSObject {
    	NSAppleScript *run;
    	NSAppleScript *start;
    	NSAppleScript *nextTrack;
    	NSAppleScript *backTrack;
    }
    -(IBAction)play:(id)sender;
    -(IBAction)next:(id)sender;
    -(IBAction)previous:(id)sender;
    @end
    Code:
    #import "AppController.h"
    
    
    @implementation AppController
    
    -(void)awakeFromNib
    {
    	NSAppleScript *run = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to run"];
    	[run executeAndReturnError:nil];
    }
    
    -(IBAction)play:(id)sender
    {
    	NSAppleScript *start = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to playpause"];
    	[start executeAndReturnError:nil];
    }
    
    -(IBAction)next:(id)sender
    {
    	NSAppleScript *nextTrack = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to next track"];
    	[nextTrack executeAndReturnError:nil];
    }
    
    -(IBAction)previous:(id)sender
    {
    	NSAppleScript *backTrack = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to back track"];
    	[backTrack executeAndReturnError:nil];
    }
    
    @end
     
  7. whooleytoo macrumors 603

    whooleytoo

    Joined:
    Aug 2, 2002
    Location:
    Cork, Ireland.
    #7
    Err.. no. ;)

    If you mean AppleEvents, then you can communicate with several applications by sending AppleEvents to them. There's only a small core set to which every application will respond; but many applications have a huge set of AppleEvents that would enable you to communicate with them. You build the AppleEvent, and send it via AESendMessage. Also look at the NSAppleEventDescriptor class documentation.

    If you mean notifications.. if you're trying to control iTunes then I'm not sure if this is an option as I don't know if you can find out what notifications it responds to. Try googling an application called NotificationWatcher, and using that you might be able to find out which notifications to send.
     
  8. cMacSW macrumors regular

    Joined:
    Mar 20, 2006
  9. hhas macrumors regular

    Joined:
    Oct 15, 2007
    #9
    Using objc-appscript, which provides 99.9% compatibility with existing scriptable applications and runs on 10.3.9 onwards:

    Code:
    // To create glue:  osaglue  -o ITGlue  -p IT  iTunes
    
    @interface AppController : NSObject {
    	ITApplication *itunes;
    }
    -(IBAction)play:(id)sender;
    -(IBAction)next:(id)sender;
    -(IBAction)previous:(id)sender;
    @end
    Code:
    @implementation AppController
    
    -(void)awakeFromNib
    {
    	itunes = [[ITApplication alloc] initWithBundleID: @"com.apple.itunes"];
    }
    
    -(void)dealloc {
    	[itunes release];
    	[super dealloc];
    }
    
    -(IBAction)play:(id)sender
    {
    	[[itunes play] send];
    }
    
    -(IBAction)next:(id)sender
    {
    	[[itunes nextTrack] send];
    }
    
    -(IBAction)previous:(id)sender
    {
    	[[itunes previousTrack] send];
    }
    
    @end
    Error handling is omitted for clarity; e.g. you might want to check for command errors raised if the user has quit/restarted iTunes while your app is running, and automatically reconnect your ITApplication instance to it if that happens.

    The latest version of ASTranslate can convert AppleScript commands to objc-appscript syntax. For example, if you run:

    Code:
    tell application "iTunes"
    	name of current track
    end tell
    it will return:

    Code:
    // To create glue:  osaglue  -o ITGlue  -p IT  iTunes
    
    ITApplication *itunes = [[ITApplication alloc] initWithName: @"iTunes"];
    
    ITReference *ref = [[itunes currentTrack] name];
    
    id result = [ref getItem];
    Again, you'll want to flesh this out a bit for production code (e.g. iTunes will raise an error if the player is completely stopped, in which case a current track isn't available), but it gives you a useful starting point.

    (p.s. Note that the objc-appscript codebase and APIs are currently going through some changes as I'm trying to push it towards a beta release so you might want to keep an eye on the subversion repository for notification of changes.)
     

Share This Page