Friday, December 15, 2017

#1 2016-03-18 02:17:55 pm

tneison
Member
Registered: 2015-04-03
Posts: 66

Make Cocoa app scriptable

I'd like to add one simple script command to a Cocoa/Swift app. However all the example tutorials are 1) really old 2) far more complicated than what I have in mind.

This is what I have in mind:

Applescript:

--I'd like my app to respond to this command:
tell application "MyApp"
   performMyCocoaClassMethod
end tell

That's it. I know I need to build a sdef file and enable scriptability in xcode, but since I skipped learning ObjC and went straight to Swift, the rest of the process is very confusing.

Any pointers would be greatly appreciated.

Last edited by tneison (2016-03-18 02:18:51 pm)

Offline

 

#2 2016-03-20 08:58:32 pm

tneison
Member
Registered: 2015-04-03
Posts: 66

Re: Make Cocoa app scriptable

Okay I've got it. I was able to dig up an Apple document (https://developer.apple.com/library/mac … e_txt.html) and find an example in Swift (http://stackoverflow.com/questions/2560 … ementation). My example isn't that useful since desktop notifications are easily implemented using ASOC, but it's a clear way to illustrate an Applescript command with arguments.

The sdef file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">


<!-- declare the namespace for using XInclude so we can include the standard suite -->
<dictionary xmlns:xi="http://www.w3.org/2003/XInclude">
   
   
    <!-- use XInclude to include the standard suite -->
    <xi:include href="file:///System/Library/ScriptingDefinitions/CocoaStandard.sdef" xpointer="xpointer(/dictionary/suite)"/>
   
   
    <!-- specific suite(s) for the application follow... -->
    <suite name="Simple Desktop Notification" code="Nofy" description="A test creating a simple Applescript command with 2 arguments.">
       
        <command name="notiphy" code="NofyParm" description="Choose text values of the notiphication">
            <cocoa class="NotiphyCMD.NotiphyWithParams"/>
           
            <parameter name="with title" code="NTle" type="text" optional="no"
                description="a title parameter.">
                <cocoa key="NotiphyTitle"/>
            </parameter>
           
            <parameter name="and subtitle" code="NTSl" type="text" optional="yes"
                description="a subtitle parameter.">
                <cocoa key="NotiphySubtitle"/>
            </parameter>
           
            <result type="boolean" description="The result of the invocation. True if it succeeds, False if it does not"/>
        </command>
    </suite>
   
</dictionary>


The Swift class instantiated by the Applescript command:

import Cocoa

class NotiphyWithParams: NSScriptCommand, NSUserNotificationCenterDelegate {
   
    var notiphy = NSUserNotification()
    var notiphyCtr = NSUserNotificationCenter.defaultUserNotificationCenter()

    override func performDefaultImplementation() -> AnyObject? {
        let parms = self.evaluatedArguments
        var aTitle = ""
        var aSubTitle = ""
        if let args = parms {
            if let title = args["NotiphyTitle"] as? String {
                aTitle = title
            }
            if let subtitle = args["NotiphySubtitle"] as? String {
                aSubTitle = subtitle
            }
        }
       
        notiphy.title = aTitle
        notiphy.subtitle = aSubTitle
        notiphyCtr.deliverNotification(notiphy)
       
        if aTitle == "" && aSubTitle == "" {
            return false
        }
       
        return true
    }
   
    func userNotificationCenter(center: NSUserNotificationCenter, shouldPresentNotification notification: NSUserNotification) -> Bool {
        return true
    }
}


Finally, the Applescript command:

Applescript:

tell application "NotiphyCMD"
   notiphy with title "Hello" and subtitle "world!"
end tell

A few notes:

in the sdef file,

NotiphyCMD.NotiphyWithParams

is peculiar in that in ObjC

NotiphyWithParams

is all that's needed to refer to the class, but in Swift the dot notation is needed to resolve the path from the application to the class.

NotiphyWithParams

is a subclass of

NSScriptCommand

. This is what does all the work. To get our subclass to respond to a scripting command, we use

override func performDefaultImplementation()

This allows us to add 'notiphy' as our custom command. Expected arguments are added in the sdef file using <parameter. They are accessible inside the override func as a dictionary called

evaluatedArguments

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)