Programmatically add application icon to dock on install - macos

I would like my application to be automatically added to the dock after the package (DMG) is installed?
Does anyone know how to do this?

There's a couple ways to do this, Andrew, and a lot of this depends on how you're doing your application installing.
If you are using PackageMaker to install your app, you can run a "postflight" script which adds your app's icon to the "defaults" (i.e. the preferences) of the dock. This older MacRumors thread shows how to do that.
If you are not using PackageMaker, then you might have to run an Applescript from within your app that does the same "defaults" writing trick. Here's a thread on AskDifferent that shows how.
In both cases you need to kill the dock (or Finder?) and restart it in order to get the change to pick up and show.

I would suggest you run the following AppleScript code, replacing myapp with the app you want to add to de dock, including its path.
In the example below, I am adding the system app "System Preferences", but you can do the same with your own path, just assign the path of your app to the myapp variable.
on run
set myapp to "/Applications/System Preferences.app"
try
tell application "Dock" to quit
end try
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>" & myapp & "</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>'"
try
tell application "Dock" to activate
end try
end run
This follows the suggestion given by Michael, but it should be more gentle as it just quits the Dock rather thank killing it.
If you prefer bash, you could run the following code, again assigning the path of your own app to the myapp variable.
Note: in the bash case, you have to use double slashes when specifying your the path, as you can see in the example.
#!/bin/bash
myapp="//Applications//System Preferences.app"
defaults write com.apple.dock persistent-apps -array-add "<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>$myapp</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>"
osascript -e 'tell application "Dock" to quit'
osascript -e 'tell application "Dock" to activate'

Related

Programmatically add web app shortcut to macOS Dock

I'm working on adding an app icon to the Dock programmatically. But all the information I found indicates I need to restart the Dock after the change.
Is there any possible method that can add icon to the Dock "live" that doesn't need to kill the Dock process? Can I perhaps use Mach IPC?
I found the following AppleScript. It worked on my system.
my add_item_to_dock(choose file of type {"APPL"} with prompt "Choose an application to add to the Dock:")
on add_item_to_dock(item_path)
try
get item_path as alias -- you need a POSIX path so this coerces the path in case it's an HFS path, alias, file ref, etc.
set item_path to POSIX path of item_path
end try
try
tell application "Dock" to quit
end try
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>" & item_path & "</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>'"
try
tell application "Dock" to activate
end try
end add_item_to_dock
This entry will be stored in ~/Library/Preference/com.apple.dock.plist
Hope this will be helpful.

OSX bash minimize window

In the Mac and using the bash shell, I want to execute a file that contains a single command (to start Jupyter Lab) and immediately minimize the terminal window.
Is there a way to do this WITHOUT installing third party software?
Yes, just use osascript and Applescript:
osascript -e 'tell application "Terminal" to set visible of front window to false'
Building on Paul R's answer, which in my testing appears to make the window fully hidden and unrecoverable, you can use the following to minimise the window to the dock if access is required again later:
osascript -e 'tell application "Terminal" to set miniaturized of every window to true'
You can create a file that with the command extension, for example jupiter-lab.command.
You add execution rights on it (chmod +x jupiter-lab.command). You edit the file and insert commands like in a bash script.
For example to open App Store, you could insert :
open "/Application/App Store.app"
The first time you double click on it, you will get a popup that tells you that the command has ended quickly. Just check the Suppress this message permanently not to see it anymore.
Note : the terminal will not be minimised but will be closed.

How to open an EMACS file in OS X by double-clicking on it, using the `emacsclient` command?

I want to open an org-mode file selected in the Finder, by double clicking on it. But since I use Emacs in daemon-mode, I want to use the emacsclient command for that.
Thus the primary idea was to wrap the command emacsclient -c posixPathToFile in an AppleScript App to open it.
tell application "Finder"
set fileAlias to the selection as alias
set fileName to name of fileAlias
set posixPath to POSIX path of fileAlias
end tell
-- tell application "Emacs" to activate
try
do shell script "/usr/local/bin/emacsclient -c " & quoted form of posixPath
end try
I know some set commands are not needed. Let's assume this script is saved as Xemacs.app and that I associate this app to always open .org file.
Using this App does not work by double-clicking on the file, but rather if I select the file in the Finder and then call the Xemacs.app independently. Why ? I'm not confident enough with AppleScript to figure out what happens.
So the workaround was to use the Automator service
on run {input, parameters}
set posixPath to POSIX path of input
tell application "iTerm" to do shell script "/usr/local/bin/emacsclient -c " & quoted form of posixPath
return input
end run
The service is saved as 'Open in Emacs'
Now selecting a file and right-clicking and callig Service > "Open in Emacs" works and opens the file.
What is wrong with the first approach ?
ok, I solved my issue. The problem comes from my misunderstanding of the difference between ScriptEditor and the Automator. If I use the Automator to create an App and use the former script instead of creating an App using the ScriptEditor, then it works as expected.
One can simplify the process by creating an App in Automator and running a shell script instead of wrapping the command in Ascript.

