It’s alive! Get your Ionic app to update automatically (Part 2)
Woody Rousseau4 min read
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);
deploy.watch().then(function() {}, function() {}, function(updateAvailable) {
if (updateAvailable) {
deploy.download().then(function() {
deploy.extract().then(function() {
deploy.unwatch();
$ionicPopup.show({
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) {
deploy.load();
}
}
],
});
});
});
}
});
};
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.
config.tpl.xml
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" id="<%=appId%>" version="<%=version%>">
<name><%=appName%></name>
<description>Updaty is a great app which self updates</description>
<author email="dev@theodo.fr" href="http://theodo.fr">Theodo</author>
<content src="index.html"/>
</widget>
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:
config.json
{
"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
gulpfile.js
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() {
gulp.src('./config.json')
.pipe(ionicChannels({
channelTag: args.channelTag
}))
.pipe(ngConstant())
.pipe(gulp.dest('./www/js'));
});
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="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" 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="dev@theodo.fr" href="http://theodo.fr">Theodo</author>
<content src="index.html"/>
</widget>
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")
;
gulp-ionic-channels
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
).
gulp-ng-constant
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 bygulp-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 bygulp-ng-constant
:
angular.module('updaty', ['config', 'ionic', 'ionic.service.core', 'updaty.controllers', 'updaty.services'])
You should be good to go!