Home | Send Feedback

Hot deploy updates to Ionic 4 / Cordova apps with CodePush

Published: January 16, 2017  •  Updated: December 07, 2017  •  ionic4, cordova

In previous posts I showed you example of updating Ionic / Cordova apps on the fly with Ionic Deploy and with the cordova-hot-code-push plugin.

In this post we are going to look at a similar offering from Microsoft: CodePush. CodePush is part of App Center. I'm not exactly sure how many updates are covered by the free plan. I couldn't find any information on the pricing page . Maybe somebody can clarify and send me a message.

App Center Setup

Before we start coding, open App Center and sign in. If you don't already have an account, create one first.

In App Center we have to create an app. Click on Add new app and enter a name and description. Select Cordova as platform and choose an OS. I use Android for this tutorial, CodePush also works for apps installed on iOS.

step 1 step 2

I think the recommendation from CodePush is to create two applications if you target iOS and Android.

Create the app with Add new app.

Open the menu Distribute and click on CodePush

step 3

on this screen click on Create standard deployments

step 4

This creates a Production and Staging deployment. You can rename, add and delete these deployments to adjust them to your specific deployment workflow.

You can close the App Center web console. From here on we can control everything with the App Center command line tool.

You can install these tools globally on your computer with

npm install -g appcenter-cli

I skip this step and install the CLI locally into my test project. If you manage a lot of projects with App Center, it makes sense to install the tools globally. I only use it for one test application so I rather prefer to install them locally.

Project Setup

The application is an Ionic 4 / Cordova application based on the blank starter application.

To bootstrap the application I run these commands

ionic start codepush blank
cd codepush
npm install -D appcenter-cli
npm install code-push
ionic cordova prepare android
ionic cordova plugin add cordova-plugin-code-push@latest

As mentioned before, I install the appcenter-cli locally into my project. I also add the code-push JavaScript library and the cordova-plugin-code-push Cordova plugin. These is the library that checks for new updates, downloads and installs them on the fly.

Next we need to login to App Center from the shell.

npx appcenter login

This command opens a browser and displays a token, copy this token and paste it into the shell.

Open config.xml and check if your file contains the following configuration. If it does you don't have to change anything.

