Making SwiftUI app Scriptable with AppleScript and Javascript JXA

524 views Asked by At

Please note I have carefully followed How to implement AppleScript support in a Swift MacOS app - however this is not working for me. I assume it's out of date.


After following a variety of documentation, guides, examples, I'm stuck trying to get AppleScript / Javascript support working in a SwiftUI app. (in Macos Big Sur, to begin with.)

The main problem seems to be that all documentation, examples, etc. are out of date.

I could pose this question as being about Swift 5 + AppDelegate instead of SwiftUI and I'd be in the same pickle.

So here's what I have so far...

  • Info.plist - (absent in SwiftUI) added with:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSAppleScriptEnabled</key>
    <true/>
    <key>OSAScriptingDefinition</key>
    <string>Progression.sdef</string>
</dict>
</plist>
  • Progression.entitlements to allow scripting. (Sandbox is switched off too.)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.app-sandbox</key>
    <false/>
    <key>com.apple.security.files.user-selected.read-only</key>
    <true/>
    <key>com.apple.security.automation.apple-events</key>
    <true/>
</dict>
</plist>
  • I've then created what I hope is a working Progression.sdef scripting definition file.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
<dictionary title="Progression Terminology">
    <suite name="Progression Suite" code="PrgN" description="Progression scripting classes and commands.">
        <command name="progress" code="proGress">
            <cocoa class="Progression.ProgressCommand"/>
        </command>
    </suite>
</dictionary>
  • ProgressCommand in the SwiftUI app.
import Foundation
@objc class ProgressCommand: NSScriptCommand {
    @objc override func performDefaultImplementation() -> Any? {
        print("Called")
        return nil
    }
}
  • I can load the app, and detect the sdef in ScriptEditor > Open Dictionary...
  • In an AppleScript I can call quit on the app (although TBH I haven't tested to see if this works if I pull all the scripting items out.):
tell application "Progression"
  quit
end tell
  • In AppleScript if I call progress it seems to recognize the command, although I'm not sure if it's getting past the .sdef level ... because it fails with:
tell application "Progression"
  progress
end tell
error "Progression got an error: Can’t continue progress." number -1708

At this point I'm stuck for a couple of days.

Edit: I found this answer:

https://stackoverflow.com/a/37202803/311660 although adding the code to the SwiftUI App doesn't work.

Thankfully there is a project & code supplied (using the older NSAppDelegate Style.) which works standalone.

If I can't get a working answer for pure SwiftUI, I'll just re-implement the app using NSAppDelegate, at the end of the day I just need a working link to ApppleScript.

The question remains, is this possible in a SwiftUI app?

1

There are 1 answers

0
ocodo On BEST ANSWER

So the answer in https://stackoverflow.com/a/37202803/311660 solves this problem, it works fine with SwiftUI.

The problem in my code is the name of my command.

<command name="progress" code="progress">

progress is a reserved word (used for progress indicator), changing it to foobar in my example code, fixes the issue.

This project was built to show how to use SwiftUI with AppleScript.