How can I launch an AppleScript application and run shell scripts from another AppleScript?

Here are my files:
launcher.applescript
tell application ":path:to:applescript:apps:shell-script-launcher.app" to launch
shell-script-launcher.app [AppleScript, saved as Application]
do shell script "say starting script"
Desired behavior:
Run "launcher.applescript" from AppleScript Editor
Listen for "starting script"
Actual behavior:
Running the "shell-script-launcher.app" by opening it manually in the finder yields expected behavior
Running the "launcher.applescript" opens the "shell-script-launcher.app" but it never executes the shell script.
I've tried saving the app as "Run Only" as well as "Stay Open". Still no progress. What do you recommend. The final result must be an Application instead of an Applescript.
Conceptually:
the run command launches and runs an application hidden
the activate command launches, runs, and activates the application (makes it the frontmost application)
launch, according to Apple, "Launches an application, if it is not already running, but does not send it a run command."
for AppleScript-based applications this should mean that they're loaded, but not executed (i.e., their - implicit or explicit - on run handler is NOT invoked), but in practice that is not true up to 10.9 - see below.
it is unclear (to me) what exactly that means for non-AppleScript-based applications
Here's how Apple thinks it works with AppleScript-based applications, which is only true starting with OSX 10.10 (Yosemite):
A script can send commands to a script application just as it can to other applications. To launch a non-stay-open application and run its script, use a launch command followed by a run command, like this:
launch application "NonStayOpen"
run application "NonStayOpen"
The launch command launches the script application without sending it an implicit run command. When the run command is sent to the script application, it processes the command, sends back a reply if necessary, and quits.
Broken behavior on OSX 10.8, 10.9 (fixed in OSX 10.10):
launch by itself is enough to run the application and is indeed the only command that works with AppleScript-based applications.
Any attempt to execute run or activate (whether in addition to launch or not) runs the application - even twice when run from AppleScript editor(!; just once with osascript) - but reports failure <appName> got an error: Connection is invalid.
This strikes me as bug.
Not sure how OSX versions <= 10.7 behave.
Note: I've witnessed the non-executing behavior with launch once, but every non-stay-open AppleScript-based test app I've created from scratch on OS X 10.9.2 and OS X 10.8.5 also executes the script with launch - contradicting what the documentation says.
Please let me know if your system behaves differently and/or how older versions behave. On what OSX version was the app that doesn't execute with launch created?
On OSX 10.10, behavior is consistent with the documentation, with one thing worth noting:
If the intent is to launch and run in one step, run application is sufficient - no need for a separate launch application command first.
Options
#user309603's pragmatic solution simply uses do shell script with the standard open utility to bypass the problem - this should work, regardless of whether the application is AppleScript-based or not:
do shell script "open " & ¬
quoted form of POSIX path of ¬
alias ":path:to:applescript:apps:shell-script-launcher.app"
If you know the type of application you're invoking up front:
to run an AppleScript-based app: best to use run script file, as #regulus6633 recommends - this has the added advantage that the invoked AppleScript-based application can return objects directly to the caller:
run script file ":path:to:applescript:apps:shell-script-launcher.app"
Note: There's also load script file, which indeed lets you merely load script code without executing it right away.
to run non-AppleScript apps: use run / activate to run the app hidden / frontmost:
run application ":path:to:applescript:apps:shell-script-launcher.app"
You could use run even with AppleScript-based applications and simply ignore errors with try ... end try, as #atonus suggests - the downside is that you won't be able to detect actual failure to invoke the application.
You can mitigate this by selectively ignoring only the specific Connection invalid error (which assumes this error would not legitimately occur) [no longer needed on OSX 10.10]:
try
run application "Macintosh HD:Applications:_Sandbox-AppleScript0.app"
on error number -609 # 'Connection is invalid' error that is spuriously reported
# simply ignore
end try
Finally, on OSX <= 10.9, you could try to simply use the launch command (though that didn't work for the OP, possibly due to working on a <= 10.7 OSX version):
launch application ":path:to:applescript:apps:shell-script-launcher.app"
However, that is not advisable for two reasons:
In OSX 10.10, Apple has fixed the launch behavior to no longer execute also, so your code will break when run there.
While non-AppleScript apps typically do run (hidden) when invoked with launch, the documentation says that AppleScript "does not send it a run command" and "allows you to open an application without performing its usual startup procedures, such as opening a new window" - what that exactly means is not clear and different applications seem to handle this differently.
Applescript has the "run script" command. It works on applescripts or applescript applications. So if I have your app on my desktop then this works...
set appPath to (path to desktop as text) & "shell-script-launcher.app"
run script file appPath
Have you tried open?
do shell script "open 'path/to/applescript/apps/shell-script-launcher.app' && say starting script"
Put it between "try" keywords.
try
tell application ":path:to:applescript:apps:shell-script-launcher.app" to activate
end try
Save your script as an application.
Add the desired script into the Script folder (see path below)
Run as follows, change per type of script you want to run...
property theApplicationPath : the path to me as text <br/>
property theShellScriptPath : theApplicationPath & "Contents:Resources:Scripts:test.command"<br/>
property theShellScript : the quoted form of POSIX path of theShellScriptPath<br/>
<br/>
tell application "Terminal" to (do shell script "/bin/bash " & theShellScript)
<br/>
Boom, Bob's your uncle! At least for me.
It is quite simple, you just have to use the normal do shell script, for example:
do shell script "open " & ¬
quoted form of POSIX path of ¬
alias ":path:to:applescript:apps:shell-script-launcher.app"
This may be helpful but I'm not an expert on this subject. I this case I found the double launching behaviour (on Yosemite, I haven't used any other version of OS X) very annoying and digging around I found one can check if it is already running.
This script is so I can launch a new terminal whenever I like.
if application "Terminal" is running then
tell application "Terminal"
activate
do script ""
end tell
else
tell application "Terminal" to activate
end if

