This article is written by Luo Zhu, a member of the team. We have authorized the exclusive use of Doodle Big Front-end, including but not limited to editing and original annotation rights.

Existing hot update solutions include Tencent’s Bugly app upgrade, React Native Chinese’s Pushy, Microsoft’s CodePush and code-push-Server for building private servers.

This article shares the hot update of CodePush service based on Microsoft AppCenter, which is more representative and convenient for readers to practice. Of course, in view of the domestic network environment, an article on how to implement the hot update function based on code-push-server will be published later.

The environment

  • Xcode: Version 11.3.1 (11C504)
  • The react – native: 0.61.5
  • The react – native – code – push: 6.1.0
  • Appcenter – cli: 2.3.3

CodePush introduction

CodePush is an App Center cloud service that enables Apache Cordova and React Native developers to deploy mobile application updates directly to their users’ devices. It acts as a central repository to which developers can publish certain updates (such as JS, HTML, CSS, and image changes) and from which applications can query (using the provided client SDK) for updates. This allows you to build a more deterministic and direct engagement model with end users, while fixing bugs and/or adding small features that don’t require you to rebuild binaries and/or redistribute binaries through any public app store. By default, all React Native apps created on App Center have CodePush enabled.

Note: For Android devices, CodePush only runs on TLS 1.2-compatible devices

1. Install the App Center CLI

You can manage most of CodePush’s features using the App Center CLI. To install the CLI, open a terminal window or command prompt and run the following command:

npm install -g appcenter-cli
Copy the code

After successfully installing the App Center CLI, run the AppCenter login command to configure the CLI for your App Center account details:

2. Application management

Before deploying the update, you must use the following command to create the App using the App Center:

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

If your app is for both Android and iOS, we strongly recommend that you create a separate app using CodePush. One for each platform. This way, you can manage and publish updates separately, which makes things easier in the long run. Most people just put the suffix -Android and -ios in the app name. Such as:

appcenter apps create -d MyApp-Android -o Android -p React-Native
appcenter apps create -d MyApp-iOS -o iOS -p React-Native
Copy the code

Note: Using the same application on Android and iOS may cause installation exceptions because the CodePush update package generated for iOS will have different content than the update generated for Android.

You can view all the apps in the AppCenter Apps List.

An important new feature in the App Center CLI is the ability to set an application currently using AppCenter Apps set-current

/

. By setting one application to the current application, you do not need -a to use this flag in other CLI commands. For example, AppCenter codepush Deployment List -a

/

can shorten the appCenter codepush Deployment List to set up the current application. You can use it to check which apps are set to your account’s current app AppCenter Apps get-current. Setting up the current application shortens the typing time of most CLI commands.



With code-push-CLI, the application is automatically deployed twice (Staging and Production). In App Center, you must create them yourself using the following commands:

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

After creating a deployment, you can use the deployment key appCenter codePush Deployment List –displayKeys to access both deployments, You can start configuring mobile clients through their respective SDKS (details for Cordova and React Native).

3. Modify versionNam

In android/app/build a android in the gradle. DefaultConfig. VersionName attribute (in ios / * * / Info. The plist is < key > CFBundleShortVersionString < / key > properties); We need to change the app version to 1.0.0 (default 1.0, but CodePush requires three digits)

3. Release application updates

After changing the application code or assets, follow the instructions below to use the App Center CLI to publish the updates to the App Center.

Run the App Center CLI release-react command to bind the application code and asset files, and publish them to the App Center server as a new version. Such as:

Appcenter codePush release-react-a <ownerName>/<appName> -d Staging -t 1.0.0 -m --development false --description <description>Copy the code
  • [-a|--app <ownerName>/<appName>]: Specify the application.
  • [-d|--deployment-name <deploymentName>]: This parameter specifies the deployment to which the update will be published. It defaults toStagingBut when you are ready to deploy toProductionOr one of your own custom deployments, simply set this parameter explicitly.
  • [-t|--target-binary-version <targetBinaryVersion>]: Specifies the native version of the application to be updated
  • [-m|--mandatory]: Mandatory update, defaultfalse
  • [--development]: This parameter specifies whether to generate unminiaturized development JS packages. If it is not specified, the default value isfalseDisable warnings and shrink the location of the package.
  • [--description <description>]: This parameter provides optional change log for deployment. This value is passed back and forth to the client so that when an update is detected, your application can choose to display it to the end user (for example, through the New Feature dialog box). The string accepts things like\nAnd control characters,\tSo you can include Spaces in the description to improve readability.

