Skip to content

Latest commit

 

History

History
469 lines (283 loc) · 16.8 KB

File metadata and controls

469 lines (283 loc) · 16.8 KB

Introduction

CodePush is an App Center Colud service provided by Microsoft that enables React Native / Cordova developers to deploy mobile app updates directly to their user's device without going throuch the google play store / Apple app store and review process. App Center provides other services as well such as

  • building
  • testing,
  • distributing and
  • monitoring app in cloud.

How CodePush works

Generally react native app in production consist of JSBundle file (i.e is the javascript files with images and other assets) which are bundle together by packager and distributed as part of a platform-specific binary (an .ipa or .apk file). When the app is released, updating either the JavaScript code (for example making bug fixes, adding new features) or image assets, requires you to recompile and redistribute the entire binary, which includes any review time associated with the stores to which you are publishing.

The CodePush plugin helps get product improvements in front of your end users instantly, by keeping your JavaScript and images synchronized with updates you release to the CodePush server. This way, your app gets the benefits of an offline mobile experience, as well as the "web-like" agility of side-loading updates as soon as they are available.

In order to ensure that your end users always have a functioning version of your app, the CodePush plugin maintains a copy of the previous update, so that in the event that you accidentally push an update that includes a crash, it can automatically roll back. This way, you can rest assured that your newfound release agility won't result in users becoming blocked before you have a chance to roll back on the server.

Get Started

1. Setup React Native Project

1.1. Create react native project

Open a terminal and execute following command to create react native project

    npx react-native init  CodePushDemo

1.2. Create git repository

  • Go to https://github.com and create new repository with name CodePushDemo

  • After that, go to root directory of just created CodePushDemo Pfoject and execute following command

      git init
      git add .
      git commit -m "first commit"
      git remote add origin https://github.com/{username}/CodePushDemo.git
      git push origin master
    

2. Setup App Center

2.1. Create account in App Center

2.2 Install the App Center CLI

  • You manage most of CodePush's functionality using the App Center CLI. Open a terminal and execute the following command

      npm install -g appcenter-cli
    

2.3. Login to App Center

Before you can begin releasing app updates, you must sign-in with your existing CodePush account or create a new App Center account. You can do this by running the following command once you've installed the CLI:

    appcenter login

This command will launch a browser, asking you to authenticate with either your GitHub or Microsoft account. Once authenticated, it will create a CodePush account "linked" to your GitHub/MSA identity, and generate an access key you can copy/paste into the CLI in order to sign-in.

2.4. Access Tokens

To authenticate against the CodePush service without launching a browser and/or without needing to use your GitHub and/or Microsoft credentials (for example, in a CI environment), you can execute the following command to create an "access token"

    appcenter tokens create -d "Azure DevOps Integration"

    appcenter login --token <accessToken>

Additional commands

    appcenter profile list  // View User profile

    appcenter logout        // logout from app center

    appcenter tokens list   //View running user session from all the machine

    appcenter tokens delete <tokenid>  // delete the user session

2.5. App Management

Create App doc

Before deploying updates, you must create an app with App Center for each platform (iOS and Android)

    appcenter apps create -d <appDisplayName> -o <operatingSystem>  -p <platform> 

    appcenter apps create -d AppUpdateDemoIOS  -o iOS  -p React-Native

    appcenter apps create -d AppUpdateDemoAndroid  -o Android  -p React-Native

If you decide that you don't like the name you gave to an app, you can rename it at any time using the following command:

    appcenter apps update -n <newName> -a <ownerName>/<appName>

If at some point you no longer need an app, you can remove it from the server using the following command:

    appcenter apps delete -a <ownerName>/<appName>

After you create the deployments, you can access the deployment keys for both deployments using

    appcenter apps list        

Create deployment key docs

We can create deployment keys for production and staging from below command

    appcenter codepush deployment add -a <ownerName>/<appName> Staging
   
    appcenter codepush deployment add -a <ownerName>/<appName> Production

We can get the / pair by running following command

    appcenter apps list

    // returns rajan.twanabashu-zakipoint.com/AudoUpdatePush

To get the list of deployment keys

    appcenter codepush deployment list  -a <ownerName>/<appName>  --displayKeys

To just this to view deployment metrics

    appcenter codepush deployment list  -a <ownerName>/<appName>