Close Terminal window from within shell script (Unix)?

Is there a way to close a Terminal window from within a shell script? I have a .command file that should just get out of the way once it's done.
Using exit 0 will cleanly terminate the script.
Whether Terminal window stays open is user-configurable. The default is to always stay open. To change this:
Terminal.app > Preferences > Profiles > Shell
- "When the shell exists:"
> Close if the shell exited cleanly
- "Ask before closing:"
(•) Never
-- OR --
(•) Only if there are....
When "Close if shell exited cleanly" is used, the script will close the window if the exit result is 0, which is the default if nothing went wrong.
Since you don't want to delete all Terminal windows, first change the name of your window from "Terminal" to something else:
echo -n -e "\033]0;My Window Name\007"
Then at the end of the script, use:
osascript -e 'tell application "Terminal" to close (every window whose name contains "My Window Name")' &
You can use apple script to quit the terminal app. Add the following to your script -
osascript -e 'tell application "Terminal" to quit'
This will give you a popup confirming to close the app. You can disable this in Terminal preferences.
Alternatively, you can also use killall command to quit the app. The following would work just as well.
killall Terminal
Note:
Just as a side note, you can freely add the above commands to your script and it would work as you want. However, there are few caveats. First being you will limit the ability of your script to work on different boxes. Secondly, it would be safer to use nohup so that any commands that are currently running won't quit due to quitting of the Terminal app.
This works for me:
#!/bin/sh
{your script here}
osascript -e 'tell application "Terminal" to close (every window whose name contains ".command")' &
exit
This will work for closing just your windows opened with a .command file but leave things already running in other terminal windows. I know that I almost always have either sass or grunt watch something so I don't want to quit terminal totally.
closeWindow() {
/usr/bin/osascript << _OSACLOSE_
tell application "Terminal"
close (every window whose name contains "YourScriptName")
end tell
delay 0.3
tell application "System Events" to click UI element "Close" of sheet 1 of window 1 of application process "Terminal"
_OSACLOSE_
}
This will close the Terminal window for your script and keep any other Terminal windows open as long as their window titles don't match. For it to work Terminal will have to be added to the list of applications permitted to use the Accessibility framework. You can also cycle through Terminal windows with a repeat command and close every window x that contains a UI element "Close" on sheet 1.
I find the best solution for this is to use Automator to create a true OSX application which will work the same way regardless of how your system is configured. You can have the Automator run your shell script, or you can embed the shell script itself in Automator.
Here is how you do it:
Run Automator (in Applications).
Choose "New Document" and when it
asks "Choose a type for your document" choose "Application"
In the
left panel, select "Utilities" then "Run Shell Script".
Type in your
script commands in the workflow item in the right panel. You can either call another
shell script, or just put your commands in their directly.
Save the
Application, which will be a full-fledged Mac App. You can even
cut-and-paste icons from other apps to give your script some
personality.
#!/bin/bash -x
{your script here}
. exit 0
kill -9 $PPID
you can also create a shortcut for your script:
cp yourscript.sh ~/bin/yourshortcutnamewhateveryouwant
then type
yourshortcutnamewhateveryouwant
will run whatever is writen into script at any directory.

Resources