File: readme.txt |
Abstract: readme file |
Version: 1.0 |
Disclaimer: IMPORTANT: This Apple software is supplied to you by |
Apple Inc. ("Apple") in consideration of your agreement to the |
following terms, and your use, installation, modification or |
redistribution of this Apple software constitutes acceptance of these |
terms. If you do not agree with these terms, please do not use, |
install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and |
subject to these terms, Apple grants you a personal, non-exclusive |
license, under Apple's copyrights in this original Apple software (the |
"Apple Software"), to use, reproduce, modify and redistribute the Apple |
Software, with or without modifications, in source and/or binary forms; |
provided that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the following |
text and disclaimers in all such redistributions of the Apple Software. |
Neither the name, trademarks, service marks or logos of Apple Inc. |
may be used to endorse or promote products derived from the Apple |
Software without specific prior written permission from Apple. Except |
as expressly stated in this notice, no other rights or licenses, express |
or implied, are granted by Apple herein, including but not limited to |
any patent rights that may be infringed by your derivative works or by |
other works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
Copyright (C) 2008 Apple Inc. All Rights Reserved. |
This sample illustrates the initial steps required to make an application scriptable. Other samples in the SimpleScripting* series build on top of this sample to show how to add additional scripting functionality. |
Step 1: Setting up |
Create a new .sdef file that includes the standard scripting suite and add it to your Xcode project. Usually, this file will have the same name as your application. Going along with that convention, the .sdef file in this sample has been named "SimpleScripting.sdef". In the contents of that file, enter an empty dictionary that includes the standard AppleScript suite as follows: |
<dictionary xmlns:xi="http://www.w3.org/2003/XInclude"> |
<xi:include href="file:///System/Library/ScriptingDefinitions/CocoaStandard.sdef" xpointer="xpointer(/dictionary/suite)"/> |
<!-- add your own suite definitions here --> |
</dictionary> |
The important parts of this definition are as follows: |
1. The 'xi' namespace declaration in the opening dictionary element declares that enclosed elements using the 'xi' namespace will follow conventions defined by the XInclude standard. This will allow us to include the standard definitions. |
2. The 'xi:include' element includes the Standard Suite in the .sdef. |
NOTE: Prior to Mac OS X 10.5 developers would copy the standard suite from the ScriptingDefinitions sample (http://developer.apple.com/samplecode/ScriptingDefinitions/index.html) directly into their .sdef file. For backwards compatibility with Mac OS X 10.4, you may continue to use that technique, but moving forward the XInclude technique described above is recommended. |
Step 2: Advertise your scriptability |
Add these two entries to your application's Info.plist file: |
<key>NSAppleScriptEnabled</key> |
<string>YES</string> |
<key>OSAScriptingDefinition</key> |
<string>Simple.sdef</string> |
The first marks your application as one that supports scripting, the second lets the system know where to look for your application's scripting definition file. You should use the file name you used in step 1. |
http://developer.apple.com/documentation/Cocoa/Conceptual/ScriptableCocoaApplications/SApps_implement/chapter_4_section_7.html |
Step 3: Start editing your Scripting Definition (.sdef) file |
In Xcode, select your .sdef file and select "File > Open As... > Plain Text File", and edit the file to include definitions for your own application. |
IMPORTANT: You can use the Script Editor application to view your application's dictionary in a dictionary viewer and to write test scripts. Whenever you make changes to your .sdef file you will have to quit and run Script Editor again for it to see the changes, because it caches dictionaries while it is running. |
Step 4: Add a starting suite |
Add a new suite to your .sdef file at the end of the dictionary just before the closing </dictionary> tag: |
<suite name="Simple Scripting Suite" code="SScr" |
<!-- put your application specific scripting suite information here --> |
</suite> |
It is inside of this suite definition where you will put your application specific scripting information. You can add additional suites if you like and use them to group related scripting functionality together, but for most purposes one should be sufficient. |
Step 5: Add an application class to your new script suite. |
Here is our new suite with the application class added in: |
<suite name="Simple Scripting Suite" code="SScr" |
description="SimpleScripting application specific scripting facilities."> |
<!-- put your application specific scripting suite information here --> |
<class name="application" code="capp" |
description="Our simple application class." inherits="application"> |
<cocoa class="NSApplication"/> |
<property name="ready" code="Srdy" type="boolean" access="r" |
description="we're always ready"/> |
</class> |
</suite> |
Note, the application class we have added inherits from the application class defined in the Standard Suite in Skeleton.sdef. Also, to get started we have added a single property to our specialized application class named 'ready'. Note that I have defined this property as 'read only' by specifying an access attribute of "r". |
The application class is the root container class for an AppleScriptable application. All of the root functionality provided by your application will be contained in this class and the other classes and objects that it contains. |
Important points to note of here: |
- the suite has a unique four-character code associated with it 'SScr'. |
- the 'ready' property has a unique code associated with it. When picking that code, I first consulted the AppleScript Terminology and Apple Event Codes table here: |
http://developer.apple.com/releasenotes/AppleScript/ASTerminology_AppleEventCodes/TermsAndCodes.html |
to see if 'ready' was already associated with a four letter code. If it was I would have used that code, but I didn't find the word 'ready' listed there so I made up a four-character code for it. And, of course, I double checked it against the codes in the Apple Event Codes table to make sure I wasn't swiping a code that was already in being used for another term). |
Step 6: Add a category to the NSApplication class. |
Add the files SimpleApplication.h and SimpleApplication.m to your project and add a definition for a category of NSApplication to them that implements the 'ready' property accessor. |
in SimpleApplication.h: |
#import <Cocoa/Cocoa.h> |
@interface NSApplication (SimpleApplication) |
- (NSNumber*) ready; |
@end |
and in SimpleApplication.m: |
#import "SimpleApplication.h" |
@implementation NSApplication (SimpleApplication) |
- (NSNumber*) ready { |
return [NSNumber numberWithBool:YES]; |
} |
@end |
Since we specified the 'ready' property as read only, we only need to provide an accessor for reading its value. There's no point in implementing a setter method function as it's a read only property. |
Step 7: The big test |
Build and run your application. Then, run the following script in the Script Editor: |
tell application "SimpleScripting" |
properties |
end tell |
It should report the following result showing the 'ready' property: |
{name:"SimpleScripting", frontmost:false, version:"0", class:application, ready:true} |
If you've gotten this far, then congratulations you have made your first scriptable application. |
Step 8: One last thing... |
As you begin to add scripting to your application you will more than likely want to debug it and see what's going on. But, in doing that you will be confronted with the fact that the way scripting operates, using a debugger isn't always the most convenient way to figure out what's going on. While processing a script your application is likely to receive many callbacks (hundreds in many cases) and what you need to do is track those callbacks to discover what is going on. So, what do you do? Well, we recommend that you add logging statements to the methods implementing your scripting callbacks. In this step we'll add a new file to the project called scriptLog.h containing the following definitions: |
#define scriptLoggingMasterSwitch ( 1 ) |
#if scriptLoggingMasterSwitch |
#define SLOG(format,...) NSLog( @"SLOG: File=%s line=%d proc=%s " format, strrchr("/" __FILE__,'/')+1, __LINE__, __PRETTY_FUNCTION__, ## __VA_ARGS__ ) |
#else |
#define SLOG(format,...) |
#endif |
And then we'll modify SimpleApplication.m so it contains: |
#import "SimpleApplication.h" |
#import "scriptLog.h" |
@implementation NSApplication (SimpleApplication) |
- (NSNumber*) ready { |
SLOG(@"Here we are!"); |
return [NSNumber numberWithBool:YES]; |
} |
@end |
Now, if we add in those changes, build and run the result, and run the same test script from before, we'll find the following entry in our application's run log: |
2007-02-21 17:36:56.913 SimpleScripting[4905] SLOG: File=SimpleApplication.m line=15 proc=-[NSApplication(SimpleApplication) ready] Here we are! |
It shows the file name, line number, method name and the string we provided. Later as we add additional scripting functionality we'll find these log messages valuable for tracking what's going on with our scripting. |
Step 9: Where to next? |
Well, now that you have the very basics in hand, you're all ready to start adding scriptability to your application. But, careful planning before you start adding in scripting features will be well worth your while. So, please consider reading the following documentation. |
- The items listed in the section "Making Your Application Scriptable" on this page are essential reading. Everyone new to scripting should read through these documents and familiarize themselves with the topics discussed. |
http://developer.apple.com/referencelibrary/GettingStarted/GS_AppleScript/index.html |
- "Designing for Scriptability in Cocoa Scripting Guide provides a high-level checklist of design issues and tactics: |
http://developer.apple.com/documentation/Cocoa/Conceptual/ScriptableCocoaApplications/index.html |
- This Scripting Interface Guidelines document provides more detailed information you should consider when adding scriptability to your application: |
http://developer.apple.com/technotes/tn2002/tn2106.html |
- The AppleScript terminology and Apple Event Codes document provides a listing of four character codes that area already defined for use with specific terms. As you are adding terminology to your application you should always check there to see if a four character code has already been defined for a term you would like to use AND to make sure a four character code you would like to use is not already being used by some other terminology. |
http://developer.apple.com/releasenotes/AppleScript/ASTerminology_AppleEventCodes/TermsAndCodes.html |
- NSScriptCommand class is the one you use for implementing verbs (aka commands) |
http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSScriptCommand_Class/Reference/Reference.html |
Step 10: And after that? |
This sample is part of a suite of samples is structured as an incremental tutorial with concepts illustrated in one sample leading to the next in the order they are listed below. |
SimpleScripting (you are here) |
http://developer.apple.com/samplecode/SimpleScripting/ |
SimpleScriptingProperties |
http://developer.apple.com/samplecode/SimpleScriptingProperties/ |
SimpleScriptingObjects |
http://developer.apple.com/samplecode/SimpleScriptingObjects/ |
SimpleScriptingVerbs |
http://developer.apple.com/samplecode/SimpleScriptingVerbs/ |
Last updated: 2008-05-30