AppleScript App Backgrounder

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

FYI, in the Resources Tab in a Script Debugger window is a checkbox, Background only, which lets you make the change permanently.

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.

Script Debugger’s setting uses the LSBackgroundOnly key, not LSUIElement.

Thanks Shane.

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:

https://forum.latenightsw.com/t/setting-an-applet-to-background-only/3264

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.

My version of the App Backgrounder Droplet code —> https://pastebin.com/SNFNnTaX
The Logging Library Script —> https://pastebin.com/gkVXMM6t