IMPORTANT NOTE: I just upgraded to Catalina and after modifying a script to run in the background with the script included below, I received the following error:
I only received this error message with one script but, still, some caution is necessary when using this script under Catalina.
About a third of my regularly-used Applescripts are saved as apps, and I’ve found some advantage to running a number of them in the background. This can be done by enabling the LSUIElement property list key, which is described by Apple as:
Normally the value of LSUIElement is modified in a terminal window, but I change it often enough that I wrote the following script, which works as an enable/disable toggle. I’ve been using this script for some time on AppleScript apps without issue but have never used it with any other app.
--Prompt user for app.
set selectedApp to POSIX path of (choose file of type "com.apple.application-bundle")
--Set variable to name of app.
set AppleScript's text item delimiters to "/"
set appName to text item -2 of selectedApp
set AppleScript's text item delimiters to ""
--Set variable to background status of app.
try
set backgroundFlag to do shell script "defaults read " & quoted form of selectedApp & "/Contents/Info LSUIElement"
on error
set backgroundFlag to "NO"
end try
--Set variables to dialog message and background flag.
if backgroundFlag = "YES" then
set dialogMessage to "Set " & quote & appName & quote & " to run in the foreground."
set backgroundFlag to "NO"
else
set dialogMessage to "Set " & quote & appName & quote & " to run in the background."
set backgroundFlag to "YES"
end if
--Prompt to change background status.
display dialog dialogMessage buttons {"Cancel", "OK"} cancel button 1 default button 2 with title "App Backgrounder"
--Write changes to app.
try
do shell script "defaults write " & quoted form of selectedApp & "/Contents/Info LSUIElement " & backgroundFlag
on error errorMessage
display dialog "The following error was reported while setting the background flag: " & return & return & errorMessage buttons {"OK"} cancel button 1 default button 1 with title "App Backgrounder" with icon stop
end try
Now that I’m using Script Debugger, I did a little additional research on this topic by setting an AppleScript applet to run in the background with the above script and by doing this with Script Debugger. I noticed two differences:
The Script Debugger applet reported an error if it contained code that resulted in user interaction (e.g. a display dialog). The other script did not do this.
The Info-LSUIElement flag was not set by the Script Debugger applet; I guess that’s what Shane was referring to when he said that the change was made permanently.
Other than the above, I don’t know if there’s any reason to prefer one approach over the other.
LSUIElement is defined in post 1, and LSBackgroundOnly is defined as:
The following script returns the background-only and agent-app status of an AppleScript applet selected in a Finder window:
-- Revised 2021.08.18
on main()
tell application "Finder"
try
set selectedApp to selection as alias
set appName to name of selectedApp
set appExtension to name extension of selectedApp
on error
display alert "An error has occurred" message "Multiple or no files selected" as critical
error number -128
end try
end tell
set selectedApp to quoted form of POSIX path of selectedApp
if appExtension ≠ "app" then
display alert "An error has occurred" message "The selected file may not be an app" as critical
error number -128
end if
try
set backgroundApp to do shell script "defaults read " & selectedApp & "/Contents/Info LSBackgroundOnly"
if backgroundApp = "1" then
set backgroundApp to "YES"
else
set backgroundApp to "NO"
end if
on error
set backgroundApp to "NOT SET"
end try
try
set agentApp to do shell script "defaults read " & selectedApp & "/Contents/Info LSUIElement"
on error
set agentApp to "NOT SET"
end try
display alert "The app " & quote & (text 1 thru -5 of appName) & quote message "Background only is " & backgroundApp & linefeed & "Agent app is " & agentApp as informational
end main
main()
@peavine Your AppleScript code broke some functionality of several of my AppleScript applets using the latest version of macOS Big Sur.
I took the liberty to add some Handlers with short descriptions, adding functionality to your original code. Now this AppleScript code works flawlessly for me using the latest version of macOS Big Sur.
--Prompt user for app.
activate
set selectedApp to POSIX path of (choose file of type "com.apple.application-bundle")
--Set variable to name of app.
tell application "System Events" to set appName to name of (selectedApp as POSIX file as alias)
--Set variable to background status of app.
try
set backgroundFlag to do shell script "defaults read " & quoted form of selectedApp & "/Contents/Info LSUIElement"
on error
set backgroundFlag to "NO"
end try
--Set variables to dialog message and background flag.
if backgroundFlag = "YES" then
set dialogMessage to "Set " & quote & appName & quote & " to run in the foreground."
set backgroundFlag to "NO"
removeLogEntry(appName)
else
set dialogMessage to "Set " & quote & appName & quote & " to run in the background."
set backgroundFlag to "YES"
logAppSetToRunInBackgroundOnly(appName)
end if
--Prompt to change background status.
activate
display dialog dialogMessage buttons {"Cancel", "OK"} cancel button 1 default button 2 with title "App Backgrounder"
delay 0.1
--Write changes to app.
try
do shell script "defaults write " & quoted form of selectedApp & "/Contents/Info LSUIElement " & backgroundFlag
compileAppScript((selectedApp as POSIX file as alias))
on error errorMessage
activate
display dialog "The following error was reported while setting the background flag: " & return & return & errorMessage buttons {"OK"} cancel button 1 default button 1 with title "App Backgrounder" with icon stop
end try
-------------------- Handlers --------------------
(* If "Backgrounded_Apps.log" file does not already exist on your Desktop,
It will be automatically created. Every time you set any AppleScript app to
"Background Only Mode", that app will be added to the "Backgrounded_Apps.log"
file. This is an excellent way to keep track of all the AppleScript applications
currently set to "Background Only". *)
on logAppSetToRunInBackgroundOnly(appName)
set currentDate to (current date) as string
set theFile to (path to desktop as text) & "Backgrounded_Apps.log"
set myName to appName
try
if myName is not in (paragraphs of (read file theFile) as text) then
set theText to myName & " was set to run in " & quote & "Background Only" & quote & " mode on " & currentDate
do shell script "echo " & quoted form of theText & " >> " & quoted form of POSIX path of theFile
end if
on error errMsg number errNum
set theText to myName & " was set to run in " & quote & "Background Only" & quote & " mode on " & currentDate
do shell script "echo " & quoted form of theText & " >> " & quoted form of POSIX path of theFile
end try
end logAppSetToRunInBackgroundOnly
(* Every time you set an AppleScript application back to "Foreground Mode",
that app will be removed from the "Backgrounded_Apps.log" file. *)
on removeLogEntry(appName)
set theFile to (path to desktop as text) & "Backgrounded_Apps.log"
set myName to appName
-- Using "-pboard ruler" preserves normal clipboard's current content
do shell script "cat " & quoted form of POSIX path of theFile & "| egrep -v " & ¬
"'" & myName & "' | pbcopy -pboard ruler ; pbpaste -pboard ruler > " & quoted form of POSIX path of theFile
end removeLogEntry
(* This will recompile and save any AppleScript app whenever its
"Background or Foreground Mode" has been changed. For me, if I
did not run the code in this handler, some of my AppleScript
apps lost functionality *)
to compileAppScript(chosenApp)
try
tell application "Script Debugger"
launch
set theApp to open chosenApp
delay 0.1
set succesfulCompile to compile theApp with showing errors
delay 0.1
close theApp saving yes
end tell
end try
return succesfulCompile
end compileAppScript
wch1zpink. Thanks for looking at my script and for the suggested revisions. Maintaining a log of AppleScript applets that have been set to run in the background is a nice enhancement.
I was interested by your following comment, because I had previously found that whenever an AppleScript applet wouldn’t run after applying my script, I could open and then immediately save the AppleScript applet in Script Debugger, which seemed to fix the problem. Your script, of course, automates this process.
When this became an issue, I seem to recall that my script jumbled the AppleScript applet’s info.plist file and that Script Debugger unjumbled it. I have little knowledge of plist files and don’t know if that was the reason my script breaks some AppleScript applets.
I had hoped Shane would consider adding this functionality to Script Debugger, which would be ideal, but that appears unlikely:
peavine, I already had something very similar to what you have, with a few differences. My version has an on open Handler also, allowing me to either launch the app directly or handle/process multiple dropped items dragged onto the applet’s icon. Because of the amount of code with the additional “open handler”, my version does not have the ”Logging Handlers” which I added to your code for you. My version has the ”Logging Handlers” in a separate Library script, which I call on via the “load script” command.