简体   繁体   中英

How to implement AppleScript support in a Swift MacOS app

I'm making a Swift MacOS app which interacts with an external device via serial port. I can control the device through the app, but I want to be able to control it even within other apps using AppleScript (all I need is one simple method like tell application "App" to send "string" ). I've searched numerous sources and couldn't find anything helpful.

I have zero knowledge in Obj-C.

Update:
I've read through some other tutorials and kinda got the idea. Unfortunately, I still don't understand how to make one simple method like tell application "App" to send "string" .
Eg Spotify Mac app has this string in its.sdef file:

    <command name="play track" code="spfyPCtx" description="Start playback of a track.">
        <access-group identifier="com.spotify.playback"/>
        <cocoa class="SPPlayTrackScriptCommand"/>
        <direct-parameter description="the URI of the track to play" type="text"/>
    </command>

Their app receives commands like tell application "Spotify" to play track <track> and executes them. This is exactly what I want.
Unfortunately, I have no idea how they handle this command in the main code. Maybe SPPlayTrackScriptCommand is implemented somehow.
I've read through many tutorials and still can't find anything about this particular thing.

Update #2
That's what I've managed to achieve:
Scriptable.sdef:

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

<dictionary title="App Scripting Terminology">
    
    <suite name="Scriptable App Suite" code="ScNo" description="Scriptable App suite.">
        
        <command name="send" code="SeNdtext">
            <access-group identifier="*"/>
            <direct-parameter description="Command to send" type="text" requires-access="r">
                <cocoa key="commandFlag"/>
            </direct-parameter>
            <result type="boolean" description="Did it do?"/>
        </command>
        
        <class name="application" code="capp" description="The application's basic scripting object.">
            <cocoa class="ScriptableApplication"/>
            <responds-to command="send">
                <cocoa method="send:"/>
            </responds-to>
        </class>
        
    </suite>
    
</dictionary>

ScriptableApp.swift:

@objc(ScriptableApplication) class ScriptableApplication: NSObject {
    func send(_ command: NSScriptCommand) -> Bool {
        //let commandFlag = command.evaluatedArguments?["commandFlag"] as? String
        print("A")
        return true
    }
}

Test AppleScript:

tell application "App"
    send "string"
end tell

Nothing works and all I get is missing value .

Thank you

So, I managed to do exactly what I wanted after 4 hours of tedious research.

Here's all the code:
Scriptable.sdef:

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

<dictionary title="App Scripting Terminology">
    
    <suite name="Scriptable App Suite" code="NoSu" description="Scriptable App suite.">
        
        <command name="send" code="NoOnSend">
            <cocoa class="App.ScriptableApplicationCommand"/>
            <access-group identifier="*"/>
            <parameter code="NoCm" name="command" description="Command to send" type="text">
                <cocoa key="commandFlag"/>
            </parameter>
            <result type="text" description="ACK"/>
        </command>
        
    </suite>
    
</dictionary>

ScriptableCommand.swift:

import Foundation
import Cocoa

class ScriptableApplicationCommand: NSScriptCommand {
    override func performDefaultImplementation() -> Any? {
        let text = self.evaluatedArguments!["commandFlag"] as! String
        print(text)
        return text
    }
}

Test AppleScript:

tell application "Noonecares"
    send command "s"
end tell

Turns out App.ScriptableApplicationCommand is essential. ScriptableApplicationCommand alone doesn't do a thing.
At least today I learned something new.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM