I’m currently stuck, to remove a Dock icon, I know I need to edit the dock.plist. Problem is, I dont know how.
What is the easiest way to remove the dock icon with applescript? I cannot find any sources on the internet.
I used this code to add a folder to the dock
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>/Applications/myApp.app/</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>'"
I wonder if I can just alter this code to remove it? is so, how?
I’ve been stuck with this problem for almost a week. any help will be very much appreciated.
Thanks
Here is the AppleScriptObjC code, but it has 1 error and don’t work yet:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property NSString : a reference to NSString of current application
property NSUserDefaults : a reference to NSUserDefaults of current application
property NSDictionary : a reference to NSDictionary of current application
set DockIconLabel to "VLC"
set DockIconLabel to NSString's stringWithString:DockIconLabel
set userDefaults to NSUserDefaults's standardUserDefaults()
set dockDict to userDefaults's persistentDomainForName:"com.apple.dock"
set dockApps to dockDict's valueForKey:"persistent-apps"
repeat with anApp in dockApps
set fileDict to (anApp's valueForKey:"tile-data")
set iconLabel to (fileDict's valueForKey:"file-label")
if DockIconLabel = iconLabel then
(dockApps's removeObject:anApp)
NSUserDefaults's resetStandardUserDefaults
exit repeat
end if
end repeat
This code is my first attempt to convert Objective C code to AppleScriptObjC. The Objective C source is HERE. The error is related to this code line (something with mutable array):
(dockApps's removeObject:anApp)
I don’t know how to fix that. Need help.
Other Objective-C example is without repeat loop, but I don’t know preidcate’s syntax as well:
I fixed the script but the icon remains in the Dock:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property NSString : a reference to NSString of current application
property NSUserDefaults : a reference to NSUserDefaults of current application
property NSDictionary : a reference to NSDictionary of current application
set DockIconLabel to "VLC"
set DockIconLabel to NSString's stringWithString:DockIconLabel
set userDefaults to NSUserDefaults's standardUserDefaults()
set dockDict to userDefaults's persistentDomainForName:"com.apple.dock"
set dockApps to dockDict's valueForKey:"persistent-apps"
set newDockApps to dockApps's mutableCopy()
repeat with anApp in dockApps
set fileDict to (anApp's valueForKey:"tile-data")
set theLabel to (fileDict's valueForKey:"file-label")
if (theLabel's isEqualTo:DockIconLabel) then
(newDockApps's removeObject:anApp)
exit repeat
end if
end repeat
NSUserDefaults's resetStandardUserDefaults()
set theAppToRemoveName to "VLC" -- for testing purposes
tell application "System Events"
if (application process theAppToRemoveName exists) then
set theMenuItemName to "Keep in Dock"
else
set theMenuItemName to "Remove from Dock"
end if
tell application process "Dock"
try
tell list 1 to tell UI element theAppToRemoveName
perform action "AXShowMenu"
click menu item "Options" of menu 1
click menu item theMenuItemName of menu 1 of menu item "Options" of menu 1
end tell
on error
display dialog "The Script should be terminated.
The App with specified name doesn't exist on the Dock." buttons "OK"
return
end try
end tell
end tell
NOTE: if the app is running, then its icon will be removed when you quit this app.
You’re missing the way defaults work. The defaults system is like a database. You can make changes, but you have no control over when apps read it. Some values they might read repeatedly, and others they just read the first time they need them.
The current Xcode documentation says that resetStandardUserDefaults() has no effect and shouldn’t be used.
Here’s my own literal translation and correction of the Objective C source to which you linked. It seems to work:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
on removeDockItem(dockItemName)
set dockItemName to current application's class "NSString"'s stringWithString:(dockItemName)
set userDefaults to current application's class "NSUserDefaults"'s standardUserDefaults()
set dockDict to (userDefaults's persistentDomainForName:("com.apple.dock"))'s mutableCopy() -- Seems to be mutable anyway.
set apps to (dockDict's valueForKey:("persistent-apps"))
if (apps's |count|() > 0) then -- More likely than 'if (apps is not missing value) …' ?
set appsCopy to apps's mutableCopy()
set |modified| to false
repeat with anApp in appsCopy
set fileDict to (anApp's valueForKey:("tile-data"))
if (fileDict is not missing value) then
set appName to (fileDict's valueForKey:("file-label"))
if (appName's isEqualToString:(dockItemName)) then
tell appsCopy to removeObject:(anApp)
set |modified| to true
exit repeat
end if
end if
end repeat
if (|modified|) then
tell dockDict to setValue:(appsCopy) forKey:("persistent-apps") -- Added.
tell userDefaults to setPersistentDomain:(dockDict) forName:("com.apple.dock")
-- current application's class "NSUserDefaults"'s resetStandardUserDefaults() -- Legacy. Shouldn't be used.
tell application "Dock" to quit -- Possibly a bit extreme.
end if
end if
end removeDockItem
removeDockItem("Launchpad")
However, less literally, it’s possible to use a predicate instead of a repeat:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
on removeDockItem(dockItemName)
set dockItemName to current application's class "NSString"'s stringWithString:(dockItemName)
set userDefaults to current application's class "NSUserDefaults"'s standardUserDefaults()
set dockDict to (userDefaults's persistentDomainForName:("com.apple.dock"))'s mutableCopy() -- Seems to be mutable anyway.
set apps to (dockDict's valueForKey:("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 dockDict to setValue:(appsCopy) forKey:("persistent-apps")
tell userDefaults to setPersistentDomain:(dockDict) forName:("com.apple.dock")
tell application "Dock" to quit -- Possibly a bit extreme.
end if
end if
end removeDockItem
removeDockItem("Launchpad")
The predicate in your last script is problematic – it’s a sort of double negative. Try removing the first !. As it stands, it’s a bit on the destructive side.
Here’s Nigel’s last script, reworked to use initWithSuiteName: rather than persistentDomainForName:. The advantage is that you don’t have to read/write a dictionary for the whole domain, but rather that of a single key. There’s probably no discernible difference in this case, but in other cases it could be significant. (I’ve also changed the predicate as above.)
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
Ouch! Thanks Shane. Sorry about your Dock. It’s a long story involving trying several different things to get the predicate to work, with the eventual solution being to have the key path as an external argument and to leave off “self.”. While I was posting the script, I noticed I still had the predicate string as “!(%K == %@)”, which I’d changed from “%K != %@” during my experiments. I decided to change it back, but by then it was 03:11 in the morning ….
Now corrected.
Your version of the handler simplifies things a bit!
Thanks, Stefan. That looks as if it could be slightly more efficient than the form with argumentArray:. It would certainly look better when there’s only one argument!