Hello! I posted this to the Apple Developers Forum and got no replies. This community seems more lively and I am hoping to get some help…
I don’t know much about AppleScripr. I found this script (see code below) on a RayCast site. It is used to dismiss notifications from Notification Center. It worked fine on Sonoma, but stopped working after an upgrade to Sonoma. Here is the code:
tell application "System Events"
tell process "NotificationCenter"
if not (window "Notification Center" exists) then return
set alertGroups to groups of first UI element of first scroll area of first group of window "Notification Center"
repeat with aGroup in alertGroups
try
perform (first action of aGroup whose name contains "Close" or name contains "Clear")
on error errMsg
log errMsg
end try
end repeat
-- Show no message on success
return ""
end tell
end tell
thanks for the feedback. edited the title. I was under the impression that “AppleScript” can also refer to a script.
getting scripts to run in Raycast is pretty trivial. Raycast is just a launcher. It’s not a Raycast issue. If I try to run the script from the CLI in Sequoia, it fails. The same exact code works under Sonoma.
The code is precisely used to erase notification messages. That is the intended function.
I did forget to include the returned error, which is:
Can’t get scroll area 1 of group 1 of window “Notification Center” of process “NotificationCenter”. Invalid index. (-1719)
Any help would be appreciated. Again I am not knowledgable in AppleScript in general so if I use the wrong terminology, apologies in advance.
This script is based on UI scripting, which is unreliable by nature. I guess in Sequoia some UI elements in Notification Center have changed, which broke the script. Maybe other members with more experience in UI scripting will be able to help.
AppleScript can also refer to the script, but adding extraneous information can drive readers away. On more focused forums such as Apple Developers, the moment they see “RayCast”, if they don’t happen to use that then they move on to the next topic. The same thing could apply if they are not running Sequoia.
In your case the problem is that, as mentioned, using GUI scripting is fragile. Any given application has its user interface grouped into various UI elements - the main window or menu, for example. These UI elements can contain other UI elements, which can also contain UI elements, and so on. There are no standards for how these UI elements are arranged - it is entirely up to the developer to use whatever design (if any) they want, and Apple loves to rearrange their user interfaces.
In order to script these UI elements, whatever layout is used will need to be figured out so that the proper reference can be used. One way to look at this hierarchy would be to compare it with entering a cave - the only way to know what is down the various dark passageways is to explore them (wearing the appropriate headgear so you don’t lose too much hair), mapping out where you are going and what is there. This can be done by using the Accessibility Inspector (included with Xcode) or a script.
For a script, you can start by using app-specific scripting terms to reveal the target UI element (if needed), and get its UI elements. From there, pick one of the elements and add it to the chain of tell statement to get its UI elements. Repeat with each item of interest, backing up and choosing different items if needed, to get to the desired element. Automator’s Watch Me Do action is also surprisingly effective at getting UI element references if you get stuck in a corner.
I am not running Sequoia, but a script to start with would be something like:
on run -- example
tell application "System Events" to click menu bar item 1 of menu bar 1 of application process "Control Center"
delay 0.5 -- allow the window to appear
spelunk("NotificationCenter")
end run
to spelunk(appName)
tell application appName to activate -- target application
tell application "System Events"
tell application process appName ¬
to tell window 1 ¬
to tell group 1 ¬
--> add sub elements as desired - note that 'to' and line continuations (option-return) are being used to keep things a little shorter and indentation from making a mess
set elements to its UI elements
if elements is {} then
return its properties -- current element info
else -- more to explore
return elements -- contained elements
end if
end tell
end tell
end spelunk
The final object reference or whatever desired pieces can be copied from the editor’s events window.
I’ve got Sequoia running in a VM, and I’ve done a bunch of UI Scripting in the past.
Here’s what I’ve found so far:
The close button is the following UI element: button 2 of first UI element of first scroll area of first group of first group of window "Notification Center"
Here’s the fun part: that button does NOT EXIST until you hover the pointer over the notification. Until you do, there is only “button 1” (I think that’s the “Show” button).
And, none of the UI elements have an “accessibility description” property, nor name, nor nothing. It’s as if Apple decided “Notifications are irrelevant to blind/low-vision people”.
BUT, after a bit of searching, I came across a post at StackExchange where someone wrote Apple Event code (in Javascript) that closes ALL notifications, and grabbed the relevant concept: search for the actions of the Notification Center window. The action is there even when the buton isn’t and you can call that directly.
So, here’s code that worked in my Sequoia VM:
-- create a test notification:
display notification "Test Notification To Find its Close Button." with title "Test Notify!" subtitle "Good luck! Seems like that button doesn't exist until you hover over this notification." sound name "Frog"
delay 1
tell application "System Events"
tell process "NotificationCenter"
tell window "Notification Center"
set nestedNotifActions to actions of buttons of first UI element of first scroll area of first group of first group
-- flatten the nest list of actions so we can loop over them.
set notifActions to {}
repeat with i in nestedNotifActions
set notifActions to notifActions & i
end repeat
repeat with oneAction in notifActions
set oneAction to contents of oneAction
if name of oneAction contains "Close" then perform oneAction
end repeat
end tell
-- Show no message on success
return ""
end tell
end tell
Note that this will close all open notifications, since it flattens the nested list of actions. If you send up 2 notifications, one right after the other, the 2nd pushes the 1st into the non-visible list.
So, you might want to play around with this.
When I made the following change, a 2nd notification created right after the 1st stuck around:
set notifActions to item 1 of actions of buttons of first UI element of first scroll area of first group of first group
repeat with oneAction in notifActions
set oneAction to contents of oneAction
if name of oneAction contains "Close" then perform oneAction
end repeat