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 184.108.40.206 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" IDfirstname.lastname@example.org #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.