A good(and more than often required) software development practice is to always automatically maintain different configurations for development and production. I talked about achieving it here briefly in this blog post where we used environment variables in Ionic to enable or disable error logging.
Some configuration for Ionic and Cordova apps resides in config.xml
and we want to separate it for development and production environments. Some examples would be:
- Different API keys for Development and Production for external services such as google maps
- Maintaining different names of the app in order to install both Development and production versions of the app
- Configuration settings for Microsoft Code-Push
Again, there is no built in mechanism which ships with Ionic. In the post below we will see how to maintain configuration for Ionic apps and also do an end to end setup for tasks such as generation of APKs, deploying updates using Microsoft App center.
config.xml version management
We will be using NPM tasks for everything and it seems to work perfectly going forward. We will be adding the below commands to package.json
and run them using npm run command
. There are other ways to do this, using Task runners such as Grunt. The good thing about this setup: 0 dependencies
First, we create 2 configuration files in config/
folder, dev.xml
and prod.xml
. We will create tasks to copy the correct config.xml file.
"copy-config:dev": "cp config/dev.xml config.xml", "copy-config:prod": "cp config/prod.xml config.xml",
Running the app
Now we will simply create more npm commands to Run apps using dev / prod settings.
"dev": "npm run copy-config:dev && ionic cordova run android", "prod": "npm run copy-config:prod && ionic cordova run android --prod",
These can be executed for example using npm run dev
. Any additional parameters can be added to the command line script using --
Examples:
npm run dev # Start Dev app npm run dev -- --livereload # Start using livereload
Deploying using Microsoft AppCenter
We use the Microsoft’s Hot code push deployment procedure to deploy live code updates to our customers. It supports 2 environment, a Staging and a Production. Only Production updates are deployed to users running the app built using --prod
variable from Ionic.
"code-push": "code-push release-cordova kunalgrover05/LeanNutri android", "deploy-dev": "npm run copy-config:dev && npm run ionic:build && npm run code-push", "deploy-prod": "npm run copy-config:prod && npm run ionic:build --prod --release && npm run code-push -- -d Production",
Another important aspect when using CodePush is which version do the updates apply to. The default is to just apply updates to the current version. The version can either be set in the AppCenter dashboard or as an additional command line parameter.
For example, to deploy updates for all users with version above 1.0.0:
npm run deploy-prod -- -t ">1.0.0"
Versioning
Let’s go to Version management. This is extremely important for any production app to correctly manage and sync versions of code on Git, APKs delivered to users and the deployments done using Hot code push.
We use a common version in all of our config files, in package.json and also our APKs. We would be using NPM’s versioning which is synced to Git tags. We will need to script up to sync it with APKs and Code push deployments. NPM versions support 3 layers: [MAJOR VERSION].[MINOR VERSION].[PATCH VERSION]
Taking inspiration from this blog post, we will add a script and add it to package.json which will execute it whenever the pre-defined version
command is called.
"version": "./change-version.sh"
Here is the file to be executed. It simply changes the version in config.xml
, dev.xml
and prod.xml
whenever npm version
is executed.
#!/bin/bash NEW_VERSION=${npm_package_version} echo $NEW_VERSION for CONFIG in config.xml config/dev.xml config/prod.xml; do echo $CONFIG if [ -e $CONFIG ]; then # sed to replace version in config.xml sed -i "s/(widget.*version=")([0-9,.]*)"/1$NEW_VERSION"/" $CONFIG git add $CONFIG echo "Updated $CONFIG with version $NEW_VERSION" else echo 'Could not find config.xml' exit 1 fi done;
Building APKs
Finally, some commands to be able to create and package an APK. I have used the $npm_package_version
environment variable to be able to define the version in the APK.
"jarsign": "jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore leanagri.keystore platforms/android/app/build/outputs/apk/release/app-release-unsigned.apk leanagri", "zipalign": "rm -f builds/LeanNutri-$npm_package_version.apk && zipalign -v 4 platforms/android/app/build/outputs/apk/release/app-release-unsigned.apk builds/LeanNutri-$npm_package_version.apk", "apk-prod": "npm run copy-config:prod && ionic cordova build android --prod --release && npm run jarsign && npm run zipalign",
The APK can be built by using npm run apk-prod
What’s here and what’s missing?
We finally have the ability to programmatically use multiple configurations for our app, and also deploy them to Android apps or using AppCenter. We also have complete version management for our app allowing us to have a scalable release management.
I still don’t have here how to make config update automatically as expected when you add / remove any plugin using cordova plugin add plugin
. It is still required to manually add any new plugin in both dev.xml
and prod.xml
whenever a plugin is added or upgraded.