For reference, if anybody else needs to remove items from their Dock, this seems to work:
use framework "Foundation"
use scripting additions
set prefsFile to (POSIX path of (path to preferences from user domain)) & "com.apple.dock.plist"
set removeApps to {"TextEdit"}
set dockRec to my readPlistAt:prefsFile
set appRecords to |persistent-apps| of dockRec
set newAppRecord to {}
repeat with anAppRecord in appRecords
if |file-label| of |tile-data| of anAppRecord is not in removeApps then copy contents of anAppRecord to end of newAppRecord
end repeat
set |persistent-apps| of dockRec to newAppRecord
my saveRecord:dockRec toPlistAt:prefsFile
repeat 2 times
do shell script "killall Dock"
delay 3
end repeat
on saveRecord:theRecord toPlistAt:posixPath
set theDict to current application's NSDictionary's dictionaryWithDictionary:theRecord
set thePath to current application's NSString's stringWithString:posixPath
set thePath to thePath's stringByExpandingTildeInPath()
theDict's writeToFile:thePath atomically:true
end saveRecord:toPlistAt:
on readPlistAt:posixPath
set thePath to current application's NSString's stringWithString:posixPath
set thePath to thePath's stringByExpandingTildeInPath()
set theDict to current application's NSDictionary's dictionaryWithContentsOfFile:thePath
return theDict as record
end readPlistAt:
Note, it’s unclear to me why I need to restart the Dock twice with a delay in between, but so far it’s working reliably on several tests with this. I tried different numbers of repeats and different delays… I wasn’t exhaustive about it, but the 2 repeats with a 3 second delay in between seems to be reliable on my machine. Your mileage may vary.
I don’t remember exactly from whom I got the following script. It is designed to remove the application icon in the Dock and is more compact.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
removeDockItem("VLC")
on removeDockItem(dockItemName)
set dockDefaults to current application's class "NSUserDefaults"'s alloc()'s initWithSuiteName:"com.apple.dock"
set apps to dockDefaults's objectForKey:"persistent-apps"
if (apps's |count|() > 0) then
set filter to current application's class "NSPredicate"'s predicateWithFormat:("%K != %@") argumentArray:({"tile-data.file-label", dockItemName})
set appsCopy to apps's filteredArrayUsingPredicate:(filter)
if (appsCopy's |count|() < apps's |count|()) then
tell dockDefaults to setObject:(appsCopy) forKey:("persistent-apps")
tell application "Dock" to quit -- Possibly a bit extreme.
end if
end if
end removeDockItem
Interestingly, the “tell dockDefaults to setObject:(appsCopy) forKey:(“persistent-apps”)” seems to make it so that a single “tell application “Dock” to quit” is sufficient.
I didn’t experiment with this much; I did use the “tell…quit” statement in your script, and maybe the difference was that vs. the “shell…killall” statement. Not important for me to get to the bottom of, this is working better.
I kept the less succinct Applescript Repeat Loop just because I’m familiar with it and can edit it as needed… I’m thinking I might want to use this script to re-arrange the dock to. The idea here is that when a user changes an entire branch of our code to test, the internal references in all our apps are consistent within whatever branch they move to, but if they added an application to the dock, then it’s got a hard-coded path pointing to something on the wrong branch… which can cause trouble.
So I want the script that switches their branch to also find and remove any apps pointing to apps on the old branch, and then add the equivalent script from the new branch.
But if I just run the handler as I have it, and then run a standard shell line to add the correct copy using (do shell script "defaults write …) then it’s going to re-arrange their dock.
So maybe I’ll also have this re-arrange it back for them. I’ll probably wait and see if there are any complaints.
Thanks again, Shane and KniazidisR! Great stuff, super helpful.
In case it’s useful to someone, here’s more complete code that keeps track of which apps were in the dock, and will only add back ones it actually removed.
use framework "Foundation"
use scripting additions
set checkApps to {"TextEdit","Mail","Whatever App Name," "Etc."}
set removedApps to remove_apps_from_dock(checkApps)
tell script "My Additions" to set scriptsFolder to POSIX path of get_scripts_folder()
set missingApps to {}
set appPaths to {}
repeat with anApp in removedApps
try
set thisAppPath to scriptsFolder & anApp & ".app"
set thisAlias to (thisAppPath as POSIX file) as alias
set appPaths to appPaths & thisAppPath
on error
set missingApps to missingApps & anApp
end try
end repeat
if (count of missingApps) > 0 then
set missinglist to ""
repeat with anApp in missingApps
set missinglist to return & anApp & missinglist
end repeat
display dialog "The following applications were in your dock, but don't exist on the new branch. The old copies will be removed from your dock and not replaced." & missinglist
end if
if (count of removedApps) > 0 then
repeat with anAppPath in appPaths
add_app_to_dock(anAppPath)
end repeat
tell application "Dock" to quit
end if
on remove_apps_from_dock(removeApps)
set dockDefaults to current application's class "NSUserDefaults"'s alloc()'s initWithSuiteName:"com.apple.dock"
set appRecord to dockDefaults's objectForKey:"persistent-apps"
set newAppRecord to {}
set removedApps to {}
repeat with anAppRecord in appRecord
set appName to (|file-label| of |tile-data| of anAppRecord) as text
if appName is in removeApps then
set removedApps to removedApps & appName
else
copy contents of anAppRecord to end of newAppRecord
end if
end repeat
tell dockDefaults to setObject:(newAppRecord) forKey:("persistent-apps")
return removedApps
end remove_apps_from_dock
on add_app_to_dock(appPath)
if class of appPath is alias then set appPath to POSIX path of appPath
do shell script "defaults write com.apple.dock persistent-apps -array-add '<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>" & appPath & "</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>'"
end add_app_to_dock
It calls a “get_scripts_folder()” handler from a library that I’m not including, because it would be localized to an individual’s setup. Replace as appropriate for wherever your apps are.