Run script in ".app" (Application Bundle) as the primary executable - macos

I'm trying to use Mono to make a portable application that works on Windows, Mac, and Linux, but I want to have a standard DMG file that allows users to simply click and drag my application to their Applications folder on their Mac. In the best answer to this post I found that by creating an executable script beginning with #! in the MyAppName.app/Contents/MacOSX/ folder, it could run whatever I liked.
How do I get a script to actually run?
I made a blank "Hello World" Cocoa App in XCode, and copied the .app file to the Applications directory, and everything worked great. But when I replaced the executable in the MacOSX folder with a script starting with #! it didn't run the script.
I tried chmod 755 myscript, I tried deleting the old executable file and renaming my script to be the old filename, but all that served to do was stop the app from running at all. The permissions of the script, and the filename, are both correct.
So then I assumed that maybe scripts wouldn't work, and XCoded a command line utility, again that would simply spout "Hello World!", but still it didn't run.
The ".app" extension is formally called an Application Bundle, and they have some pretty good documentation, but none of it seems to tell me why my approach isn't working.
Here is the .app bundle that I'm working on. Inside the MasOSX directory you'll find hello (the Hello Word command line utility) and script (a one line script with a #! as the first line) and XCodeTest (a Hello World cocoa app).

Scripts in Unix
Well, first of all, the correct syntax for the first line of a script is
#! <path-to-script-interpreter> [<optional-args>]
For instance
#! /usr/bin/perl -wT
... perl code here
Using the open command
However, this won't help you because the open command does not support shell scripts as launchers. You need to write some C / Objective-C code and compile it into a native executable. Simply using system() or execv() inside that tool won't work either, you'd have to dlopen() the Mono runtime.
Look at monodevelop/mainbuild/MacOSX/monostub.m for an example. This is what MonoDevelop uses to launch MonoMac application.
When you write a Cocoa app with XCode, it will compile your app into native code and put the resulting binary as launcher in the Contents/MacOS directory.
The easy solution
Why don't you simply create a MonoMac application with MonoDevelop? This would automatically create the .app package for you - no need to fiddle around with scripts or custom launchers.

Related

How to Notarize an executable shell script (.command) file for MacOS 10.15 Catalina

This is a DIFFERENT scenario than discussed in other postings:
I have a .sh (shell script) which I've changed to a .command (executable shell script). It's signed using code sign, and being distributed on a .dmg that is signed.
However, Catalina (of course) doesn't like it -- complains it "can't be opened because Apple can't check it for malicious software". The user can still open the .command file if they right-click and select "Open" from the context menu, but the alert is still displayed, although this time with an available Open button.
I'd really like to avoid having to create a simple command line APPLICATION just for the purpose of executing a few shell script lines -- just so it can be notarized.
Anyone know of how to get around this?
Stephen
Your going to hate this but throw it into a .app bundle and call it from the .plist as the exec. Then you may proceed with notarization.

How do I present application with additional server mode on macOS to customer

I have a desktop application that I successfully package and install on macOS using dmgcanvas. The user simply drags the icon into Applications to install and then run by clicking on the Application Icon in Applications.
My problem is whereas the software was previously a Desktop only application it now has a new mode whereby it runs as a server, and can then be controlled via a web browser. On Windows, I would simply create another .exe file with the option set to run as server and put this in the installation folder, so the user would just run MyApp.exe or MyAppServer.exe
But in macOS I can not see how to do the equivalent thing since there is just one folder Myapp.app containing the installation and clicking on Myapp.app runs the application, so where do I put MyAppServer?
Of course, the user could right-click on MyApp.app and run Show Package Contents and then navigate to a subfolder such as bin containing a cmdline version that runs in server mode. But how is the user supposed to know how to do that, I want an easy way for the user to run MyAppServer?
Its hard for find documentation of how things exactly work on MacOS. But below is a good article
https://mathiasbynens.be/notes/shell-script-mac-apps
The internal folder structure may vary between apps, but you can be sure that every Mac app will have a Contents folder with a MacOS subfolder in it. Inside the MacOS directory, there’s an extension-less file with the exact same name as the app itself. This file can be anything really, but in its simplest form it’s a shell script. As it turns out, this folder/file structure is all it takes to create a functional app!
They have a simple script to automate the whole process
#!/usr/bin/env bash
APPNAME=${2:-$(basename "${1}" '.sh')};
DIR="${APPNAME}.app/Contents/MacOS";
if [ -a "${APPNAME}.app" ]; then
echo "${PWD}/${APPNAME}.app already exists :(";
exit 1;
fi;
mkdir -p "${DIR}";
cp "${1}" "${DIR}/${APPNAME}";
chmod +x "${DIR}/${APPNAME}";
echo "${PWD}/$APPNAME.app";
So what I would do is that, instead of having my apps binary directly, I will have a Shell Script and the Binary in the same folder. This shell script will check if the AppName Server.app already exists or not, if not, it will create the folder and put a script which then calls your original app with -r flag.
And then I would just run the actual app with the pass arguments that were passed to the script
Is this the best approach? Not sure about that, I could not find a way where a app has multiple Icons in but just one folder. In this case the Server option will not exists on first installation of the app, but after the first run of the app. You could even ask the user if they really want an additional icon for the app or not.

What's the difference between "./" and "open" in Terminal and how could run a Unix executable from XCode?

I'm new in all these and I would like to excuse me for my ignorance..
I have a unix executable file. I run through terminal with command: open programname --args argument and it responds that can't find the resource file(which is the argument that I'v passed.)
I tried by writing: ./programname argument and it works.
Firstly, I would like to know the difference between these two methods and why the first one doesn't work, while the second works.
The problem that I have now is that I can't do it in XCode. When a executable is running, it says that it can't find the resourse file. I passed an argument in executable by cmd+i to executable and adding the resource file as an argument.
Thank you for your potential answer..
open is the exact equivalent of double clicking on a thing in the Finder. So if you use it on a UNIX executable then the executable will launch but the current working directory won't be where the executable is located and won't necessarily be anything useful. However, you could also use it to open a .doc file or any other file type, to open a directory in the Finder, to open a URL in the finder, etc.
Launching an executable with ./name is a normal UNIX way to run the thing. The current working directory will be wherever you are when you type it. So that'll be the same directory as the executable is located in (unless you launch from elsewhere on the disk, e.g. by going down a directory and using ../name to launch the executable).
What you probably want to do is write code to get the path to the executable, and seek the specified file relative to that? You don't say what language you're working in, and annoyingly that's not something that's in the POSIX spec so it varies from OS to OS.
If you're in C or anything that can call C (so, C++, Objective-C, etc) then NSGetExecutablePath (ignore Google's desire to put an underscore before it, see e.g. this site) is quite probably what you want. If you're in Objective-C then NSString has some methods for automatically appending paths.
"open" is a command that works exactly as if you had navigated to a specific application via Finder and then double-clicked it.
./ is a way of running a particular file that's marked executable via chmod.
For example, you can run a Mac OS X application from the command line by entering "open /Applications/MyApp.app/". But it won't work if you do ./MyApp.app/ (assuming you're in the /Applications directory).
If you type "man open" into your terminal, you can read more details there.

