A disclaimer before we create our AIR installers for Mac and Windows: this is for AIR 1.5! Adobe has not yet released the redistributable for AIR 2.0, though AIR 2.0 GA release is expected in the first half of 2010. However, everything we are doing here should work in AIR 2.0. The Native Installers in AIR 2.0 throw in a little twist, but is should be noted that the Native Installers a) will NOT install/update the AIR runtime, and b) also will NOT (I believe) support silent install/uninstall by themselves, but only via the AIR redistribution mechanism, outlined here.
Some tools we will need.
On Mac:
- XCode (free)
- A good text editor, such as TextWrangler (free)
- A log viewer; the Console App built into Mac works fine
- A Mac installer maker; PackageMaker (part of the XCode download) works fine
- Visual Studio 2008 (pay) or Visual C++ 2008 Express Edition (free)
- A good text editor, such as Notepad++ (free)
- A log viewer; you can use tail -f in cygwin (free), or use BareTail (free version)
- A Windows installer maker; I used InstallJammer (free)
Installer scenarios (work silently on both Mac and Windows):
- Machine lacks both AIR Runtime and AIR app.
- Machine has AIR Runtime, but is missing AIR app.
- Machine has both AIR Runtime and AIR app, but needs to upgrade app.
The Windows and Mac installers do the same actions:
- Copy AIR installer files to a temporary directory.
- Check if the AIR app is installed (via OS-specific calls) and, if it is installed, uninstall it (also OS-specific calls).
- Check the version of AIR Runtime currently installed (if any) and install or update as needed.
- Install the AIR app.
- Delete the temporary directory.
Step #2 above requires writing an OS-specific native program (in Visual Studio or XCode) and an OS-specific script file (BAT file or bash shell script).
It works like this:
- The installer program (created with InstallJammer or PackageMaker) calls the script file.
- The script file calls the native program to get information about the installed AIR app, if it is installed.
- The script file gets the exit code and stdout from the native program.
- If the exit code is 0, the stdout is the OS-specific app info (a GUID for Windows and an absolute path for Mac), and the script then uninstalls the AIR app (“msiexec /x {GUID}” on Windows, and “rm –rf {PATH}” on Mac).
- If the native program exit code is 1, the AIR app is not installed, and the script does nothing.
- Any other exit code is an error and is reported back to the installer and fails the install.
The Windows Installer depends upon a native app created by Oliver Goldman, in this post. You can download his code from his blog post.
I made one small change to remove the DLL dependency on msvcr90.dll (you can see this dependency with Dependency Walker). Msvcr90.dll is not guaranteed to be on all Windows machines, so it is better to not have the dependency. In the msiutils project properties, go to General Properties > C++ > Code Generation. In the Configuration drop-down, change to Debug if is not already displaying Debug. In the right pane, go to Runtime Library and change to "Multi-threaded Debug (/MTd)". Change the Configuration drop down to Release, and change Runtime Library to "Multi-threaded (/MT)". See this documentation at MSDN for more info. Build the Release version, and you can see with Dependency Walker that it no longer depends on mscvr90.dll; it depends (directly) only on msi.dll and kernel32.dll, which are on all Windows Machines (at least with XP or later OS). The trade-off is that msiu2p.exe is 53 KB as opposed to the 8 KB version from Oliver's example.
Next we need a Batch file named install.bat to drive the msiu2p.exe native program.
@echo off
cd %~dp0
:checkIfInstalled
REM echo Checking if older version installed
set OSID={8209FAF5-4714-5CB1-20B5-9D840B252637}
REM echo OSID=%OSID%
set AIR_APP=yourApp.air
REM echo AIR_APP=%AIR_APP%
REM must redirect stderr as well, or InstallJammer sees existence of any stderr as a failure
%~dp0msiu2p.exe %OSID% > msiu2p.out 2>&1
REM Bad error in msiu2p.exe, exit this script
if ERRORLEVEL 2 EXIT /B 1
REM ERRORLEVEL 1 just means the app was not previously installed, so go to install step
if ERRORLEVEL 1 goto install
:uninstall
REM echo Attempting to uninstall
SET /p PROD_GUID= < msiu2p.out
msiexec /q /x %PROD_GUID%
REM check to see if an error occurred in msiexec (error 1603 if not run as administrator)
if ERRORLEVEL 1 echo ERRORLEVEL=%ERRORLEVEL%
if ERRORLEVEL 1 EXIT /B 2
:install
REM echo installing
@call installer -silent -eulaAccepted -desktopShortcut -programMenu -location %1 %AIR_APP%
REM echo install ERRORLEVEL=%ERRORLEVEL%
REM ERRORLEVEL 1 indicates success, but reboot required
if ERRORLEVEL 2 EXIT /B 3
EXIT /B 0
You will need to make 2 changes to the BAT file:
- Change the line "set OSID=" to the Windows OSID of your AIR app (see Part 2 for how to get the OSID).
- Change the line "set AIR_APP=" to the correct name of your AIR file.
We will also creating another Batch file named test.bat to test install.bat.
@echo off
@call %~dp0install.bat "%ProgramFiles(x86)%"
echo ERRORLEVEL=%ERRORLEVEL%
pause
Save install.bat, msiu2p.exe, and test.bat in the same directory. Run a command line prompt, cmd.exe. Be sure to "Run as Administrator" on Vista and 7. Make sure your AIR app is currently not installed (Add/Remove Programs or Programs and Features in Control Panel). In the command line prompt, run test.bat. It should run with exit code (ERRORLEVL) 0. The Batch file determined your AIR app was not installed and did nothing.
Next, manually install your AIR app by double-clicking on the AIR file. Confirm the AIR app is installed. In the command line prompt, run test.bat. It should run with exit code (ERRORLEVEL) 0, AND your AIR app should be uninstalled.
Now, un-comment out the line that begins "@call installer" by removing the REM from the beginning of the line. Go into Control Panel and uninstall both your AIR app and the Adobe AIR runtime. In Part 2, I told you how to get the AIR runtime redistributable files, so you should have access to "AIR_Win_installer_files.zip". Extract the contents of the zip into the same directory as install.bat and test.bat (the zip has a directory named "Adobe AIR" and three files in the top directory, setup.msi, setup.swf, and "Adobe AIR Installer.exe". I renamed the file "Adobe AIR Installer.exe" to just installer.exe, but you can rename it to anything you like, just fix install.bat to call your executable name.
Now from the command line prompt, run test.bat. It should run with exit code (ERRORLEVEL) 0. The AIR runtime and your AIR app should be installed. Verify by making sure your AIR app can run.
Now uninstall just your AIR app in Control Panel. Run test.bat again and your AIR app should be installed once again.
Lastly, just run test.bat (without uninstalling anything). Your AIR app should be uninstalled and re-installed, which you can verify be seeing the difference in the file timestamps of your app in the Program Files (or Program Files (x86)) directory.
We have now tested all three install/update scenarios above.
The AIR installer can log messages to a file named .airinstall.log (note leading dot) in the user's home directory. On Windows, you can see the log file as the install is running with tail -f command in cygwin, or with the BareTail log viewer.
The last part of the Windows Installer is to package everything up with InstallJammer, which I will do in the next post. The InstallJammer installer will call the install.bat file. We will then move onto the Mac installer, which follows the same basic pattern.