To list version history

    appcenter codepush deployment history -a  <appowner/appname> <deployment Name>

To rename or delete deployment keys

    appcenter codepush deployment remove -a <ownerName>/<appName> <deploymentName>
    appcenter codepush deployment rename -a <ownerName>/<appName> <deploymentName> <newDeploymentName>    

Dsipatch release via code push

Once your app has been configured to query for updates against the App Center server, you can begin releasing updates to it.

    appcenter codepush release-react -a <ownerName>/<appName> -d <deploymentName>
    
    //e.g.
    appcenter codepush release-react -a rajan.twanabashu-zakipoint.com/AudoUpdatePush  -d Production

Rollback release update

A deployment's release history is immutable, so you cannot delete or remove an update once it has been released. However, if you release an update that is broken or contains unintended features, it is easy to roll it back using the rollback command:

    appcenter codepush rollback <ownerName>/<appName> <deploymentName>

    //e.g.
    appcenter codepush rollback  -a rajan.twanabashu-zakipoint.com/AudoUpdatePush  Production

Promote stagging update to production

    appcenter codepush promote -a <ownerName>/MyApp-iOS -s Staging -d Production -t "*"

3. Integrating Code Push : docs

Once we have configured the App Center, its time to integrate code-push into the react native application. Execute below command in terminal

    npm install --save react-native-code-push

3.1. iOS Setup

Once you have the CodePush plugin, you must integrate it into the Xcode project of your React Native app and configure it correctly. Code push is not compactible with autolink in react native at this moment. So execute following command to link

react-native link react-native-code-push

or update the Podfile to include

pod 'CodePush', :path => '../node_modules/react-native-code-push'

Finally from root directory install pod dependencues

npx pod-install

//or 
cd ios
pod install

Integrate in Xcode project

Open up the AppDelegate.m file, and add an import statement for the CodePush headers:

    #import <CodePush/CodePush.h>

Find the following line of code, which sets the source URL for bridge for production releases:

    return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

and replace with

return [CodePush bundleURL];

your code should now look like this

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
  #if DEBUG
    return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
  #else
    return [CodePush bundleURL];
  #endif
}

Using Deployment Key

To let the CodePush runtime know which deployment it should query for updates against, open the project's Info.plist file and add a new entry named CodePushDeploymentKey, whose value is the key of the deployment you want to configure this app against

    <key>CodePushDeploymentKey</key>
	<string>R7Ms5WZiHbQ4fl4XB4_8HsAhPcm9ky53Ck1Am</string>

CodePush plugin makes HTTPS requests to the following domains:

    - codepush.appcenter.ms
    - codepush.blob.core.windows.net
    - codepushupdates.azureedge.net

If you want to change the default HTTP security configuration for any of these domains, you have to define the NSAppTransportSecurity (ATS) configuration inside the project's Info.plist file:

<plist version="1.0">
  <dict>
    <!-- ...other configs... -->

    <key>NSAppTransportSecurity</key>
    <dict>
      <key>NSExceptionDomains</key>
      <dict>
        <key>codepush.appcenter.ms</key>
        <dict><!-- read the ATS Apple Docs for available options --></dict>
      </dict>
    </dict>

    <!-- ...other configs... -->
  </dict>
</plist>

3.2 Managing multiple deployment target

In order to effectively test your releases, it is critical that you leverage the Staging and Production enviroment and deploy the repease accordingly.

If you use appcenter dashboard, creating codepush deployment creates both production and staging keys. If you are using appcenter cli then we first need to create keys for production and staging

For production:

appcenter codepush deployment add -a <ownerName>/<appName> Production

For Staging

appcenter codepush deployment add -a <ownerName>/<appName> Staging

After that it time to create Production and Staging target in Xcode. Follow below steps for this.

  • Open Xcode workspace
  • Select project navigator and click on xcode project
  • By default you will see one target (AppName) created initially along with other test target.
  • Duplicate the default target (AppName) and rename the target to AppName-UAT.
  • This process will create seperate plist file , rename this to AppName-uat.plist
  • Go to build settings and change the Packaging->Info.plist file to AppName-uat.plist
  • Now you have two plist file each for production and staging build, we can now configure the codepush deployment for each target
    • In AppName.plst add CodePushDeploymentKey = Production key in codepush and DeploymentType = Production
    • In AppName-UAT.plist add CodePushDeploymentKey = Staging key in codepush and DeploymentType = Staging
  • We will also get two scheme one for each target. This will help us choose production or staging build during debug and release activity.