Making an executable bash file run when clicked

I have a bash file that does some file manipulation. I don't want to have to open the terminal every time I run it. Is there a way to make the program run when I double click it? (Like a windows .exe file)
Thanks
You can add a ".command" extension to the filename -- then double-clicking it will automatically open Terminal and run the script in a new window. Note: this assumes you still want to watch/interact with the script via a Terminal interface; if you want to avoid this as well, wrapping the script with Platypus, AppleScript, or Automator (as Zifei and Ned suggest) would be better options.
What you need is Platypus.
Platypus is a developer tool for the Mac OS X operating system. It can be used to create native, flawlessly integrated Mac OS X applications from interpreted scripts such as shell scripts or Perl and Python programs. This is done by wrapping the script in an application bundle directory structure along with an executable binary that runs the script.
The easiest thing to do is to type: sudo chmod 755 the_file_Name.This will allow you to double click on the file in the finder.
With OS X 10.5+, you can wrap the bash shell script in an AppleScript application using the AppleScript editor or an Automator application using Automator.app (see the Automator on-line help).
You could write (and there are apps out there that do this) an OS X app that accepts arbitrary .sh files and executes them. However, that's generally a bad idea as it could open you up to attacks if you inadvertently download a malicious shell script file that is automatically opened by your web browser. Better to be explicit.

How to launch an app on OS X with command line - The best way

