One of Ionic's strengths is in the services that it offers on top of the framework. This includes services for authenticating users of your app, push notifications, and analytics. In this series, we're learning about those services by creating apps which make use of them.
In this post, we're going to take a look at Ionic Deploy. This service allows you to publish changes to your Ionic app without the need for recompiling and re-submitting it to the app store. This is very useful for quickly pushing bug fixes, minor updates and other cosmetic changes to the app. With the "Deploy Channels" feature, you can also perform A/B tests by introducing different code changes to different deploy channels.
Not all changes that you want to introduce to your app can be pushed using Ionic Deploy, though. Only changes to your HTML, CSS, JavaScript, and assets under your www directory can be pushed this way. Binary changes such as updates to the Cordova platform version, Cordova plugins (either updating existing ones or adding new ones), and app assets such as the icon and splash screen cannot be pushed using Ionic Deploy.
How It Works
In your Ionic app, you can have code that will check for available deployments (updates). By default, it will check for deployments in the production
channel. But you can also specify other channels to receive updates from.
You can then push your changes using the ionic upload
command. This will upload your changes to Ionic Cloud. Once they're uploaded, you can choose which channel you wish to deploy to, and whether to deploy now or at a later time.
Deploying to a channel that your app is monitoring will trigger the code in your app to execute. That code is then responsible for downloading the update, extracting it, and reloading the app to apply the changes.
What You'll Be Building
In this post, you'll be using the command line to push the changes and test if the deploy works as expected. To keep things simple, the changes that we're going to introduce will be mainly to the UI. For every deploy, we're going to change the version number displayed for the app. We're also going to change the image displayed on the app to show that assets can be updated as well.
Setting Up
Now that you have an idea of how Ionic Deploy works and what you will be building, it's time to get your hands dirty by actually creating an app which uses Ionic Deploy. Start by bootstrapping a new Ionic app:
ionic start --v2 deployApp tabs
The command above will create a new app using the tabs template. Navigate inside the deployApp
directory once it's done installing:
cd deployApp
Next, you need to install the @ionic/cloud-angular
package. This is the JavaScript library for the Ionic Cloud service. It allows us to interact with the Ionic Deploy service and other Ionic services via JavaScript code.
npm install @ionic/cloud-angular --save
Once that's done installing, you can now initialize a new Ionic app based on this app. Before you do so, make sure that you already have an Ionic account. The command line tool will prompt you to log in with your Ionic account if you haven't done so already.
ionic io init
This will create a new app named "deployApp" (or whatever you named your app when you bootstrapped a new Ionic app) under your Ionic apps dashboard.
Once you've verified that the app is listed on your Ionic dashboard, go back to the terminal and install the Deploy plugin:
cordova plugin add ionic-plugin-deploy --save
Note that this plugin is the one which actually does the heavy lifting. The @ionic/cloud-angular
package simply exposes the APIs required for easily working with the Ionic services inside an Ionic app.
Working With Deploys
Now that you have done all the necessary setup, it's time to add the code for checking and applying updates. But before you do that, first serve the app through your browser:
ionic serve
This allows you to check whether the code that you've added is working or not. This way you can make the necessary corrections as soon as you see an error.
Open the src/app/app.module.ts file. Under the SplashScreen
import, import the services needed for working with Ionic Cloud:
import { SplashScreen } from '@ionic-native/splash-screen'; // add the following: import { CloudSettings, CloudModule } from '@ionic/cloud-angular';
Next, add the app_id
of your Ionic app. You can find this on your Ionic app dashboard, right below the name of the app.
const cloudSettings: CloudSettings = { 'core': { 'app_id': 'YOUR IONIC APP ID' } };
Once you've added that, you can now include it as one of the modules of the app:
@NgModule({ declarations: [ //... ], imports: [ BrowserModule, IonicModule.forRoot(MyApp), CloudModule.forRoot(cloudSettings) // <-- add this ], });
Next, open the src/app/app.component.ts file. Right below the TabsPage
import, include the following:
import { TabsPage } from '../pages/tabs/tabs'; // add these: import { AlertController, LoadingController } from 'ionic-angular'; import { Deploy } from '@ionic/cloud-angular'; // import the Deploy service from @ionic/cloud-angular package
In the constructor()
, add the services that we imported earlier:
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, public deploy: Deploy, private alertCtrl: AlertController, private loadingCtrl: LoadingController){ //... }
Setting the Deployment Channel
Since we're still developing the app, set the deployment channel to dev
:
this.deploy.channel = 'dev';
Later on, if you want to switch to the production channel, you can simply remove this line as production
is the default channel for deployments. If you have created another channel, you can also include its name here.
Working With Snapshots
You can access an array of snapshots that have been previously downloaded by the app. The snapshots
variable is an array containing the IDs of each of the snapshots.
this.deploy.getSnapshots().then((snapshots) => { console.log('now getting snapshots...'); console.log(snapshots); });
We won't really be using snapshots for this app, but it's good to know that the app is storing this type of information for later use. In the example below, we'll go through the list of old snapshots and delete each one to free up some space on the device.
snapshots.forEach((snapshot_id) => { this.deploy.getMetadata(snapshot_id).then((metadata) => { // do something with metadata }); // delete snapshot this.deploy.deleteSnapshot(snapshot_id); });
Checking for Updates
To check for updates, use the check()
method. This returns a boolean value that tells you whether a new snapshot is available or not. By default, the latest deploy will create a new snapshot. So only the latest deploy will be applied if you pushed two updates consecutively.
this.deploy.check().then((snapshotAvailable: boolean) => { // ... });
If a snapshot is available for download, you can get additional information about it by calling the getMetaData()
method. This metadata can be added to a deploy through the Ionic app dashboard. Key-value pairs can be added here, and each of them becomes available as a property for the metadata
object. Later on, we will be using metadata to customize the messages shown in the app every time a new update becomes available.
if (snapshotAvailable) { // get metadata this.deploy.getMetadata().then((metadata) => { console.log('now getting metadata..'); console.log(metadata); }); }
Next, show a confirmation alert message to let the user decide whether they want to download the update or not:
let alert = this.alertCtrl.create({ title: 'Version ' + metadata.version + ' is available', message: 'Do you want to download this update?', buttons: [ { text: 'No', role: 'cancel', handler: () => { // do some stuff (e.g. add analytics code for counting how many users didn't apply the update) } }, { text: 'Yes', handler: () => { // proceed with downloading the update } } ] }); alert.present();
You might be concerned that this would annoy the user if they continue to receive the prompt to update their app if they keep responding "No". More often that not, though, this is actually a good thing. There shouldn't be any reason for a user to reject an update if it's going to improve their experience.
Downloading and Applying Updates
When the user agrees, you can go ahead and download the update. This may take a while depending on your internet connection and your device. Once the update is downloaded, show a loader to attract the user's attention while it extracts. Once it's extracted, reload the app and hide the loader.
this.deploy.download().then(() => { // download is done console.log('download completed!'); // show loader let loading = this.loadingCtrl.create({ content: 'Now reloading the app...' }); loading.present(); // extract the update this.deploy.extract().then(() => { console.log('extract completed!'); this.deploy.load(); // reload the app to apply the changes console.log('reload completed!'); loading.dismiss(); }); });
Take a look at what the updated app.components.ts file should look like after all those changes.
Installing the App on the Device
Now that the code for checking deploys is added, we can build the app and install it on a device. The rest of the changes that we're going to introduce will be primarily pushed through the Ionic Deploy service.
Go ahead and add the android platform to your Ionic project and build the .apk file with the following commands:
ionic platform add android ionic build android
This will create an android-debug.apk file inside the platforms/android/build/outputs/apk folder. Copy it to your device and install it.
Pushing Changes
Now it's time for us to push some changes to the app. To try it out, just make some minor changes to the app UI. And now you can upload the changes:
ionic upload
Adding Metadata
Once it's done uploading, a new entry will be listed in your Recent Activity. Click the Edit link of that entry. This will allow you to add a note, versioning information and metadata to that specific release. It's always a good idea to add a note so you know what that specific release is all about. Once you've done so, click on the Metadata tab and add the following:
Then click on the Save button to commit your changes. Finally, click on the Deploy button to deploy the release. Once the app picks up on the change, the metadata that you supplied also becomes available.
You can see that it now shows the version number of the release:
Versioning
Sometimes you will push an update out with Ionic Deploy, but also rebuild and ship those packages to the bundled app in the App Store. Watch out, though, because Ionic doesn't know that your app already contains that update, and your app will prompt the user to download the latest updates the first time your app is run.
The versioning feature can help prevent this. With the versioning feature, you can specify the version of the app which can receive the updates:
- Minimum: deploys only if the current app version is higher or equal to this version.
- Maximum: deploys only if the current app version is equal or lower than this version.
- Equivalent: do no perform a deploy if the current app version is equal to this version.
You can add versioning information by clicking on the EDIT link on a specific release, and then going to the VERSIONING tab. From there, you can specify the versions (either iOS or Android) that you want to target.
What Ionic does is compare this version with the one that you specified in your config.xml file:
If the app version falls between the minimum and maximum specified, the release is picked up. And if the app version is equal to the equivalent version value, the release is ignored. So for the above screenshot, if the version indicated in the config.xml file is 0.0.1
, the release will be ignored by the app.
Asset Updates
The next change that we're going to make is to show an image.
The first thing that you need to do is find an image. Put it inside the src/assets/img folder and link it from the src/pages/home/home.html file:
<ion-header><ion-navbar><ion-title>Home</ion-title></ion-navbar></ion-header><ion-content padding><ion-card><img src="assets/img/lightning.png" /><ion-card-content><ion-card-title> Version 4</ion-card-title></ion-card-content></ion-card></ion-content>
Upload your changes as a new release to Ionic Deploy.
ionic upload
Once uploaded, go to your Ionic app dashboard and update the release with a note and the corresponding version
in the metadata. Save the changes and deploy it.
Opening the app should now pick up this new release, and updating it would apply the changes to the UI.
Deploy Channels
By default, Ionic Deploy has three channels which you can deploy to: dev
, staging
, and production
. But you can also create new channels for your app to listen for updates on. You can do that by clicking on the gear icon on the Ionic Deploy tab on your app dashboard:
This is useful for things like A/B testing, so you can push specific changes to specific users only.
Don't forget to update your code to use that specific deploy channel:
this.deploy.channel = 'me';
Rollback
If you've pushed something you shouldn't have, you could use the rollback feature. With this feature, you can push a previous release back to your users.
Note that you can't fix broken code by rolling back! For example, if you have a syntax error in your JavaScript code, it will break the whole app and the code for checking for updates won't ever run. To fix those kinds of errors, the only thing you can do is release a new version on the app store.
You can rollback by clicking on the Roll back to here link on any given deploy.
This will ask you to confirm whether you want to roll back or not. Once confirmed, it will be automatically set as the current release. So the code for picking up new releases will recognize it as the latest release and will prompt users to update. Rolled back releases will have an orange refresh icon.
You can also deploy a specific release by clicking on the Deploy link beside the release that you want to deploy.
Using Git Hooks
You can automate the deployment of app updates on Ionic Deploy with Git hooks. Git hooks allow you to execute scripts before or after specific Git events such as commit, push, and receive. In this case we will be using the pre-push
hook to upload our changes to Ionic Cloud right before the git push
command does its thing.
Start by renaming the sample pre-push
script to the actual name recognized by Git:
mv .git/hooks/pre-push.sample .git/hooks/pre-push
Open the file in your text editor and replace its contents with the following:
#!/bin/sh echo now pushing changes to Ionic deploy ionic upload
Now commit your changes and push them to a remote repo:
git add . git commit -m "make some changes..." git push origin master
Right before the git push
command is executed, ionic upload
will be executed.
You can also automatically deploy the release if you want:
#!/bin/sh echo now pushing changes to Ionic deploy ionic upload --deploy dev
This won't work for our example, though, because you can't specify metadata!
If you want to take the deployment process further, I recommend you check out the HTTP API for Ionic Deploy. This allows you to programmatically deploy changes to your app from your Continuous Integration server. It allows you to update the version numbers and metadata on your deployments as well. All of this can be done automatically and without ever touching the Ionic app dashboard.
Conclusion
That's it! In this tutorial you've learned about Ionic Deploy and how you can use it to push updates to your Ionic app. This is a powerful feature which allows you to build a robust versioning and update system into your app.
Stay tuned for more content on Ionic and on cloud services like Ionic Deploy! If you want a complete introduction to getting started with Ionic 2 app development, check out our course here on Envato Tuts+.
And check out some of our other posts on Ionic and cross-platform mobile app development.
- Ionic 2Code Your First Ionic 2 App: A Photo Sharing App
- Mobile DevelopmentIntroducing Vue and Weex for Native Mobile Apps
- App Templates15 Best Ionic App Templates