It’s alive! Get your Ionic app to update automatically (Part 2)

In part 1 of this tutorial, we learned how you can get your Ionic app to self-update, to deploy new code whenever needed, instead of having to wait up to two weeks for Apple to review your new versions.

Deploy channels

As with web applications, you may want to first deploy features on a test application (often called staging), to also have a preproduction application, or even to have specific versions to test latest large features (A/B testing for instance).

Ionic Deploy handles this need with channels. You can manage your channels on the Ionic Platform Dashboard‘s Deploy section. By defaut, the “Production” channel is used and a few others were also already created, but you can create a lot more.

Pushing environment specific updates

To push only to a certain environment, just add the --deploy flag. For instance, if you a have a staging channel, you can simply use

ionic upload --deploy staging

I recommend against using the “Production” channel as it is the one used by default when uploading a new version without specifying a deploy value.

Fetching environment specific updates

Let’s say you have an angular constant channelTag being the tag of the channel. Fetching updates only from this specific channel can be done by adding a single line to the code from the first part of the tutorial. Check this out.

.run(function($ionicPopup, channelTag) {
  var deploy = new Ionic.Deploy();
  deploy.setChannel(channelTag); {}, function() {}, function(updateAvailable) {
    if (updateAvailable) { {
        deploy.extract().then(function() {
            title: 'Update available',
            subTitle: 'An update was just downloaded. Would you like to restart your app to use the latest features?',
            buttons: [
              { text: 'Not now' },
                text: 'Restart',
                onTap: function(e) {

One codebase, several applications

Using a single codebase and being able to hold all the versions of your app simultaneously on your phone can be achieved in a few extra steps:

  • You need to be able to generate specific cordova config.xml files for the different versions
  • You need to be able to generate a different channelTag constant for each version of your app

Let’s start by building a config.tpl.xml file, which is to be the template of the cordova config file. Place it on the root of your project.


<widget xmlns="" xmlns:cdv="" id="<%=appId%>" version="<%=version%>">
  <description>Updaty is a great app which self updates</description>
  <author email="" href="">Theodo</author>
  <content src="index.html"/>

A few values are to be injected in the file:

  • The app id (which looks like a reverse url such as a java package name and must match your apple developper app id)
  • The application’s version
  • The application’s name (which will appear below your app icon on the phone). I usually use the application’s real name for the production version, and shortened names containing the environment for other versions of the app.

Let’s now create a config.json file (also placed at the root of your project) which will define those values for each environment:


  "staging": {
    "appId": "fr.theodo.updaty-staging",
    "appName": "Updaty Staging"
  "prod": {
    "appId": "fr.theodo.updaty",
    "appName": "Updaty"

Generating the environment specific files

A simple gulpfile is enough to generate all the files you need. Pick up the following libraries to start off:

npm install --save-dev gulp-ng-constant gulp-ionic-channels yargs


var gulp = require('gulp');
var ionicChannels = require('gulp-ionic-channels');
var ngConstant = require('gulp-ng-constant');

var args = require('yargs').default('channelTag', 'staging').argv;

gulp.task('config', function() {
    channelTag: args.channelTag

Simply running gulp config will generate ./config.xml and ./www/js/config.js for the staging channel tag, and gulp config --channelTag prod will do the same for the prod channel tag.

config.xml (output)

<widget xmlns="" xmlns:cdv="" id="fr.theodo.updaty-staging" version="0.0.1">
  <name>Updaty Staging</name>
  <description>Updaty is a great app which self updates</description>
  <author email="" href="">Theodo</author>
  <content src="index.html"/>

www/js/config.js (output)

angular.module("config", [])

.constant("appId", "fr.theodo.updaty-staging")

.constant("appName", "Updaty Staging")

.constant("version", "0.0.1")

.constant("channelTag", "staging")



I made it all easy for you with this gulp plugin I developed, which takes the config.json file as source, adds to it the version from your package.json file as well as the channelTag passed as an argument, and uses it to:

  • Pass the enriched (and environment filtered) configuration to the next gulp pipe
  • Generate from the template (by default it looks for ./config.tpl.xml) a cordova configuration file (by default ./config.xml).


This useful plugin will generate a javascript file which contains all the angular constants you need from the enriched configuration returned by gulp-ionic-channels, such as the channelTag constant.

Final modifications

You finally need to edit

  • your ./www/index.html file to include the file generated by gulp-ng-constant:
<!-- your app's js -->
<script src="js/config.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>
  • your ./www/js/app.js file to include the module generated by gulp-ng-constant:
angular.module('updaty', ['config', 'ionic', 'ionic.service.core', 'updaty.controllers', ''])

You should be good to go!

You liked this article? You'd probably be a good match for our ever-growing tech team at Theodo.

Join Us

  • Jimmy Jimmy

    how to get part 3 reply me as quick as possible

  • Woody Rousseau

    Hi Jimmy,
    Part 3 is not published yet, but I can do it for next week, would that be useful for you ?



  • Jimmy Jimmy

    ya….dude…i’m soo impressive about your work… wishes….keep update your work…

    thank you soo much for your reply….

  • Deepdark

    I have a multi tenant application, would you recommend just creating a deploy channel for each client or a new ionic app for each?

  • Woody Rousseau

    Hi there,

    If the code is significantly different, you should use a ionic app for each client. If however the only differences are environment variables and a few constants, you should absolutely use a deploy channel for each along with the use of gulp-ng-constant.


  • Carlos De Oliveira

    That looks fine, but if you install a new cordova component it will overwrite your output config.xml, not the template config.tpl.xml, how do you solve this ?

  • Tracy Cheung

    wondering when part 3 would be published

  • Ladna Meke

    Lol, been 3 months already

  • Woody Rousseau

    I don’t have the perfect solution but most plugins will only require you to update your package.json file and if you need to modify the cordova configuration as well, you can always :

    – follow the documentation if there are manual installation instructions
    – install it on a blank cordova project, check the diff on the config.xml and do the same on your project

  • Woody Rousseau

    I truly apologize, I’m not working on the same technical stack since a few months and I have been unable to find the time to make the part 3 (and if I did it probably would not be really relevant anymore) :/

    I’m editing the article to not mention part 3, but thanks for reading. Sorry again

  • Johan

    Hi there Woody and other readers,

    Has anyone come up with a good way to clean up older snapshots? There doesn’t seem to be a simple way to download the unused snapshots.

  • Woody Rousseau

    Hi Johan, I believe the API provides a way to fetch all snapshots and another method to delete one by uuid. However, it says you should not delete the snapshot currently used. I’m not sure how to identify it currently.

  • Thanks for the article Woody – I personally find the Deployment service very confusing – it always downgrades my Production build with a Dev channel snapshot that is very old – have you encountered this?