The CodePush client supports differential updates, so even if you release JS bundles and assets with each update, end users will only actually download the files they need. The service takes care of this automatically, so you can focus on creating great applications while we worry about optimizing end-user downloads.

React Native Client SDK

The plugin provides client-side integration for the CodePush service, making it easy to add a dynamic update experience to your React Native app.

Note: The following configurations are based on React-Native 0.60.

How does it work?

React Native applications consist of JavaScript files and any associated images that are bundled together by the packager Metro and distributed as part of platform-specific binaries (.ipa or.apk files). When you ship the application, updating the JavaScript code (such as bug fixes, adding new features) or updating the image resources requires you to recompile and redistribute the entire binary, including all the time associated with the store.

By synchronizing your JavaScript and image resources with updates you publish to CodePush servers, the CodePush plug-in helps you get immediate product improvements in front of end users.

To ensure that your end users always have a working version of your application, the CodePush plug-in maintains a copy of previous updates, so it can automatically roll back if you accidentally push an update that contains a crash. That way, you can rest assured that newly discovered distributions won’t cause users to block.

Note: any product related to native code changes (for example, modify the AppDelegate. M/MainActivity. Java, add the vera.ttf or add native plug-in) cannot through CodePush distribution, must be updated through the corresponding store.

The React Native platform is supported

  • IOS (7 +)
  • Android (above 4.1)
  • Windows (UWP)

Install the react – native code — a push

yarn add react-native-code-push
Copy the code

As with all React Native plug-ins, the iOS and Android integration experience is different, so perform the following setup steps depending on your target platform. Note that if you are targeting both platforms, it is recommended to create separate CodePush applications for each platform.

This tutorial assumes that you have used the React-native init command to initialize the React Native project.

IOS Settings

Once you have the CodePush plug-in, you must integrate it into the React Native application’s Xcode project and configure it correctly.

  1. Run CD ios && pod install && CD.. To install all the required CocoaPods dependencies.

  2. Open the appdelegate. m file and add an import statement to the CodePush header:

    #import <CodePush/CodePush.h>
    Copy the code
  3. Find the following line of code that sets the source URL for the production bridge:

    return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
    Copy the code
  4. To replace it downstream:

    return [CodePush bundleURL];
    Copy the code

    This change configures your application to always load the latest version of the application JS bundle. On first startup, this will correspond to the files compiled with the application. However, after an update is pushed through CodePush, this returns the location of the most recently installed update.

    Often, you only want to use CodePush to resolve the JS package location in your distribution, so we recommend using the DEBUG preprocessor macro to dynamically switch between using a packer server and CodePush. This makes it easier to ensure that you get the correct behavior you need in production, while still being able to use Chrome development tools at debug time, reload in real time, and so on.

    Your sourceURLForBridge method should look like this:

    - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
    {
      #if DEBUG
        return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
      #else
        return [CodePush bundleURL];
      #endif
    }
    Copy the code
  5. Add the deployment key to info.plist:

    To let the CodePush runtime know which deployment to query for updates, open your app’s info.plist file and add a new entry called CodePushDeploymentKey, The value is the Staging Deployment Key of the application you want to configure.

    You can retrieve this value by appCenter codePush Deployment List -k (the -k flag is required because the Key is not displayed by default) and then copy the corresponding Deployment Key.

    To take advantage of the Staging and Production deployments created with your CodePush application, configure multiple deployment tests before actually moving your application’s use of CodePush into Production.

    If you need to use other deployments dynamically, you can also use dynamic deployment allocation to override the deployment key in your JS code

The Android Settings