Sending Deployment Key and Type info to React Native from iOS

Now its time to send the deployment key and deployment type to react native part from iOS end. Open AppDelegate.m and add the following code to send key information as initialProps to react native code. Based on selected scheme we will get respective key and type.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

NSString *deploymentKey = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CodePushDeploymentKey"];
NSString *deploymentType = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"DeploymentType"];
 
NSDictionary *props;

props = @{@"CodePushDeploymentKey" : deploymentKey, @"DeploymentType":deploymentType};


NSLog(@"%@", props);

RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                 moduleName:@"zConnect"
                                          initialProperties:props];

rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}

Requesting the bundle update from React Native.

Open App.js and following code. here deploymentKey will determine which bundle to download from appcenter to get updates.

useEffect(() => {
        CodePush.sync({deploymentKey:props.CodePushDeploymentKey,  installMode: CodePush.InstallMode.ON_NEXT_RESUME, minimumBackgroundDuration: 10 }, codepushSyncStatus, null); //10 sec  
      }, [])

4. Installing the new update docs

CodePush provides Cordova and React Native developers with multiple options to configure the end users update experience. There are three potential "update modes" or deployment strategies for CodePush updates: Silent, Active, and Custom.

4.1 Silence Mode

First of all in App.js we need to wrap out app inside CodePush higher order functions to configure the update check frequency.

const codePushOption = {
  checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME,
};

............

export default CodePush(codePushOption)(App);

App will check for new update from appcenter server on every resume

To sync and install the available update we will need to add following code which will install the update after 10 seconds of app inactivity in background

 CodePush.sync({ installMode: CodePush.InstallMode.ON_NEXT_RESUME, minimumBackgroundDuration: 10}, codepushSyncStatus, null); //10 sec

Here CodePush.sync accept following parameter

  • installMode: apply update when the app is resume next time
  • minimumBackgroundDuration : after this time of app in background new updates are applied
  • codepushSyncStatus: call back function that will show the sync statys
  • null : downloadProgress indicator. which we are not using at this moment. So ignore.

Full source code will look like this

import CodePush from 'react-native-code-push'

const codePushOption = {
  checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME,
};

const App: () => React$Node = () => {

  useEffect(() => {
    //app resumes after 10 minutes
    CodePush.sync({ installMode: CodePush.InstallMode.ON_NEXT_RESUME, minimumBackgroundDuration: 10}, codepushSyncStatus, null); //10 sec
    
  }, [])

  const codepushSyncStatus = (status) => {
    console.log("code push sync status", status)
  }
  
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <View style={{flex: 1,justifyContent: 'center',alignItems: 'center'}}>
        <Text> Rajan Twanabashu</Text>
      </View>
    </>
  );
};

export default CodePush(codePushOption)(App);

Code cleanup

  • create codepushwrapper.js
import React,  {useEffect}from 'react';
import CodePush from 'react-native-code-push'

const codePushOption = {
  checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME,
};


const CodePushWrapper = (WrappedComponent) => {
    
    const WrappedApp = ()=>{
        useEffect(() => {
            //app resumes after 10 minutes
            CodePush.sync({ installMode: CodePush.InstallMode.ON_NEXT_RESUME, minimumBackgroundDuration: 10}, codepushSyncStatus, null); //10 sec
            
          }, [])
        
          const codepushSyncStatus = (status) => {
            console.log("code push sync status", status)
          }
          return <WrappedComponent />
    }
    
    return CodePush(codePushOption)(WrappedApp);
}

export default CodePushWrapper

then we can cleanup app.js as following

import CodePushWrapper from './codepush';
const App: () => React$Node = () => {
  
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <View style={{flex: 1,justifyContent: 'center',alignItems: 'center'}}>
        <Text> Rajan Twanabashu</Text>
      </View>
    </>
  );
};

export default CodePushWrapper(App);

5. Conclusion

Now after all the above configuration we can dispatch the new release to appcenter via following command. Then depending on the codepush option your update will be silently installed at client end.

    appcenter codepush release-react -a <ownerName>/<appName> -d <deploymentName>

Source Code:

  • Complete source code: code

Other useful links