Building an App Factory

Building similar apps for different brands or products of the same company may sound like easy money. It is also extremely boring. That’s why I try to minimize repetitive work by re-using existing and self-build modules and widgets across different projects. However, if the projects are very similar and only differ in style, contents and configuration it pays off to go beyond that and build an app factory.

What’s an App Factory?

An App Factory can be any (semi)automated process to produce apps. Solutions vary from having a collection of widgets to some kind of framework like ChariTi or a even full back-end. Such a back-end can be a public one like GoodBarber, but also a custom factory.

How I built a custom App Factory

I’ve been building such a custom App Factory for a client lately and in this and some related blogs later on I’d like to share some ideas with you.

The idea

In all simplicity, my approach is the following:

  • Build a white-label app that:
    • Reads all of its styles and settings from a Alloy.CFG, which is the parsed config.json containing the default configuration, extended by a CommonJS module containing the app-specific.
    • Gets all of its data from collections that use a custom Backbone sync adapter reading one CommonJS module per collection. Note: These particular apps needed to require no online data!
    • Runs as-is without needing to go through the factory process, so that I can develop it like any other app.
  • Build a back-end that:
    • Lets the client set styles and settings, including uploading icon and splash.
    • Lets the client add content and assets.
  • Build a process that:
    • Copies the white-label app.
    • Generates a CommonJS module containing all styles and configuration.
    • Generates one CommonJS module per collection of models.
    • (Over)writes assets including fonts, images, media etc.
    • Modifies the id, name, activity, guid and other stuff in tiapp.xml
    • Zips the project for me to download, test and deploy.

The how

I hope to blogs about some of these elements in more detail later on, but here are some short hints on how I implemented this factory:

Full-Stack-JavaScript

I’ve build the app factory in NodeJS using Geddy as MVC. Doing the back-end in JavaScript allowed me to easily move business logic from the app to the factory process. This way I could first focus on building the app and then make it more lightweight.

Extending config.json

The back-end stores all app styles and settings in an app-model. The factory process simply writes the full model to a CommonJS module like this:

fs.writeFileSync(path.join(project, 'app', 'assets', 'data', 'settings.js'), 'module.exports = ' + JSON.stringify(app, null, '  ') + ';');

In the app’s alloy.js I then simply extend the parsed default settings from config.json:

Alloy.CFG = _.defaults(require('data/settings'), Alloy.CFG);

Of course I could also let the factory process read, modify and then write back config.json file itself. I might actually do this later on, as well as moving some other initialization from alloy.js to the factory process, making the app even more lightweight.

Altering tiapp.xml

Another file that needs to be adjusted is tiapp.xml. I actually re-use the back-end model’s guid and of course replace the <name> and <id> values as well. Since the app requires some customizations to AndroidManifest.xml the tiapp.xml also contains the app’s activity classname. To know what this would be I simply took the code from the Android build command:

var className = appName.split(/[^A-Za-z0-9_]/).map(function (word) {
  return word.substr(0, 1).toUpperCase() + word.substr(1).toLowerCase();
}).join('');
/^[0-9]/.test(className) && (className = '_' + className);

In the same way I also modify the configuration files for the ti.urbanairship module, which the app uses for its push notifications.

Icons & Splashes

For the splash screen and app icon I allow the client to upload 2 images. These are then processed by the new TiCons CLI and CommonJS module. Since TiCons uses the project’s tiapp.xml to figure out what files need to be generated I really only have to set a border radius for the Android icon and instruct it to not crop but contain and fill the splash. The input for the splash image is a square file which I require to have a solid background color. For Android TiCons will generate 9-Patch images and for iOS it will resize the image to fit in the required dimensions and then fills the area around it with the color of the outer most pixels.

Data

Since the back-end already stores the data in MongoDB, I decided to simply export each collection of models to a CommonJS module, just like I did for the settings. A very – very – simple custom Backbone sync adapter then reads that so I can use data-binding etcetera:

// app/lib/alloy/sync/common.js
exports.sync = function(method, model, opts) {
  if ("read" === method) {
    opts.success(require(model.config.adapter.collection_name));
    model.trigger("fetch");
  } else {
    throw "common.js sync adapter supports is read-only.";
  }
};

And the just-as-simple model:

// app/assets/data/items.js
exports.definition = {
  config: {
    adapter: {
      type: "common",
      collection_name: "data/items"
    }
  }
};

Alternatives

The right solution for your app factory really depends on what you need and prefer. Some ideas for alternative or even more fully automated approaches:

Alloy themes

Another approach you might consider is using Alloy themes. You could generate all app-specific styles and assets under app/themes/foo and then select this theme in the app/config.json. The advantage would be keeping the app-specific stuff separated from the shared. However, at this moment you cannot theme the i18n and platform folders (ALOY-858) and the config-file itself (ALOY-754). Amongst other reasons, this lead me to not use themes for this specific app factory.

Automating build, test and deploy

Depending on the number of apps the factory produces you can even take it a step further. Instead of zipping the project for download, the factory could even integrate fully automated build, test and deployment. For this particular app factory this is not worth the extra effort.

App imagineer: Imagining, Engineering & Speaking about Native mobile Apps with Appcelerator Titanium & Alloy • Meetup organizer • Certified Expert • Titan


Comments

  • Jaco

    Awesome, you’re on fire with Titatnium! I’ll def be going through the detail when I attempt my own app factory for FlowPress Beta version.