React Native 6.1集成CodePush(安卓篇)

2,066 阅读5分钟

什么是codepush?

CodePush是一个微软开发的云服务器。通过它,开发者可以直接在用户的设备上部署手机应用更新。CodePush相当于一个中心仓库,开发者可以推送当前的更新(包括JS/HTML/CSS/IMAGE等)到CoduPush,然后应用将会查询是否有更新。

集成流程

  • 安装CodePush Cli

  • 注册CodePush帐号

  • 在CodePush服务器注册App

  • 在React Native中集成CodePush

  • 在React Native中运行CodePush

  • 如何发布CodePush更新包

一、安装CodePush Cli

CodePush指令只需要在终端上输入指令即可,而且只需要全局输入一次。

$ npm install -g code-push-cli

二、注册CodePush帐号

注册CodePush只需要运行下面的指令后跟着他的步骤走就可以了,也是只需要注册一次即可。

$ code-push register

注意:运行完当前指令后会打开一个授权网页,让你选择当前注册的方式。这里我选择的是Github。

注册完之后你会拿到一个CodePush的一个Key值

然后将它复制粘贴到终端

成功后会出现Successfully的提示

如果你想验证一下是否注册成功,可以通过$ code-push login进行验证

CodePush注册登录的相关命令有:

  • code-push register 注册
  • code-push login 登录
  • code-push logout 登出

三、在CodePush服务器注册App

为了让CodePush服务器有我们的App,我们需要在CodePush中注册App,输入下面命令即可完成注册。这里需要注意的是注册分为IOS和Android两个平台,这里只讲解Android的,下一篇写IOS的。
应用添加成功后就会返回对应的Production 和 Staging 两个key,Production代表生产版的热更新部署,Staging代表开发版的热更新部署

添加android平台

$ code-push app add 你的App名 Android react-native

我们可以输入如下命令来查看我们刚刚添加的App

$ code-push app list

CodePush管理App的相关命令有:

  • code-push app add 在账号里面添加一个新的app
  • code-push app remove 或者 rm 在账号里移除一个app
  • code-push app rename 重命名一个存在app
  • code-push app list 或则 ls 列出账号下面的所有app
  • code-push app transfer 把app的所有权转移到另外一个账号

四、在React Native中集成CodePush

首页需要在项目中安装组件,然后再android文件夹中进行一些配置

  1. 安装组件
$ npm install react-native-code-push --save

注意:由于RN6.0以后会自动进行依赖,所以我们不需要再去link

  1. android/app/build.gradle文件中添加codepush.gradle
...
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
...
  1. 更新MainApplication.java文件(android/app/src/main/java/com/youApp/MainApplication.java)
...
// 1. 导入CodePush
import com.microsoft.codepush.react.CodePush;

public class MainApplication extends Application implements ReactApplication {

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        ...

        // 2. 覆盖getJSBundleFile方法
        // the CodePush runtime determine where to get the JS
        // bundle location from on each app start
        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
        }
    };
}
  1. 将部署密钥添加到strings.xml(android/app/src/main/res/values/strings.xml)
<resources>
    <string name="app_name">youApp</string>
    <string moduleConfig="true" name="CodePushDeploymentKey">你的staging值</string>
</resources>

你可以通过code-push deployment ls <appName> -k来检索你的App中Production值和Staging值。

  1. build.gradle(android/app/build.gradle)中加上production和staging的CODEPUSH_KEY
buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        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.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            buildConfigField "String", "CODEPUSH_KEY", '"你的Production CodePushKey"'
        }
        releaseStaging {
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            buildConfigField "String", "CODEPUSH_KEY", '"你的Staging CodePushKey"'
        }
    }

注意:在这步的时候,网上的文章都需要在MainApplication.java文件中加上下面的代码

@Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
          // packages.add(new MyReactNativePackage());
          packages.add(new CodePush(getResources().getString(R.string.reactNativeCodePush_androidDeploymentKey), getApplicationContext(), BuildConfig.DEBUG));
          // packages.add(new CodePush(BuildConfig.CODEPUSH_KEY, getApplicationContext(), BuildConfig.DEBUG, getResources().getString(R.string.reactNativeCodePush_androidDeploymentKey)));
          return packages;
        }

上面的两种方式我都试了,但是都报了下面错误,后面我将它注释掉了以后就不报错了,我也不知道为啥。

五、在React Native中运行CodePush

在使用之前需要考虑的是检查更新时机,更新是否强制,更新是否要求即时等

更新时机

一般常见的应用内更新时机分为两种,一种是打开App就检查更新,一种是放在设置界面让用户主动检查更新并安装

  • 打开App就更新

此时只需要将更新的代码放在componentDidMount中即可

import React from 'react'
import Router from './app/routes/routes'

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

const codePushOptions = {
  // 设置检查更新的频率
  // ON_APP_RESUME APP 恢复到前台的时候
  // ON_APP_START APP 开启的时候
  // MANUAL 手动检查
  checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME,
  updateDialog: true,
  installMode: CodePush.InstallMode.IMMEDIATE
}