To integrate CodePush into your Android project, follow these steps:

  1. In the Android /app/build.gradle file, add the file codepush.gradle to the following other build task definitions:

    . applyfrom: ".. /.. /node_modules/react-native-code-push/android/codepush.gradle".Copy the code
  2. Mainapplication.java updates the file to use CodePush with the following changes:

    .// 1. Import the plug-in's classes
    import com.microsoft.codepush.react.CodePush;
    public class MainApplication extends Application implements ReactApplication {
        private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {...// 2. Rewrite the getJSBundleFile method to let the CodePush runtime decide where to load the JS bundle each time the app starts
            @Override
            protected String getJSBundleFile(a) {
                returnCodePush.getJSBundleFile(); }}; }Copy the code
  3. Add the deployment key to strings.xml:

    To let the CodePush runtime know which deployment updates it should query for, open your application’s string.xml file and add a new string called CodePushDeploymentKey, whose value is the application’s Staging deployment. You can obtain this value from appCenter Deployment List

    /

    -k.

    Your strings.xml should look like this:

     <resources>
         <string name="app_name">AppName</string>
         <string moduleConfig="true" name="CodePushDeploymentKey">DeploymentKey</string>
     </resources>
    Copy the code

    To take advantage of the Staging and Production deployments created with the CodePush application, please refer to the multi-deployment test documentation below before actually moving your application’s use of CodePush into Production.

    If you need to use other deployments dynamically, you can also use dynamic deployment allocation to override the deployment key in your JS code

The use of plug-in

After downloading and linking the CodePush plug-in, and asking CodePush where to get the correct JS bundle for your application, the only thing left is to add the necessary code to your application to control the following policies:

  1. When (and how often) should updates be checked? (For example, the application starts, clicks a button on the Settings page or at regular intervals)
  2. When updates are available, how do you present them to end users?

The simplest way is the root component of the Codepush-ify application. To do this, you can choose one of two options:

  • Option 1: Wrap your root component with the codePush higher-order component:

    import codePush from 'react-native-code-push'
    const App = () = > {}
    App = codePush(App)
    Copy the code
  • Option 2: Use the ES7 decorator syntax:

    Babel 6.x does not yet support decorators. You may need to enable the decorator by installing and using babel-preth-react-native stage-0.

    Babel 7.x supports decorator syntax. You can use @babel/plugin-proposal-decorators to enable decorators.

    import codePush from "react-native-code-push"
    
    @codePush
    class MyApp extends Component {}Copy the code

By default, CodePush checks for updates every time the application is launched. If an update is available, it will be downloaded and installed silently the next time the application is restarted (explicitly displayed by the end user or the operating system), ensuring the least intrusive experience for the end user. If an update is available, it is installed immediately to ensure that end users get it as soon as possible.

If you want your application to find updates faster, you can also choose to synchronize with the CodePush server every time your application recovers from the background.

let codePushOptions = { checkFrequency: codePush.CheckFrequency.ON_APP_RESUME }
const App = () = > {}

export default codePush(codePushOptios)(App)
Copy the code

Alternatively, if you want fine-grained control over when a check occurs (such as button pressing or timer interval), you can call it at any time using codepush.sync (), CodePush can also be disabled with SyncOptions via CheckFrequency.MANUAL:

import React from 'react';
import {View, StyleSheet} from 'react-native';
import codePush from 'react-native-code-push';
import AwesomeButton from 'react-native-really-awesome-button';

const codePushOptions = { checkFrequency: codePush.CheckFrequency.MANUAL };

const App = () = > {
  const checkForUpdate = () = > {
    codePush.sync({
      updateDialog: true.installMode: codePush.InstallMode.IMMEDIATE,
    });
  };

  const clear = () = > {
    codePush.clearUpdates();
  };

  return (
    <View style={styles.container}>
      <AwesomeButton type="secondary" onPress={checkForUpdate}>Check the update</AwesomeButton>
      <AwesomeButton type="secondary" onPress={clear}>Remove the update</AwesomeButton>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1.justifyContent: 'center'.alignItems: 'center',}});// Note: This is optional and can be wrapped without codePush
export default codePush(codePushOptions)(App);
Copy the code

If you want to display an update confirmation popup (an active install). To configure when to install available updates (such as forcing an immediate reboot) or to customize the update experience in any other way, see the CodePush API Reference for information on how to adjust this default behavior.

