“The issue here is that the code signature uniquely identifies the code, so if the code is not signed there’s no way to know that one instance of your app is the same as another instance”OP might consider deploying scripts via the global script menu (enabled via Script Editor’s general preferences) or third-party launcher, rather than as standalone applets (which need to be individually codesigned and immutable). Being conventional macOS .app bundles those should provide a stable target for the OS’s identity checks to latch onto, unlike traditional Script Editor applets which are notoriously self-modifying.Yeah, associating signatures with executables rather than scripts is a loophole in the current security setup which may eventually be plugged. But until Apple figures out what its future IPC and end-user automation strategies are going to be and makes it happen, might as well make the most of those holes. It’s frustrating all round.
Post
Replies
Boosts
Views
Activity
AppleScript bitrot setting in too? How delightful.At this point OP might want to consider switching to zsh scripting and go read the manpage for `sips`, which is the command line equivalent of Image Events.app minus [hopefully] its hassles. There are definitely faster, less painful ways to get through life than dealing with an obsolescent AppleScript stack and its creeping failures; nevermind filing bug reports that will never get actioned.--[For those unaware: Apple scrapped its Mac Automation team back in 2016 after multiple new product failures. The whole Apple event/OSA/AppleScript stack looks to be in maintenance mode now, so unlikely to receive any further updates outside of plugging security holes. The future of automation most likely lies now in the cross-platform Siri and its [conversational] Shortcuts backend. The underpinnings for the latter are already lurking in 10.15 so I expect the full package will land in 10.16 sometime next year.]
“The largest point of these apps is drag/drop functionality.”Yeah, I did consider that possibility. Droplets are just too **** handy in a production environment. Code signing would be best; unfortunate that costs $99/year but if it’s a business I’m sure they can absorb that. (If only Adobe licenses were that cheap!)One of the challenges with Script Editor applets is that they tend to mutate themselves. (I think AppleScript took some ideas about persistency from Smalltalk VMs; a noble ambition, but goes down in *nix OSes with retrofitted user-level security like a lead balloon.) Off the top of my head, the easiest way to defeat that is to modify its entry point(s) like so:on run
-- do stuff
endbecomes:on run
local scpt
copy me to scpt
tell scpt to _run()
return
end
on _run()
-- do stuff
endThat should make a copy of the entire script, run that copy, and discard it. This prevents any changes to properties/globals being saved back to the applet bundle’s embedded script file, so the applet’s resource files should remain stable. I think (but don’t quote me on this) that Xcode-saved applets might be non-persistent too.Unfortunately, I don’t have access to a 10.15 machine right now to see if that makes any difference to Automation permission requests. If it does help, let us know.
“AppleScript has been around since the early ’90s, and it’s shrugged off such rumours many times in the past.”The other thing that was around since the early ’90s was the Mac Automation/AppleScript development team. Even after its original creators quit in frustration at the lack of support, there was still a team to [nominally] work on it. However, the Mac Automation team got canned in 2016; and while I completely agree with Apple’s firing of its manager (and wish it’d had been done a decade sooner when a new manager could’ve been appointed to turn it around), it is apparent there are no longer any engineers tasked to AppleScript and its related technologies beyond a minimal maintenance role. (And even those minimal API additions made to accommodate securty are half-baked and poorly tested at best.)Beyond that, the AppleScript language itself is at the end of its lifecycle, and with no apparent moves to straighten out the very dated and arcane Apple event IPC systems that underpin it and bring that technology to iOS, it’s painfully obvious it has no future beyond slowly rotting away. All that tech all be fixed/replaced/reinvigorated, and reborn as the cross-platform cornerstone for all high-level interprocess communication and end-user automation, but there’s nobody left to do it; and even when there was they had no clue why or how! (Which is why there is nobody now.)Even Soghoian dropped broad hints post-ejection that Apple envisages the future of cross-platform automation in Siri-based technologies (now including [conversational] Shortcuts) and App Extensions, and he was the one who cratered its predecessor. And that is not necessarily a bad future, but it is still one far less capable or flexible that what could’ve, should’ve, would’ve had by now had the Apple events stack not been long since run into the ground.I know Apple seriously restricts individual employees discussing current and future plans, but I wish someone there would just be honest and officially declare the whole technology stack Legacy Technology to be Deprecated in a future release of macOS, so that all users now know exactly where they stand and can plan their own futures accordingly.†Yes, radical change hurts and they’ll complain like ****, but it’s still massively less damaging than radical change with zero notice. --† (And if you lose a few print shops to Windows as a result, so what? That hasn’t been a key market for Apple in 15 years, and is probably more trouble than it’s worth. At least with a timeline they can migrate sensibly, and customers generally appreciate a vendor—even an ex-one—who treats them professionally and doesn’t burn their business from under them.)
“The idea is to get hold of the KVC definitions for the AS object graphs from a list of running applications and call them using KVC.”Apple event IPC = RPC + Queries, not OOP. It’s also notoriously high latency. Crawling the object graph will be murderously slow. Plus, application dictionaries are not IDLs; they are famously ambiguous/incomplete/incorrect, so there is a limit to how much you can rely on them.The more important question is: why do you want to do it? If you’re just trying to learn your way around scriptable applications, get Script Debugger which includes powerful dictionary and object graph browsers. If you’re thinking of writing your own, don’t bother: the whole AE/AS/OSA stack was put into maintenance mode and left to die quietly years ago. Barring miracles, its day is done.“I was hoping to simply use the Scripting Bridge to query SBApplications using the cocoa keys in the sdef.”There is no desktop automation task that cannot be made worse by trying to do it in Scripting Bridge. It’s junk. Stick to AppleScript. It’s the only [nominally] supported option that speaks Apple events right.If you like living dangerously then SwiftAutomation also speaks AEs right, but caveat emptor as I haven’t updated or tested it in a couple years and do not provide support.
“ScriptingBridge tries to impose a Cocoa interpretation on an AppleScript world”This is why SB’s ORM approach doesn’t (and can’t) work right. ORMs covering RDBMSes are notoriously twitchy; and those only have to cover half a dozen apps speaking broadly the same language (SQL). In AppleScript’s world, there are hundreds of apps with wildly different structure and commands, and little consistency in behavior.The only information in an AETE/SDEF that AppleScript actually uses are the name/OSType mappings and the type of each (type/enum/property/command/parameter). Everything else is ignored—classes and inheritance are a fiction created for documentation purposes; even one-to-one and one-to-many relationships (containment) aren’t guaranteed to hold. (You’ll see this logic replicated in SwiftAutomation’s AETE/SDEF parsers, AS quirks and all.)It would really help if OP would describe the problem they’re trying to solve. We can talk about “how” till the cows come home, but unless we understand the “why” we don’t know if our advice is appropriate or not.
“That way, I'm guessing I'd make use of the AE codes in the sdef and not the <cocoa> element KVC-compliant key mappings, and use those with the Carbon framework?”I think you’re getting confused by the KVC data found in .sdef files. That data is not provided for clients’ use; it’s purely for use by the CocoaScripting framework upon which Cocoa-based apps implement their AE support. See `man 5 sdef` if you’ve not already done so.As to navigating an app’s object graph, run-time introspection is poor/non-existent. CS-based apps have a standard `properties` property, but this only tells you about attributes and one-to-one relationships; it doesn’t tell you what one-to-many relationships (elements) exist. Nor is it a standard feature in older non-CS based apps (e.g. most MS, Adobe apps). You have to resort to reading the app’s aete/sdef; however, even that is troublesome, e.g. SDEF does not distinguish between attributes of type `text` (really, typeUnicodeText) and one-to-one relationships of type `text` (really cText), so you’ve no idea if a given property is one or other except to try querying elements (e.g. `every character of PROPERTY`) and see if the event succeeds or fails. Human users, of course, learn an app’s object model and recognize which is which, e.g. `name of front document of app "TextEdit"` vs `text of front document of app "TextEdit"`; an automated crawler will not, so will have to trial-and-error extensively.And remember, AppleScript does not use any of that “type” information itself, so there are zero guarantees that information is accurate. e.g. Properties that can return, say, a string or `missing value` constant may declare their type as `text`, so even if you do a `get` there is no guarantee the result is a String. If you try to enforce that type (as SB does), you won’t get the right result. And that’s even before we consider implementation bugs in CS and/or apps, e.g. try `tell app "TextEdit" to get path of front document` and see what happens when the front document is newly created and hasn’t been saved yet. This is why SwiftAutomation leaves casting entirely to the client code, e.g. `PROPERTY.get() as String?`; it expects the code’s author knows that property returns either String or `missing value`, regardless of what the app’s dictionary may claim, so puts them in control. Works great, and takes advantage of the Apple Event Manager’s ability to coerce between various types so if you say `[String]` and the returned data is 1.0 then you’ll still get `["1.0"]`, but it’s not something you can automate as SDEF data’s not reliable enough.Another example: `tell application "Finder" to get entire contents of desktop`, where the dictionary defines the `entire contents` property as type `specifier` (typeObjectSpecifier). Run that command and it returns a list of specifiers. Yet you can also write `tell application "Finder" to get name of every file of entire contents of desktop`, so it’s clear the property’s type is not a list. As with `text of front document of app "TextEdit"`, or `text of every document of app "TextEdit"`, what you get it partly dependent on the query you ask, and partly dependent on what the app anticipates is the most helpful result for you. (Unfortunately, while AE IPC has the facility to do content negotiation—see keyAERequestedType—it is poorly specced, underpowered, and rarely supported by applications.)..Again, if you’re trying to extract all data from each running app, you are going to be crushed at how unspeakably slow it all is, even if you do apply each `get` operation to all elements at once. I just did a job for a customer, automating a task in Adobe Illustrator, which I prototyped in Python3+appscript because AppleScript is just a PITA. That script only sent a few thousand AEs; took half an hour to run!!! I dunno exactly what it was tickling wrong (a couple minutes is more typical performance), but even on a good day AEOM queries are hella expensive and any form of IPC is inevitably magnitudes slower than in-process messaging. (The production version, written for Illustrator’s own in-process JS engine: 10secs.)That’s why, in practice, we only query/manipulate the remote data we need. Pulling mass data over the wire is totally impractical performance-wise; plus there’s no transactional guarantees so even while you’re doing it the remote state may be simultaneously changing.Apple event IPC may have its virtues—e.g. I’ve long argued its query-driven model could be a great match for Siri’s query-builder (especially if the AEOM spec was tightened up)—but when you get down to details it is painfully rough to deal with.There’s two decades’ hard experience encoded in SwiftAutomation, and even then it’s not perfect, but it’s maybe worth a skim of the code just to get some appreciation of how and why it works the way it does. Because every other approach (gensuitemodule, JavaScriptOSA, aeve, RubyOSA, and of course ScriptingBridge) falls apart when real-world *AppleScriptable* apps stomp all over their assumptions.Oh, and for general insight into Apple event IPC and how and why it works the way it does (and why it was left so awkward and unpolished), read this paper by one of its original designers:www.cs.utexas.edu/~wcook/Drafts/2006/ashopl.pdfYou’ll learn more from that than you ever will from Apple’s own public developer docs, which are riddled with omissions and lies, it pains me to say.Not trying to deter you, mind (must be a pretty good idea to make you so determined to pursue it!); just letting you know what a world of hurt you are in for! 😉
Be very wary of the SB documentation—it is a fiction, and very misleading. (There’s a reason SB and JXA never became popular, even though Mac Automation should be catnip for geeks.)As to CS documentation, it’s worth reading around. Third-party tutorials can offer insights that the Apple docs don’t. e.g. Here’s one by Matt Neuburg (old, but still worth reading as CS itself hasn’t changed much):www.apeth.net/matt/scriptability/scriptabilityTutorial.htmlOne good thing about Apple’s CS docs if memory serves: it’s the once place where they do talk about one-to-one and one-to-many relationships, which is the key to understanding how an Apple Event Object Model really works.Also bear in mind that CS’s behaviors (which are themselves not without bugs and quirks) only apply to apps built on CS, and don’t generalize to apps built on the older, lower-level Apple Event Manager APIs, which are much more variable in their behaviors...Yes, you can construct and send AEs yourself using NSAppleEventDescriptor. It’s low-level and a bit of a chore, but it can be done if that’s what you need. It’s what the “stable” version of SwiftAutomation on my BitBucket uses.†As for finding SwiftAutomation useful, nice to hear it. Alas, I couldn’t get Apple to take it (the offer stands), which is why I don’t see much point in pursuing it further. As far as studying other code, the only other AE bridge of worth is Frontier’s, but I don’t think you’ll glean much from that as it’s ancient, ancient C; besides I’ve already been through that and every other AE bridge myself and distilled all that knowledge into appscript, which in turn is refined into SA.You can message me via my SF profile (sourceforge.net/u/hhas), though as you can tell I’m pretty cheesed off at the whole mess and make no promises as to how helpful I can be.--(† There’s also an experimental fork of SA on my GitHub which assembles AE data directly, being intended as a modern cross-platform replacement to AEM itself, but ignore that. I got most of the way down to the Mach layer, but it’s a lot of effort to black-box reverse-engineer that last step when Apple themselves aren’t interested.)
“Yes. This is exactly what Script Editor does when you run a script.”Not exactly. SE is just a host for OSA language components. The language itself is responsible for building and sending AEs. In AppleScript’s case, the parser uses lookup tables built from an app’s AETE resource to convert property/element/command/etc names in a script’s source code to the corresponding OSTypes (four-char codes) which are stored in the generated bytecode. On executing that bytecode, the interpreter calls the C AEM APIs to assemble typeObjectSpecifier and typeAppleEvent records and send them to the app process.Since OSA is built on the Carbon ComponentManager (which is an old and gnarly in-process plugin mechanism), and SE (also being old and gnarly) loads OSA components directly instead of into separate subprocesses as per modern recommendations, then yeah, outgoing AEs and their replies will be sent from and to the SE process itself, which is why Apple grant SE special exemption to standard sandboxing rules. But that’s a separate pain point/discussion, so let’s not get into that here.
“The error line in AppleScript works well”I think you’ve found your solution: stick to AppleScript. The language may be a mess, but at least it knows how to speak Apple events right. ScriptingBridge and JXA don’t work right; never have, never will.
I don’t think there is one. There’s a default Standard Suite definition at /System/Library/ScriptingDefinitions/CocoaStandard.sdef, which CS-based apps can XInclude in their own SDEFs (because nothing makes XML parsing more fun than having to deal with XIncludes too; this is why SA ended up using Cocoa’s bulky XML DOM API instead of faster, simpler CF SAX APIs), but AFAIK CocoaScripting’s default Text Suite is always included via cut-n-paste.Don’t expect too much rigor or polish from CocoaScripting. IIRC it was originally created by a NeXT engineer working blind from internal AppleScript documentation, and later patched up by the Mac Automation team into something that usually mostly works, but it has various legacy bugs and flaws in addition to the inevitable challenge of trying to be a robust, efficient, usable framework for a painfully underspecced AEOM. Fair attempt, but far from complete success.BTW, the standard Text Suite implementation is famously buggy, e.g. this will disappear your text before your eyes, so don’t run it on anything important:tell front document of application "TextEdit" move last word of paragraph 1 to end of paragraph 2end tell(It’s also, as I recall, fabulously slow; CS’s one-size-fits-all query-mapping abstraction doesn’t do well representing lots of single characters; quelle surprise. It would’ve made more sense to treat `character` elements as *character ranges*, i.e. substrings, which is what users invariably want anyway.)
NSAppleEventDescriptor is just a thin (and rather dumb) Objective-C class wrapper around an AEDesc struct, and includes methods for getting that struct data in and out. It does not support NSCoding so is not directly serializable, but I’m sure you can figure how to combine the aforementioned methods with AEM’s AEFlattenDesc/AEUnflattenDesc procedures yourself.And yes, stick to the Foundation classes as Quinn says. Pointer-heavy Swift/C interop is not much fun, and neither is the old Carbon AEM API† in general. It’s more polished and capable than the crude Foundation methods that wrap it, but it’s hella arcane and you’re just making work for yourself when you don’t have to.Oh, and as far as launching apps goes, you need to use LaunchServices for that (either what’s left of the old C LaunchServices API, or AppKit’s NSWorkspace). You’ll see all that in the SwiftAutomation code (which hauls in AppKit only because the stripped down LS* APIs no longer provide the means to locate/launch an app by file name).--† There’s a reason I totally redesigned the AEM API when doing an experimental reimplementation in pure Swift (github.com/hhas/AppleEvents). Much better API than either, though I quit work on it after realizing the Mach bridge uses a completely different serialization format to AEM itself (*after* I’d written it, derp) and wasn’t in a mood to reverse-engineer that too.
This question has nothing to do with Script Editor and really belongs on a general AppleScript forum (macscripter.net or discussions.apple.com/community/mac_os/mac_os_x_technologies).But anyway, the problem is you misunderstand how `repeat with VAR in LIST` loops work. Variable VAR does not contain a list item, it contains a *reference* to a list item, e.g. `item 1 of LIST`. Depending on how you use that reference, it may get deferenced automatically and you’re none the wiser. However, when using it in equality operations (=, ≠) which do take value type into account, you must explicitly derefence it using `contents of REFERENCE`:if contents of index is equal to ind then …end ifdeveloper.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_control_statements.html
This is nonsense. AppleScript is perfectly appropriate to OP’s task, and the only supported option that speaks Apple events right. Anything else is an unnecessary exercise in pain. (Yes, there are lower-level Accessibility APIs, but those aren’t any easier to use than GUI Scripting.)OP has two problems. First, using GUI Scripting to automate another application is notoriously fragile, not very portable, and subject to macOS security blocks. But I’m going to assume the Ableton Live app does not provide any sort of API making this unavoidable. Second, OP needs to activate the Ableton Live Intro/Standard/Suite app so that it receives the key events sent via GUI Scripting. If all versions of the app have the same CFBundleIdentifier then just use that, e.g.:tell application id "com.example.foo" to activateIf they have different bundle identifiers then I’d suggest something like the following handler, which attempts to launch each app in turn:on launchApp()
repeat with aRef in {"com.example.foo.suite", "com.example.foo.standard", "com.example.foo.intro"}
try
activate application id aRef
return
on error number -1728 -- app not found
end try
end repeat
error number -1728 -- fail if none of the supported apps were found
end launchApp
launchApp()Since the only command used here is `activate`, there’s no need to worry about compiling application-specific terminology. Dealing with all the other pitfalls of GUI Scripting is left as an exercise to OP and their users, natch.
The absolute awfulness of GUI Scripting as a solution is orthogonal to the choice of language used to write it. I’m pretty sure if Ableton Live provided a proper Apple event interface the OP would be using that to control it; as they aren’t, it’s fair to assume they’re using GUI Scripting not because it’s the best or the worst solution available to them but because it’s the ONLY solution there is.