class App extends React.Component {
  render () {
    return (
      <Router />
    )
  }

  update = () => {
    CodePush.sync({
      // 安装模式
      // ON_NEXT_RESUME 下次恢复到前台时
      // ON_NEXT_RESTART 下一次重启时
      // IMMEDIATE 马上更新
      installMode: CodePush.InstallMode.IMMEDIATE,
      // 对话框
      updateDialog: {
        // 是否显示更新描述
        appendReleaseDescription: true,
        // 更新描述的前缀。 默认为"Description"
        descriptionPrefix: '更新内容:',
        // 强制更新按钮文字,默认为continue
        mandatoryContinueButtonLabel: '立即更新',
        // 强制更新时的信息. 默认为"An update is available that must be installed."
        mandatoryUpdateMessage: '必须更新后才能使用',
        // 非强制更新时,按钮文字,默认为"ignore"
        optionalIgnoreButtonLabel: '稍后',
        // 非强制更新时,确认按钮文字. 默认为"Install"
        optionalInstallButtonLabel: '后台更新',
        // 非强制更新时,检查到更新的消息文本
        optionalUpdateMessage: '有新版本了,是否更新?',
        // Alert窗口的标题
        title: '更新提示'
      }
    })
  }

  async componentWillMount () {
    CodePush.disallowRestart() // 禁止重启
    this.update() // 开始检查更新
  }

  componentDidMount () {
    CodePush.allowRestart() // 在加载完了,允许重启
  }
}

App = CodePush(codePushOptions)(App)

export default App

  • 用户点击检查更新按钮

在用户点击检查更新按钮后进行检查,如果有更新则弹出提示框让用户选择是否更新,如果用户点击立即更新按钮,则会进行安装包的下载(实际上这时候应该显示下载进度,这里省略了)下载完成后会立即重启并生效(也可配置稍后重启),部分代码如下:

  update = () => {
    const deploymentKey = '你的CodePush Key'
    CodePush.checkForUpdate(deploymentKey).then(update => {
      if (!update) {
        Alert.alert('提示', '已是最新版本', [
          {
            text: 'Ok',
            onPress: () => {
              console.log('点了OK')
            }
          }
        ])
      } else {
        CodePush.sync({
          // 安装模式
          // ON_NEXT_RESUME 下次恢复到前台时
          // ON_NEXT_RESTART 下一次重启时
          // IMMEDIATE 马上更新
          installMode: CodePush.InstallMode.IMMEDIATE,
          // 对话框
          updateDialog: {
            // 是否显示更新描述
            appendReleaseDescription: true,
            // 更新描述的前缀。 默认为"Description"
            descriptionPrefix: '更新内容:',
            // 强制更新按钮文字,默认为continue
            mandatoryContinueButtonLabel: '立即更新',
            // 强制更新时的信息. 默认为"An update is available that must be installed."
            mandatoryUpdateMessage: '必须更新后才能使用',
            // 非强制更新时,按钮文字,默认为"ignore"
            optionalIgnoreButtonLabel: '稍后',
            // 非强制更新时,确认按钮文字. 默认为"Install"
            optionalInstallButtonLabel: '后台更新',
            // 非强制更新时,检查到更新的消息文本
            optionalUpdateMessage: '有新版本了,是否更新?',
            // Alert窗口的标题
            title: '更新提示'
          }
        },
        (status) => {
          switch (status) {
            case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
              console.log('DOWNLOADING_PACKAGE')
              break
            case CodePush.SyncStatus.INSTALLING_UPDATE:
              console.log(' INSTALLING_UPDATE')
              break
          }
        },
        (progress) => {
          console.log(progress.receivedBytes + ' of ' + progress.totalBytes + ' received.')
        })
      }
    })
  }

最后得到的界面如下:

六、如何发布CodePush更新包

在将React Native的bundle放到CodePush服务器之前,我们需要先生成bundle,在将bundle上传到CodePush

生成bundle

  • 在RN项目的根目录下创建bundle文件夹,然后创建android文件夹
  • 生成bundle命令react-native bundle --platform 平台 --entry-file 启动文件 --bundle-output 打包js输出文件 --assets-dest 资源输出目录 --dev 是否调试
$ react-native bundle --platform android --entry-file index.js --bundle-output ./bundle/android/main.jsbundle  --assets-dest ./bundle/android --dev false

上传bundle

  • 将生成的bundle文件上传到CodePush,我们直接执行下面的命令即可
$ code-push release-react <Appname> <Platform> --t <本更新包面向的旧版本号> --des <本次更新说明>
$ code-push release-react androidApp android --t 1.0.0 --dev false --d Staging --des "这是第一个更新包" --m true

注意:--m true表示强制更新

查看历史bundle

查看发布的历史记录,命令如下

  • 查询Production
$ code-push deployment history projectName Production
  • 查询Staging
$ code-push deployment history projectName Staging