App Store Rules

  • Apple’s Developer Agreement allows the use of hot updates in Apple apps. In order not to affect the user experience, silent updates must be used.

  • Google Play can’t use silent updates, so you have to pop up a box to tell the user that the App has been updated.

  • China’s Android market must adopt silent update (App will be rejected by “Please upload the latest version of binary application package” if the pop-up box prompts).

Multiple deployment testing

In the getting started document, we explained how to configure the CodePush plug-in with a specific deployment key. However, in order to test the hair version effectively, it is critical to take advantage of our recommended Staging and Production deployments when you first create your CodePush application (or any custom deployments you may have already created).

Our client-side rollback features help you unblock users after installing the version that crashed, and server-side rollback (such as AppCenter CodePush Rollback) allows you to prevent other users from installing the wrong version after discovering it. However, it would be better if you could prevent widespread release of bug updates in the first place.

With Staging and Production deployments, you can implement a workflow like the following (customize!) :

  1. Staginguseappcenter codepush release-reactThe CodePush command publishes CodePush updates to your deployment (available if you need more controlappcenter codepush release
  2. Build staging of the application/Beta, synchronizing updates from the server and verifying that it works as expected
  3. Use the following command to change the distribution under test fromStagingUpgrade to theProuction: appcenter codepush promote -a <ownerName>/<appName> -s Staging -d Production
  4. Build the applicationproduction/release, synchronize updates from the service and verify that it works as expected

If you want to take a more cautious approach, you can even choose to perform a phased roll-out in “# 3,” which allows you to mitigate additional potential risks associated with the update (for example, whether the tests in # 2 touched all possible devices), Make Production updates available to only a certain percentage of users (for example, code-push promote -a / -s Staging -d Production -r 20%). Then, after waiting a reasonable amount of time to see if there are crash reports or customer feedback, you can extend it to the entire audience by running appCenter CodePush Patch-a/production-R 100%.

The android system

The Android Gradle Plugin allows you to define custom configuration Settings for each “build type” (e.g. debug, release). This mechanism allows you to easily configure debug releases using CodePush deployment keys, and distributions can also be configured to produce deployment keys using CodePush.

As a reminder, you can retrieve these keys by running appCenter CodePush Deployment List -k from your terminal.

To set this up, perform the following steps:

  1. Open the application level build.gradle file for your project (e.g. android/app/build.gradle in the standard React Native project)

  2. Look for this Android {buildTypes {}} section and resValue for your DEBUG and Release build type definition entries, referencing your key Staging and Production deployment keys, respectively.

    android {
      ...
      buildTypes {
        debug {
          signingConfig signingConfigs.debug
          // Note: CodePush updates should not be tested in Debug mode as they are overriden by the RN packager. However, because CodePush checks for updates in all modes, we must supply a key.
          resValue "string"."CodePushDeploymentKey".'" "'
        }
        release {
          // Caution! In production, you need to generate your own keystore file.
          // see https://facebook.github.io/react-native/docs/signed-apk-android.
          signingConfig signingConfigs.release
          minifyEnabled enableProguardInReleaseBuilds
          proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
          resValue "string"."CodePushDeploymentKey".'" "'
        }
        releaseStaging.initWith(release)
        releaseStaging {
            resValue "string"."CodePushDeploymentKey".'" "'
            // Note: It is a good idea to provide matchingFallbacks for the new buildType you create to prevent build issues
            // Add the following line if not already there
            matchingFallbacks = ['release']}}... }Copy the code

If you configure the deployment key during the build, remember to remove the key from strings.xml.

ReleaseStaging this cannot be changed due to the naming convention of this row.

iOS

This section applies to Xcode 11

Xcode allows you to customize build Settings for each configuration (e.g. Debug, Release), which can then be referenced as key values in the info.plist file (e.g. CodePushDeploymentKey setting). This mechanism allows you to easily do build configurations to generate binaries that are configured to synchronize with different CodePush deployments.

To set this up, perform the following steps:

  1. Open your Xcode Project, then select your Project in the Project Navigator window

  2. Ensure that the PROJECT node is selected, not TARGETS

  3. Select the Info tag

  4. Click the inside button of + for Duplicate “Release” Configuration

  1. Name your new configuration Staging (or whatever you like)

  2. Select the Build Settings TAB

  3. Click on the toolbar+Button to create a file namedCONFIGURATION_BUILD_DIRUser-Defined Setting, the configuration is as shown in the figure:

    Note: Every time you create this Xcode, it crashes. You can only write the value first and then modify it in project.pbxproj.

  4. Click + on the toolbar and select Add User-defined Setting

  5. Name this new setting CodePushDeploymentKey, expand it, and then specify your Staging deployment key for the Staging configuration and your Production deployment key for the Release configuration.

    As a reminder, you can retrieve these keys by running appCenter codePush Deployment List -a

    /

    –displayKeys from the terminal.

  6. Open the project’s info.plist file and change the CodePushDeploymentKey entry to $(CODEPUSH_KEY)

That’s it. Now when you run or build your App, your Staging package will automatically synchronize your Staging deployment, and your Release package will automatically synchronize your Production deployment.

Note: If you encounter ld: Library not found for… Error message, look at this issuse

In addition, if you want to give them different names and/or ICONS, you can modify the Product Bundle Identifier, Product Name, and Asset Catalog App Icon Set Name

Dynamic deployment allocation

The previous section showed you how to leverage multiple CodePush deployments to effectively test your updates before they are released to users. However, because this workflow statically emashes deployment assignments into the actual binaries, temporary and production builds only synchronize updates to that deployment.

In many cases, this is sufficient, because you only want your team, customers, stakeholders, and so on to synchronize with your pre-production build, so they just need to know how to synchronize with that build.

However, if you want to be able to do A/B testing, or to provide some users with early access to your application, it can be useful to be able to dynamically place certain users (or audiences) in particular deployments at run time.

To implement this workflow, all you need to do is specify the deployment key that you want the current user to synchronize with when the codePush method is called. When specified, this key overrides the “default” key provided in the application’s info.plist (iOS) or MainActivity.java (Android) file. This allows you to generate temporary or production builds, as well as dynamically “redirect” as needed.

// Imagine that "userProfile" is a prop that this component received
// which includes the deployment key that the current user should use.
codePush.sync({ deploymentKey: userProfile.CODEPUSH_KEY });
Copy the code

With this change, you now just have to choose how the application configures the correct deployment key for the current user. In practice, there are usually two solutions:

  1. Open up the ability to change deployment to users. For example, your Settings page might have a toggle button to enable “beta” access. If you don’t care if pre-production updates are known, and some of your users may want to choose to use the latest (and possibly erroneous) updates on their own terms (a bit like the Chrome channel). However, this solution leaves the decision authority to your users, which does not help you execute transparentlyA / BThe test.
  2. Annotate the user’s server-side profile with additional metadata to indicate the deployment synchronized with it. By default, your application can only use binary embedded keys, but after users are authenticated, your server can choose to “redirect” them to other deployments so that you can gradually place certain users or groups in different deployments as needed. You can even choose to store the server response in local storage to make it the new default. How the key is stored with the user’s profile is entirely up to your authentication solution (for exampleAuth0.Firebase, the customDB + REST API), but it’s usually very simple.

Note: If desired, you can also implement a hybrid solution that allows end users to switch between deployments while also allowing your servers to override this decision. Thus, you have A “deploy solution” hierarchy that ensures that your application updates itself, that users get the latest experience by gaining access to the latest content, but that you also have the ability to A/B test users as needed.

Since we recommend A Staging deployment for pre-release testing of updates (as described in the previous section), it does not necessarily make sense to use it to perform A/B testing on users, instead you should allow early access (as described in option 1 above). Therefore, we recommend taking full advantage of custom application deployment so that you can segment users by their needs. For example, you can create long-term or even one-time deployments, publish variations of the application to them, and then drop certain users into them to see their engagement.

// #1) Create your new deployment to hold releases of a specific app variant
appcenter codepush deployment add -a <ownerName>/<appName> test-variant-one

// #2) Target any new releases at that custom deployment
appcenter codepush release-react -a <ownerName>/<appName> -d test-variant-one
Copy the code

Note: The number of users who “switch” from one deployment to another is included in the total number of users reported in the “Install Metrics” within the deployment. For example, if your Production deployment currently reports a total of 1 users, but you dynamically switch that user to a Staging deployment, the Production deployment will report 0 total users, and the Staging deployment will report 1 (the user that just switched). Even in the case of a run-time based deployment redirection solution, this behavior allows you to accurately track your version usage.

Best practices

Source: github.com/youngjuning…

App.js

import React, {useEffect} from 'react';
import {View, StyleSheet} from 'react-native';
import codePush from 'react-native-code-push';
import AwesomeButton from 'react-native-really-awesome-button';
import {codePushSync, checkForUpdate} from './CodePushUtils';
const App = () = > {
  const getUpdateMetadata = async() = > {const running = await codePush.getUpdateMetadata(
      codePush.UpdateState.RUNNING,
    );
    const pending = await codePush.getUpdateMetadata(
      codePush.UpdateState.PENDING,
    );
    console.log('[CodePush] running', running);
    console.log('[CodePush] pending', pending);
  };

  useEffect(() = >{ codePushSync(); } []);return (
    <View style={styles.container}>
      <AwesomeButton onPress={checkForUpdate} style={{marginBottom: 10}} >
        Check For Update!
      </AwesomeButton>
			<AwesomeButton onPress={()= > codePush.clearUpdates()} style={{marginBottom: 10}}>
        Clear Updates!
      </AwesomeButton>
      <AwesomeButton onPress={getUpdateMetadata}>
        getUpdateMetadata!
      </AwesomeButton>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1.justifyContent: 'center'.alignItems: 'center',}});export default App;
