Creating a bundled AIR / Java Installer on a Mac
A few weeks ago, I wrote a post detailing how to use Merapi in a Production Environment. That tutorial was primarily written to address managing Java and AIR on a Windows Platform including creating an installer that installs both the Adobe AIR Runtime, the Java-side of an application, and the AIR-side of an application. However, I realized that I was neglecting those OS X enthusiasts out there, so this article is for you guys! However, I would still recommend reading Merapi in a Production Environment first for an in-depth overview of integrating Java and AIR through Merapi as this post is only for creating a Mac bundled installer.
The first thing I noticed while trying to make a Mac installer with the bundled Adobe AIR Runtime is that there is relatively little out there that addresses this issue. While there are some resources provided by Adobe after applying for a distribution license, there were still some questions that I had to answer on my own. What will follow is a step-by-step approach that I took to create a Mac installer.
1. Create a Java Installer
The Java installer will serve as the core of our installer. It is responsible for copying class files and jars into the Applications directory and it is also responsible for executing the Adobe AIR Runtime installer which will install both the AIR Runtime on the user’s computer (if they don’t have it already), and installing the AIR-side of the application. Much of this portion I discovered through this post and I won’t go into as much detail as Dem Pilafian covers that material very well.
The tool that I used to initially create a bundled Java app is called “Jar Bundler”. It is located in Developer/Applications/Utilities and is part of XCode. This tool allows you to specify your Main Class, any additional Classes or Jars that are part of the library, an icon, and some configuration options. When you click on the “Create Application” button, you will see that a MyJavaApp.app bundle is created. If you right-click the app bundle and select “Show Contents”, you will see what Jar Bundler created for you. In the Contents folder you will see a PList file (XML-based file which contains the properties for the application), a folder called MacOS which contains the executable, and another folder called Resouces which contains your icon and a subfolder called Java with all the Class and Jar files contained in your Java Application.
At this point you may also have realized what a pain the Jar Bundler is! If you haven’t yet, you will realize it the ump-teenth time you need to create another version of the installer. It doesn’t save an XML configuration file like Launch4j does on the PC, nor does it remember where your previous files selections were so you have to navigate through your Java application looking for class and jar files every single time. Plus, Jar Bundler does not support every application configuration option for your application. That means you have to go into the PList file and do it manually every time.
To solve this problem, I wrote a script which automatically builds the jar files I need and copies them into MyJavaApp.app/Contents/Resources/Java automatically. It also overwrites the PList file that is generated by Jar Bundler to give me more configuration options. Basically, the only thing that remains from Jar Bundler is the executable.
2. Include the AIR Application inside the bundle
After you get the Java bundle set up, it is time to include the AIR portion of the application. Inside of MyJavaApp.app/Contents/Resources, create a directory called AIR. This directory will contain the Adobe AIR Runtime and MyAirApp.air. During the install process we will run the AIR Runtime and pass it a reference to MyAirApp.air to be installed with the runtime.
3. Create an Install Package
With the application bundle in place, we now need to generate an installer. This can be done by using PackageMaker (Developer/Applications/Utilities) or a third party app called Iceberg. I prefer Iceberg due to its intuitive user interface and step-by-step process, however the choice is up to you although I will use Iceberg throughout this tutorial.
Mac install packages are very handy and much easier to create than Windows EXE executables in my opinion. However there are a few things to keep in mind. If you have any custom welcome text, license information, or README this can be displayed in the installer as well. Iceberg allows you to specify text files for each of these three functions in the Documents section. Also, there are Perl or Bash scripts that can be executed during different stages of the install process. You can find these in the Scripts section of Iceberg in their order of execution.
- preinstall: This script is run before files are installed.
- preinstall: This script is run after the preinstall script, but before files are installed. This script is only run if the application has not been installed previously on the target machine.
- preupgrade: This script is run after the preinstall script, but before files are installed. This script is only run if the application has already been installed on the target machine.
- postinstall: This script is run after files have been installed and before the postflight script. This script is only run if the application has no been installed previously on the target machine.
- postupgrade: This script is run after files have been installed and before the postflight script. This script is only run if the application has already been installed on the target machine.
- postflight: This script is run after files have been installed.
Also, keep in mind that each script must return zero. If it doesn’t, the installer will determine that they have failed. For my application, I created a preflight script that checked to see if there were any previous versions of the app and then I removed them. I also created a postflight script that installed the .air application inside of the already created MyApp.air inside of the Applications directory. The script contained a couple of lines that looked something like this:
1 2 3 | cd /Applications/myApp.app/Contents/Resources/AIR Adobe_AIR_Installer.app/Contents/MacOS/Adobe\ AIR\ Installer -silent -location /Applications/myApp.app/Contents/Resources/AIR MyAirApp.air |
Now that I have explained some of the components of a Package, let’s open up Iceberg and get started. First, create a new project and go through each of the steps customizing the installer to fit your specifications. Add any custom text files or scripts and then define where your app will be installed. I put MyApp.app under the Applications directory. When you are finished configuring the package, go to the Build menu and select Build and Run. This will allow you to test your package and scripts to see how well they work. Also, make sure to save your project when you are finished. This will keep your configuration settings as a .packproj file that you can use to make future builds.
[...] post is for Windows installers, for Mac-based installers, see my more recent post. For the installation, the plan we came up with was that our installer would unpack 2 [...]
hey, thanks for quickly putting up the instruction for macOS. the steps work perfect for me. i have been successfully create installer bundled with AIR runtime and my air app.
I also need to bundle the JRE in the installer. But I realized that MacOS has java in its standard installation and OS update as well. Also there are different versions of JREs.
Can you give more details about installing the JRE during the installer process?
I guess JRE are bunch of jars and resource files for MacOS. Or I need to do it is unpack and then set up java_home and class_path. right?
thanks,
Glad to hear it helped
A while ago, Apple decided to bundle Java automatically on their operating system. When they did this, they rewrote some of the underlying Java framework to make it compatible with the OS and have the GUI end look like native applications. Effectively this cut them off from Sun’s implementation of Java.
Long story short, Apple no longer supports Sun’s version of Java nor the OpenJDK movement. As a result, Apple is lagging behind Windows and Linux versions of Java between 6 – 9 months.
If you have Tiger or above, you will have Java 1.5. If that version works for you, you’re in luck. If you need Java 1.6, you must have a 64 bit Intel processor and Leopard to use Apple’s version of Java, or you can try SoyLatte which professes to be a backward compatible Java port for OSX that works on all Intel-based Macs and complies with OpenJDK.
Luckily for me, the application we are running uses Java 1.5, so we don’t have to bundle the SoyLatte JRE or rely on Apple for Java 1.6. 1.5 seems to just work for Tiger and above. So, in our installer we make sure the user has Tiger or higher, otherwise we tell them to perform a Software Update.
If you need to bundle SoyLatte for whatever reason, you may want to check out this tutorial.
thanks for the information, that is very helpful.
regarding the postflight script you have, that is for the case that user doesn’t have AIR runtime installed on the Mac.
if user does have the AIR runtime installed already, that script won’t work. so i write script like this:
if [ -d /Applications/Utilities/Adobe\ AIR\ Uninstaller.app ]
then
/Applications/Utilities/Adobe\ AIR\ Uninstaller.app/Contents/MacOS/Adobe\ AIR\
Installer -uninstall
fi
Adobe\ AIR\ Installer.app/Contents/MacOS/Adobe\ AIR\ Installer -silent -location
/Applications/Annotare.app/Contents/Resources/AIR Annotare.air
Actually, the silent AIR installer will only install the AIR Runtime if you don’t have it (or if you have a different version). If you do, it will bypass the AIR Runtime install and move on to installing the AIR application. So, you shouldn’t have to check to see whether the runtime is installed because the installer handles it without any problems.
My installer gets as far as running the script and then dies. It won’t run the script. I’ve tried adding the script ot eh files and giving everyone full permissions, but I can’t get it to run the script for the life of me. Probably a total n00b question… but I’m stuck.
Matt, can you give us more information? Maybe post the script that fails?
Matt, Did you every resolve your issue I’m having the same problem. The shell script works fine in the terminal, but dies in the package install
I am interested in hiring someone who can create a installation package for us using this method described above, please contact me at creditumbrella@gmail.com if interested
Thanks
I just wrote a library called Transmission which uses AIR 2.0 native process to start up a Java jar in your project and receive messages via standard output in much the same way that Merapi did. The biggest benefit is that you don’t have to create a custom installer (you can use the native AIR 2.0 installer for both PC and Mac), and you also can use the AIR updater framework.
Check it out here.