I want to launch an app on OSX from a script. I need to pass some command line arguments. Unfortunately, open doesn't accept command line args.
The only option I can think of is to use nohup myApp > /dev/null & to launch my app so it can exist independently of the script that launches it.
Any better suggestions?
As was mentioned in the question here, the open command in 10.6 now has an args flag, so you can call:
open -n ./AppName.app --args -AppCommandLineArg
In OS X 10.6, the open command was enhanced to allow passing of arguments to the application:
open ./AppName.app --args -AppCommandLineArg
But for older versions of Mac OS X, and because app bundles aren't designed to be passed command line arguments, the conventional mechanism is to use Apple Events for files like here for Cocoa apps or here for Carbon apps. You could also probably do something kludgey by passing parameters in using environment variables.
An application bundle (.app file) is actually a directory. Instead of using open and the .app filename, you can move into the app's directory and start the actual machine code program located inside. For instance:
$ cd /Applications/LittleSnapper.app/
$ ls
Contents
$ cd Contents/MacOS/
$ ./LittleSnapper
That is the actual binary executable that might accept arguments (or not, in LittleSnapper's case).
In case your app needs to work on files (what you would normally expect to pass as: ./myApp *.jpg), you would do it like this:
open *.jpg -a myApp
You can launch apps using open:
open -a APP_YOU_WANT
This should open the application that you want.
open also has an -a flag, that you can use to open up an app from within the Applications folder by it's name (or by bundle identifier with -b flag). You can combine this with the --args option to achieve the result you want:
open -a APP_NAME --args ARGS
To open up a video in VLC player that should scale with a factor 2x and loop you would for example exectute:
open -a VLC --args -L --fullscreen
Note that I could not get the output of the commands to the terminal. (although I didn't try anything to resolve that)
I would recommend the technique that MathieuK offers. In my case, I needed to try it with Chromium:
> Chromium.app/Contents/MacOS/Chromium --enable-remote-fonts
I realize this doesn't solve the OP's problem, but hopefully it saves someone else's time. :)
Lots of complex answers when you can simply access Applications folder and type:
open -a [APP NAME]
This is it!
I wanted to have two separate instances of Chrome running, each using its own profile. I wanted to be able to start them from Spotlight, as is my habit for starting Mac apps. In other words, I needed two regular Mac applications, regChrome for normal browsing and altChrome to use the special profile, to be easily started by keying ⌘-space to bring up Spotlight, then 'reg' or 'alt', then Enter.
I suppose the brute-force way to accomplish the above goal would be to make two copies of the Google Chrome application bundle under the respective names. But that's ugly and complicates updating.
What I ended up with was two AppleScript applications containing two commands each. Here is the one for altChrome:
do shell script "cd /Applications/Google\\ Chrome.app/Contents/Resources/; rm app.icns; ln /Users/garbuck/local/chromeLaunchers/Chrome-swirl.icns app.icns"
do shell script "/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --user-data-dir=/Users/garbuck/altChrome >/dev/null 2>&1 &"
The second line starts Chrome with the alternate profile (the --user-data-dir parameter).
The first line is an unsuccessful attempt to give the two applications distinct icons. Initially, it appears to work fine. However, sooner or later, Chrome rereads its icon file and gets the one corresponding to whichever of the two apps was started last, resulting in two running applications with the same icon. But I haven't bothered to try to fix it — I keep the two browsers on separate desktops, and navigating between them hasn't been a problem.
Beginning with OS X Yosemite, we can now use AppleScript and Automator to automate complex tasks. JavaScript for automation can now be used as the scripting language.
This page gives a good example example script that can be written at the command line using bash and osascript interactive mode. It opens a Safari tab and navigates to example.com.
http://developer.telerik.com/featured/javascript-os-x-automation-example/
osascript -l JavaScript -i
Safari = Application("Safari");
window = Safari.windows[0];
window.name();
tab = Safari.Tab({url:"http://www.example.com"});
window.tabs.push(tab);
window.currentTab = tab;
Simple, here replace the "APP" by name of the app you want to launch.
export APP_HOME=/Applications/APP.app/Contents/MacOS
export PATH=$PATH:$APP_HOME
Thanks me later.
With applescript:
tell application "Firefox" to activate
Why not just set add path to to the bin of the app. For MacVim, I did the following.
export PATH=/Applications/MacVim.app/Contents/bin:$PATH
An alias, is another option I tried.
alias mvim='/Applications/MacVim.app/Contents/bin/mvim'
alias gvim=mvim
With the export PATH I can call all of the commands in the app. Arguments passed well for my test with MacVim. Whereas the alias, I had to alias each command in the bin.
mvim README.txt
gvim Anotherfile.txt
Enjoy the power of alias and PATH. However, you do need to monitor changes when the OS is upgraded.
To Create a New Text File OR open an existing one, in any folder, using a Text/Code Editor like the Free TextMate app on MACOSX, use this command on Terminal:
open -n /Applications/TextMate.app --args "$PWD/some file.txt"
Instead of a Text File, you can use any file type, based on your app's requirements and its support for this syntax.
This command also simulates the New Text Document Here Command on Windows and has been tested on MacBook Pro 2021 and Monterey 12.2.1 successfully.

Resources