Copy the code

CodePushUtils.js

import {AppState, Platform, Alert} from 'react-native';
import codePush from 'react-native-code-push';
import configReader from 'react-native-config-reader';

const CodePushDeploymentKey = {
  ios: {
    debug: ' '.staging: '944zuIiRSds-ZZY6AQF82aRl0b1vUL_mMxiie'.release: 'yyJfk2vtpLUUlOCg3FnvCcky9o4U1lEWR1UJV',},android: {
    debug: ' '.releasestaging: 'tOncLvKACzzSkUaML9tCOUfPZxHVnobfaNIUe'.release: 'Gtc4iXTPn24yu6CBrbl_V2GTy21xtdQyfm6x1',}};const getDeploymentKey = () = > {
  const buildType = configReader.BUILD_TYPE.toLowerCase();
  const deploymentKey = CodePushDeploymentKey[Platform.OS][buildType];
  console.log('[CodePushUtils]', deploymentKey);
  return deploymentKey;
};

const codePushStatusDidChange = async syncStatus => {
  switch (syncStatus) {
    case codePush.SyncStatus.CHECKING_FOR_UPDATE:
      // 0 - Querying the CodePush server for updates.
      console.info('[CodePush] Checking for update.');
      break;
    case codePush.SyncStatus.AWAITING_USER_ACTION:
      // 1 - Updates are available and a confirmation dialog is displayed to the end user. (only available when updateDialog is used)
      console.info('[CodePush] Awaiting user action.');
      break;
    case codePush.SyncStatus.DOWNLOADING_PACKAGE:
      // 2 - Downloading available updates from the CodePush server.
      console.info('[CodePush] Downloading package.');
      break;
    case codePush.SyncStatus.INSTALLING_UPDATE:
      // 3 - One available update has been downloaded and installed.
      console.info('[CodePush] Installing update.');
      break;
    case codePush.SyncStatus.UP_TO_DATE:
      // 4 - The application is configured for deployment to be fully up to date.
      console.info('[CodePush] App is up to date.');
      break;
    case codePush.SyncStatus.UPDATE_IGNORED:
      // 5 The application has an optional update that the end user chooses to ignore. (only available when updateDialog is used)
      console.info('[CodePush] User cancelled the update.');
      break;
    case codePush.SyncStatus.UPDATE_INSTALLED:
      / / 6 - installed an available update, it will be subject to SyncOptions InstallMode specified in the application in syncStatusChangedCallback function returns immediately after or at the next recovery/reboot immediately run.
      console.info('[CodePush] Installed update.');
      break;
    case codePush.SyncStatus.SYNC_IN_PROGRESS:
      // 7 - The sync operation being performed
      console.info('[CodePush] Sync already in progress.');
      break;
    case codePush.SyncStatus.UNKNOWN_ERROR:
      // -1 - Synchronization encountered an unknown error.
      console.info('[CodePush] An unknown error occurred.');
      break; }};const codePushDownloadDidProgress = progress= > {
  const curPercent = (
    (progress.receivedBytes / progress.totalBytes) *
    100
  ).toFixed(0);
  console.log('[CodePushUtils] Downloading Progress'.`${curPercent}% `);
  // console.log(`${progress.receivedBytes} of ${progress.totalBytes} received.`);
};

