I was working with some XUL that was eventually to be part of a Firefox extension, but at the time loading the XUL directly into Firefox. Didn’t take long until I stumbled into the infamous “Error: uncaught exception: Permission denied to create wrapper for object of class UnnamedClass”. Time to break out XULRunner. I hadn’t played with XULRunner since Ubuntu days and it was enough of a pain to set up just right on Ubuntu. On Mac, it’s a right headache.
I started by downloading and installing the XULRunner 1.8.1.3 DMG, then I tried assembling the app files as I’ve done in the past and found that the xulrunner executable would silently fail to launch the app. Turns out I had a good deal more work to do. The clues are scattered all over the Web. On Ubuntu (and I guess Windows) “Getting started with XULRunner” told me all I needed to know. On Mac you need the added magic in “XULRunner:Deploying XULRunner 1.8″. The “myapp” subtree root in the former article corresponds to the “Contents/Resources” directory in the latter. It still wasn’t clear to me how to assemble all the Mac-specific parts and pieces until I found “Cross platform XPCOM (a howto)”.
In the end I just cooked up a BASH script for bootstrapping an app bundle.
ROOT=$1
APPNAME=$2
VENDOR="XUL Hacker"
VERSION=0.1
BUILDID=`date +%Y%m%d`
COPYRIGHT="Copyright `date +%Y` $VENDOR"
ID=xulapp@example.com
#Set up Mac app bundle
mkdir -p $ROOT/$APPNAME.app/Contents/Resources/chrome/content
mkdir -p $ROOT/$APPNAME.app/Contents/Frameworks
mkdir -p $ROOT/$APPNAME.app/Contents/MacOS
#Just soft-link all this stuff for dev. If I were creating a real app they'd have to be real copies
ln -s /Library/Frameworks/XUL.framework $ROOT/$APPNAME.app/Contents/Frameworks/XUL.framework
ln -s ../../app $ROOT/$APPNAME.app/Contents/Resources
ln -s /Library/Frameworks/XUL.framework/Versions/Current/xulrunner $ROOT/$APPNAME.app/Contents/MacOS/xulrunner
cat >> $ROOT/$APPNAME.app/Contents/Info.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>xulrunner</string>
<key>CFBundleGetInfoString</key>
<string>3.0</string>
<key>CFBundleIdentifier</key>
<string>$APPNAME</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>$VERSION</string>
<key>CFBundleName</key>
<string>$APPNAME</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$VERSION</string>
<key>CFBundleSignature</key>
<string>$APPNAME</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>$APPNAME</string>
<key>CFBundleURLSchemes</key>
<array>
<string>chrome</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$VERSION</string>
</dict>
</plist>
EOF
mkdir -p $ROOT/$APPNAME.app/Contents/Resources/defaults/preferences
cat >> $ROOT/$APPNAME.app/Contents/Resources/application.ini << EOF
[App]
Vendor=$VENDOR
Name=$APPNAME
Version=$VERSION
BuildID=$BUILDID
Copyright=$COPYRIGHT
ID=$ID
[Gecko]
MinVersion=1.8
MaxVersion=1.9
EOF
cat >> $ROOT/$APPNAME.app/Contents/Resources/chrome/chrome.manifest << EOF
content $APPNAME chrome/content/
EOF
#content $APPNAME file://`pwd`/$ROOT/$APPNAME.app/Contents/Resources/content
cat >> $ROOT/$APPNAME.app/Contents/Resources/defaults/preferences/prefs.js << EOF
pref("toolkit.defaultChromeURI", "chrome://$APPNAME/content/main.xul");
EOF
With the above in place it’s easy enough to write a Makefile to deploy the meat of the XUL app into the bundle during the dev cycle, throwing in the likes of:
cp $APPNAME.xul $ROOT/$APPNAME.app/Contents/Resources/chrome/content/main.xul
I skimmed a bit of what all the Mac app stuff means “Inside Application Bundles” but obviously I have a ways to go in understanding Apple’s odd conventions bunged into atrocious XML (Really. Those plist files? They’re execrable).
I’ll have to see whether this is the same sort of recipe to run the new capability in FF 3.0 for running XUL apps from the command line.

