TITANIUM BUILD PLUGINS, HOOKS, AND COMMANDS IN SDK 3.X.X

Many times when developing apps you need to use tools that can automate your workflow. Titanium allows you to integrate your tools with compile/build steps using plugins or hooks. Until v3.x of Titanium, these plugins were built using python, but now they can be built using NodeJS! Just one issue… it’s not yet documented how to do this. So to help out the community, we have assembled this quick intro to NodeJS plugins for Titanium.

Plugins can go in either a “plugins” folder in your project or in the global (~/Application Support/Titanium/plugins). Then create a plugin folder such as “myplugin” for example. In there, create a version directory like “1.0″. In that folder you can have a plugin.py (Note: the py files only work for Titanium 2.1.4.GA and below or Android builds) as well as a “hooks” and “commands” folder. You can name the js files in the “hooks” folder anything you want. Currently all plugin JS files are loaded. As for commands, it has as of this writing not been fully tested by Appcelerator, so good luck.

JS files in the commands folder that begin with _ are ignored by the CLI command scanner. This is how you can hide commands from the CLI. Appcelerator does this in the SDK for each platform’s _build.js so that the CLI only picks up the build.js in the SDK level commands folder. The reason Chris Barber built it that way is so they can support platform specific commands. For example, they anticipat having a fastdev.js command in android/cli/commands, but I am told they just haven’t had time to do that yet.

So if you do this, the path to your JS based build plugin/hook would look something like this:

/path/to/myproject/plugins/myplugin/1.0/hooks/myhook.js

To activate a hook plugin, you have 2 options:

– Add the plugin directory to your config’s plugin path

– You enable it in your tiapp.xml.

If you set the plugin path in the CLI config, then these paths are scanned for EVERY command across all projects. If you only want a plugin to work for a single project, then use the tiapp.xml.

titanium config paths.plugins /path/to/myplugin -a

(The CLI config is in ~/.titanium/config.json and the paths.plugins is an array of paths, so you need to use -a to append a path to the existing values)

And here’s what it looks like in the tiapp.xml.

<plugins>

<plugin version=”1.0″>myplugin</plugin>

</plugins>

Note that the version attribute is not required. If you don’t specify it, it will select the latest version.

Current supported hook events are:

build.pre.construct – fires before the build even starts

build.pre.compile – build state is initialized, but build has not begun

build.prerouting – fired from within the Xcode pre-compile phase after files have been minified/copied… currently does NOT fire for simulator builds

build.post.compile – fired after build is complete (both successful and unsuccessful builds)

build.finalize – fired after build ends and analytics have been sent… sort of pointless and only exists for parity with old plugin.py system

 

Here’s an example plugin:

exports.cliVersion = '&gt;=3.X';

exports.init = function (logger, config, cli, appc) {

    cli.addHook('build.pre.compile', function (build, finished) {

        // "build" arg contains the state of the build

        // note: "build" arg is null for "build.pre.construct" event

        logger.log("you're doing a " + build.deployType + " type build!");

        finished(); // remember to call finished!

    });

};

 

You can look in the iphone/cli/hooks folder of the Titanium SDK to see more examples that are actually in use. Alloy uses a plugin too, it’s a little complicated to read but it’s there.

The plugin system in still undocumented and needs a bit more fleshing out. We currently only have hooks for the “build” command. I’d like to add hooks for the “clean” and “create” as well as more hooks in the actual “build” commands. The events will probably vary based on platform.

You can have multiple hooks attach to an event. You can also set the “priority” (I know, bad name) to control the order in which the hooks run:

 

exports.cliVersion = '&gt;=3.X';

exports.init = function (logger, config, cli, appc) {

    cli.addHook('build.pre.compile', {

        priority: 10,

        post: function (build, finished) {

           logger.log("I'm super important");

           finished();

        }

    });

    cli.addHook('build.pre.compile', {

        priority: 2000,

        post: function (build, finished) {

            logger.log("I'm not that important");

            finished();

        }

    });

};

Default priority for all hooks is 1000.

So now to the command plugins mentioned at the outset… they are a little more “gray area” since they have had the least amount of testing and aren’t really used anywhere. In theory you can create a plugin with a “commands” folder, then drop a *.js file in there. Then you need to add the path to the plugin to the CLI config by running:

titanium config paths.commands /path/to/myplugin/1.0/commands

As long as it does NOT start with a _, the CLI will add it to the list of commands. This part of the plugin system needs some love to iron out the kinks. You can see an example command by looking at the built-in titanium commands or checkout slide 33 from Chris Barber’s Codestrong 2012 presentation here: http://www.slideshare.net/cb1kenobi/exploring-the-titanium-cli-codestrong-2012.

Have questions or comments? Hit us up on twitter! And a special thanks to Chris Barber for his help and examples!