const syncImmediate = async() = > {const deploymentKey = getDeploymentKey();
  codePush.sync(
    {
      updateDialog: {
        // Whether to display the update description
        appendReleaseDescription: true.// Update the description prefix. The default is "Description"
        descriptionPrefix: '\n\n Update: \n'.// Forces the button text to be updated. The default is continue
        mandatoryContinueButtonLabel: 'Update now'.// Mandatory update information. The default is "An update is available that must be installed."
        mandatoryUpdateMessage: 'Must be updated before use'.// The text of the button is "ignore" by default.
        optionalIgnoreButtonLabel: 'later'.// Confirm button text when not forced to update. The default is "Install"
        optionalInstallButtonLabel: 'Background Update'.// The updated message text is checked when the update is not mandatory
        optionalUpdateMessage: 'There is a new version, is it up to date? '.// Title of the Alert window
        title: 'update',
      },
      deploymentKey,
      installMode: codePush.InstallMode.IMMEDIATE,
    },
    codePushStatusDidChange,
    codePushDownloadDidProgress,
  );
};

export const checkForUpdate = async() = > {const deploymentKey = getDeploymentKey();
  const update = await codePush.checkForUpdate(deploymentKey);
  if(! update) { Alert.alert('tip'.'Current version');
  } else{ syncImmediate(); }};export const codePushSync = () = > {
  AppState.addEventListener('change'.newState= > {
    newState === 'active' && syncImmediate();
  });
};
Copy the code