<access origin="*" />`

But if you restricted internet access in your app to certain servers you have to add the following three addresses, so your app is allowed to communicate with the CodePush servers

<access origin="https://codepush.azurewebsites.net" />
<access origin="https://codepush.blob.core.windows.net" />
<access origin="https://codepushupdates.azureedge.net" />

Open src/index.html and add the following meta tag to the head section. This allows access to the CodePush server on CSP-compliant platforms.

<meta http-equiv="Content-Security-Policy" content="default-src https://codepush.azurewebsites.net 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *" />

Sync Code

In this section we add code to our application that initiates the sync functionality. But before we dive into the code we need to figure out the deployment key.

You find them in the App Center web console or get them from the command line. To get the key for my test application I run this command.

npx appcenter codepush deployment list -a ralphschaer/TestApp --displayKeys
┌────────────┬───────────────────────────────────────┐
│ Name       │ Key                                   │
├────────────┼───────────────────────────────────────┤
│ Staging    │ Z_F0kSey7z0lrIWRr7rjobgU0qwnSJ8SY5DJV │
├────────────┼───────────────────────────────────────┤
│ Production │ x8cua6U1-BCYr2BUjlfqoSZ6Hl0fBJISY9DkE │
└────────────┴───────────────────────────────────────┘

The CodePush Cordova plugin does not automatically check and install new updates, you have to add code that controls this from your application.

Open src/app/app.component.ts and add the following code to the initializeApp() method.

  initializeApp() {
    this.platform.ready().then(() => {

      const deploymentKey = 'Z_F0kSey7z0lrIWRr7rjobgU0qwnSJ8SY5DJV';
      codePush.sync(null, {deploymentKey});

      this.platform.resume.subscribe(() => codePush.sync(null, {deploymentKey}));

      this.statusBar.styleDefault();
      this.splashScreen.hide();
    });
  }

sync() connects to the CodePush server and looks for new updates. If an update is available, it downloads the changes and either installs and restarts the app immediately (mandatory update) or only downloads the update and install it the next time the user starts the app from fresh (non-mandatory update).
This is the default behaviour that you can customize with syncoptions (2nd parameter).

The first call to sync is issued when you start the app for the first time. When you resume the app from the background, the resume event is emitted and in this example we also call sync. There are many possibilities how to check for new updates. You could also add a check for update button that triggers the check.

For more information about the API visit the official documentation page:
https://docs.microsoft.com/en-us/appcenter/distribution/codepush/cordova

Instead of adding the deployment key into the code you can paste the keys into config.xml

<platform name="android">
    <preference name="CodePushDeploymentKey" value="YOUR-ANDROID-DEPLOYMENT-KEY" />
</platform>
<platform name="ios">
    <preference name="CodePushDeploymentKey" value="YOUR-IOS-DEPLOYMENT-KEY" />
</platform>

This is a more static way to configure the deployment key. Adding the keys to the code allows a more dynamic approach where users can change the deployment channel in the app.

Initial version

To test the on the fly update we add the following code to the homepage template and install the app on a device or in an emulator. We're going to increase the version number for the update and are then able to verify if the update was successfully installed.

  <ion-card>
    <ion-card-header>
      Version
    </ion-card-header>
    <ion-card-content>
      0.0.1
    </ion-card-content>
  </ion-card>

home.page.html

Build the app and install it

ionic cordova run android --prod

You should now see this on your device or emulator. step 5

Update

Now we create an update. To simulate a change we change the version number in the home page template.

    <ion-card-content>
      0.0.2
    </ion-card-content>

Now build the app and push the update to App Center

ionic cordova build android --prod
npx appcenter codepush release-cordova -m -a ralphschaer/TestApp -d Staging

The -m flag denotes a mandatory update. In our example this is going to force a restart of the app immediately after the CodePush plugin downloaded the update.

To trigger the update we need to close and open the app. When the app is in the foreground, press the home button and open the app again. After a few seconds, you should see the updated home page.

step 6

Advanced sync() calls

If you need more insight into the update process you can provide two callback function as first and third argument to the codePush.sync() function.

codePush.sync(syncCallback?, syncOptions?, downloadProgress?);

The first callback is called when the sync task changes (from checking to downloading, from downloading to installing). The downloadProgress callback is called periodically when the plugin downloads the update package.

codePush.sync(syncStatus, null, downloadProgress);

function syncStatus(status) {
    switch (status) {
        case SyncStatus.DOWNLOADING_PACKAGE:
            // do something here
            break;
        case SyncStatus.INSTALLING_UPDATE:
            // do something here
            break;
    }
}

function downloadProgress(downloadProgress) {
    if (downloadProgress) {
      console.log("Downloading " + downloadProgress.receivedBytes + " of " +    
                   downloadProgress.totalBytes);
    }
}

With the second argument you configure the sync() call. See the official documentation about the sync() method. In our example we used it for providing the deploymentKey.

Note that you should not set the updateDialog option to true if your app is running on iOS. This option tells sync() to show a dialog when a new update is available.

codePush.sync(null, { updateDialog: { title: "An update is available!" } });

While Apple allows on the fly updates for Cordova apps, it is against their policy for an app to display an update prompt. There is no such restriction on the Google Play store.

Advanced workflows

sync() is the most convenient way to use the CodePush API, but if you need more control over the update process you can call the methods that are involved in the update process individually. The API provides these following methods

Method Description
checkForUpdate Sends a request to the CodePush server and checks if an update is available
getCurrentPackage Retrieves the metadata about the currently installed package.
getPendingPackage Retrieves the metadata for an update (if one exists) that was downloaded and installed, but hasn't been applied yet via a restart.
notifyApplicationReady Notifies the CodePush runtime that an installed update is considered successful
restartApplication Immediately restarts the app and applies a pending update.

CodePush has many additional feature, we did not cover in this post. For example there is an option to release an update only to a specific percentage of users and it supports rollback of updates. See the CodePush documentation for a complete description:
https://docs.microsoft.com/en-us/appcenter/distribution/codepush/


You find the code for this example on GitHub.