Npm Scripts

{
  "scripts": {..."gradle:clean": "cd android && ./gradlew clean"."an:release": "yarn gradle:clean && cd android && ./gradlew app:assembleRelease"."an:installRelease": "yarn gradle:clean && cd android && ./gradlew app:installRelease"."an:staging": "yarn gradle:clean && cd android && ./gradlew app:assembleReleaseStaging"."an:installStaging": "yarn gradle:clean && cd android && ./gradlew app:installReleaseStaging"."displayKeys": "yarn disPlayIosKeys && yarn disPlayAndroidKeys"."disPlayIosKeys": "appcenter codepush deployment list --app youngjuning/AppCenterCodePushDemo-iOS --displayKeys"."disPlayAndroidKeys": "appcenter codepush deployment list --app youngjuning/AppCenterCodePushDemo-Android --displayKeys"."release-react": "yarn release-react-ios && yarn release-react-android"."release-react-ios": "appcenter codepush release-react --app youngjuning/AppCenterCodePushDemo-iOS"."release-react-android": "appcenter codepush release-react --app youngjuning/AppCenterCodePushDemo-Android". }},Copy the code

extension

When does CodePush not restart an app immediately

  1. Since the lastdisallowRestartCalled with no new updates.
  2. There are updates, butinstallModeforInstallMode.ON_NEXT_RESTARTIn the case of.
  3. There are updates, butinstallModeforInstallMode.ON_NEXT_RESUME, and the program has been in the foreground, and did not switch from the background to the foreground.
  4. Since the lastdisallowRestartCalled, not called againrestartApp.

TypeSctipt

With TypeScript, after reviewing the API section of the document, you can rely on the type system’s prompt: react-native code-push.d.ts

IOS add BUILD_TYPE

Add BUILD_TYPE to info.plist with value $(CONFIGURATION)

react-native bundle

Generate bundle name: React-native bundle –platform platform –entry-file Startup file –bundle-output JS output file –assets-dest resource output directory –dev

$ react-native bundle --platform android --entry-file index.js --bundle-output ./bundle/android/main.jsbundle --assets-dest ./bundle/android --dev false
Copy the code