React-Native Android集成Code-Push 热更新

本文介绍了如何在React-Native Android项目中集成Code-Push实现热更新,包括code-push常用命令、项目集成步骤、设置更新策略以及发布更新的方法。重点讲解了在build.gradle中配置deployment-key,以及使用JavaScript API控制更新策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. code-push 常用命令

  • 安装客户端: npm install -g code-push-cli
  • 注册账号: code-push register(自建服务不需要注册)
  • 登陆: code-push login <address>
    例如:
code-push login http://localhost:3000

image.png

执行完后会自动打开浏览器,输入用户密码密码后跳转到获取 token 页面

image.png

点击获取 token,将生成的 token 复制到控制台

image.png

image.png

此处可以看到登陆成功,并且将登陆信息持久化保存到了文件里,只要文件不删除,就不需要重新登陆。Your session file was written to C:\Users\42556\AppData\Local\.code-push.config,当再次登陆时会提示!

image.png

  • 注销: code-push logout
    注销登陆时会删除用户本地存储的登录信息,当遇到不能正常注销时,可手动删除.code-push.config 文件

image.png

  • 添加项目: code-push app add [app名称] android/ios react-native
    注意:一定要为 Android 和 iOS 分别注册,两者的更新包内容会有差异,这里建议在 App 名称后加上操作系统类型如 Android 或 iOS 以方便区分。

image.png

添加成功后会返回不同运行时环境的 Key,比如 Production,Staging等。

  • 删除项目: code-push app remove [app名称]

image.png

  • 列出账号下的所有项目:code-push app list

image.png

  • 显示登陆的 token: code-push access-key ls

image.png

  • 删除某个 access-key: code-push access-key rm <accessKey>

  • 添加协作人员code-push collaborator add <appName> lizhenhua@agree.com.cn

  • 添加一个部署环境: code-push deployment add <appName> <deploymentName>

image.png

  • 删除部署: code-push deployment rm <appName> <deploymentName>

image.png

  • 列出应用的部署: code-push deployment ls <appName>

image.png

  • 查询部署环境的 key: code-push deployment ls <appName> -k

image.png

  • 查看部署的历史版本信息: code-push deployment history <appName> <deploymentName>

image.png

  • 重命名一个部署环境名称: code-push deployment rename <appName> <currentDeploymentName> <newDeploymentName>

image.png

2.集成到项目

  • 第一步:安装 CodePush 插件npm install -g code-push-cli
    安装完毕后,输入 code-push -v查看版本,如看到版本代表成功。
    注意:自建 code-push-server 服务与 react-native-code-push 版本有强依赖关系,如果对应有问题则会导致无法正常更新,本项目 rn 版本0.60.4,使用 code-push-server 版本为0.5.4,react-native-code-push 插件版本 0.5.6。我尝试使用最新的 code-push 插件版本为 0.5.7,但服务请求路径完全不配套。目前 code-push 与 rn 版本的对应关系如下image.png

  • 第二步:引入到项目里

    • 2.2.1 自动引入react-native link react-native-code-push(建议手动引入,这样清楚具体添加了哪些内容)
    • 2.2.2 手动引入
      在 android/app/build.gradle 文件里面添如下代码:
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
dependencies {
...
    implementation project(':react-native-code-push')
}
并修改defaultConfig中的versionName为三位(默认为1.0),如1.0.0

然后在/android/settings.gradle 中添加如下代码:

include ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
  • 第三步:运行 code-push deployment -k ls <appName>获取 部署秘钥。默认的部署名是 staging,所以 部署秘钥(deployment key ) 就是 staging。

  • 第四步:添加配置。当 APP 启动时我们需要让 app 向 CodePush 咨询 JS bundle 的所在位置,这样 CodePush 就可以控制版本。更新 MainApplication.java 文件

public class MainApplication extends Application implements ReactApplication {
  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    protected boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }
    @Override
    protected String getJSBundleFile() {
      return CodePush.getJSBundleFile();
    }
    @Override
    protected List<ReactPackage> getPackages() {
      // 3. Instantiate an instance of the CodePush runtime and add it to the list of
      // existing packages, specifying the right deployment key. If you don't already
      // have it, you can run "code-push deployment ls <appName> -k" to retrieve your key.
      return Arrays.<ReactPackage>asList(
        new MainReactPackage(),
        new CodePush("deployment-key-here", MainApplication.this, BuildConfig.DEBUG,"YOUR_SERVER_URL")
      );
    }
  };
  @Override
  public ReactNativeHost getReactNativeHost() {
      return mReactNativeHost;
  }
}

别忘了

import com.microsoft.codepush.react.CodePush;

关于 deployment-key 的设置

在上述代码中我们在创建 CodePush 实例的时候需要设置一个 deployment-key,因为 deployment-key 分生产环境与测试环境两种,所以建议大家在 build.gradle 中进行设置。在 build.gradle 中的设置方法如下:

打开 android/app/build.gradle 文件,找到android { buildTypes {} }然后添加如下代码即可:

android {
    ...
    buildTypes {
        debug {
            ...
            // CodePush updates should not be tested in Debug mode
            ...
        }

        releaseStaging {
            ...
            buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_STAGING_KEY>"'
            ...
        }

        release {
            ...
            buildConfigField "String", "CODEPUSH_KEY", '"<INSERT_PRODUCTION_KEY>"'
            ...
        }
    }
    ...
}

心得:另外,我们也可以将 deployment-key 存放在 local.properties 中:

code_push_key_production=erASzHa1-wTdODdPJDh6DBF2Jwo94JFH08Kvb
code_push_key_staging=mQY75RkFbX6SiZU1kVT1II7OqWst4JFH08Kvb

然后在就可以在 android/app/build.gradle 可以通过下面方式来引用它了:

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
android {
    ...
    buildTypes {
        debug {
            ...
            // CodePush updates should not be tested in Debug mode
            ...
        }

        releaseStaging {
            ...
            buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_production")+'"'
            ...
        }

        release {
            ...
            buildConfigField "String", "CODEPUSH_KEY", '"'+properties.getProperty("code_push_key_staging")+'"'
            ...
        }
    }
    ...
}

在 android/app/build.gradle 设置好 deployment-key 之后呢,我们就可以这样使用了:

@Override
protected List<ReactPackage> getPackages() {
     return Arrays.<ReactPackage>asList(
         ...
         new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG,"YOUR_CODE_PUSH_SERVER"), // Add/change this line.
         ...
     );
}

至此 Code Push for Android 的 SDK 已经集成完成。

3.设置更新策略

在使用 CodePush 更新你的应用之前需要,先配置一下更新控制策略,即:

  • 什么时候检查更新?(在 APP 启动的时候?在设置页面添加一个检查更新按钮?)
  • 什么时候可以更新,如何将更新呈现给终端用户?

最简单的方式是在根 component 中进行上述策略控制。

  1. 在 js 中加载 CodePush 模块:
    import codePush from 'react-native-code-push'
    2.在 componentDidMount中调用 sync方法,后台请求更新
    codePush.sync()

如果可以进行更新,CodePush 会在后台静默地将更新下载到本地,等待 APP 下一次启动的时候应用更新,以确保用户看到的是最新版本。
如果更新是强制性的,更新文件下载好之后会立即进行更新。
如果你期望更及时的获得更新,可以在每次 APP 从后台进入前台的时候去主动的检查更新:
在应用的根 component 的componentDidMount中添加如下代码:

AppState.addEventListener("change", (newState) => {
    newState === "active" && codePush.sync();
});
JavaScript API Reference
  • allowRestart
  • checkForUpdate
  • disallowRestart
  • getUpdateMetadata
  • notifyAppReady
  • restartApp
  • sync

其实我们可以将这些 API 分为两类,一类是自动模式,一类是手动模式。

自动模式

sync为自动模式,调用此方法 CodePush 会帮你完成一系列的操作。其它方法都是在手动模式下使用的。
codePush.sync
codePush.sync(options: Object, syncStatusChangeCallback: function(syncStatus: Number), downloadProgressCallback: function(progress: DownloadProgress)): Promise<Number>;
通过调用该方法 CodePush 会帮我们自动完成检查更新,下载,安装等一系列操作。除非我们需要自定义 UI 表现,不然直接用这个方法就可以了。
sync 方法,提供了如下属性以允许你定制 sync 方法的默认行为

  • deploymentKey (String): 部署 key,指定你要查询更新的部署秘钥,默认情况下该值来自于 Info.plist(Ios)和 MianActivity.java(Android)文件,你可以通过设置该属性来动态查询不同部署 key 下的更新。
  • installMode (codePush.InstallMode): 安装模式,用在向 CodePush 推送更新时没有设置强制更新(mandatory 为 true)的情况下,默认 codePush.InstallMode.ON_NEXT_RESTART 即下一次启动的时候安装。
  • mandatoryInstallMode (codePush.InstallMode):强制更新,默认 codePush.InstallMode.IMMEDIATE。
  • minimumBackgroundDuration (Number):该属性用于指定 app 处于后台多少秒才进行重启已完成更新。默认为 0。该属性只在installModeInstallMode.ON_NEXT_RESUME情况下有效。
  • updateDialog (UpdateDialogOptions) :可选的,更新的对话框,默认是 null,包含以下属性
    • appendReleaseDescription (Boolean) - 是否显示更新 description,默认 false
    • descriptionPrefix (String) - 更新说明的前缀。 默认是” Description: “
    • mandatoryContinueButtonLabel (String) - 强制更新的按钮文字. 默认 to “Continue”.
    • mandatoryUpdateMessage (String) - 强制更新时,更新通知. Defaults to “An update is available that must be installed.”.
    • optionalIgnoreButtonLabel (String) - 非强制更新时,取消按钮文字. Defaults to “Ignore”.
    • optionalInstallButtonLabel (String) - 非强制更新时,确认文字. Defaults to “Install”.
    • optionalUpdateMessage (String) - 非强制更新时,更新通知. Defaults to “An update is available. Would you like to install it?”.
    • title (String) - 要显示的更新通知的标题. Defaults to “Update available”.

eg:

codePush.sync({
updateDialog: {
appendReleaseDescription: true,
descriptionPrefix:'\n\n 更新内容:\n',
title:'更新',
mandatoryUpdateMessage:'',
mandatoryContinueButtonLabel:'更新',
},
mandatoryInstallMode:codePush.InstallMode.IMMEDIATE,
deploymentKey: CODE_PUSH_PRODUCTION_KEY,
});

手动模式

codePush.allowRestart

codePush.allowRestart(): void;
允许重新启动应用以完成更新。
如果一个 CodePush 更新将要发生并且需要重启应用(e.g.设置了 InstallMode.IMMEDIATE 模式),但由于调用了disallowRestart方法而导致 APP 无法通过重启来完成更新, 可以调用此方法来解除disallowRestart限制。
但在如下四种情况下,CodePush 将不会立即重启应用:

  1. 自上一次disallowRestart被调用,没有新的更新。
  2. 有更新,但installModeInstallMode.ON_NEXT_RESTART的情况下。
  3. 有更新,但installModeInstallMode.ON_NEXT_RESUME,并且程序一直处于前台,并没有从后台切换到前台的情况下。
  4. 自从上次disallowRestart被调用,没有再调用restartApp

codePush.checkForUpdate

codePush.checkForUpdate(deploymentKey: String = null): Promise<RemotePackage>;
向 CodePush 服务器查询是否有更新。
该方法返回 Promise,有如下两种值:

  • null 没有更新
    通常有如下情况导致 RemotePackage 为 null:

    1. 当前 APP 版本下没有部署新的更新版本。也就是说没有想 CodePush 服务器推送基于当前版本的有关更新。
    2. CodePush 上的更新和用户当前所安装的 APP 版本不匹配。也就是说 CodePush 服务器上有更新,但该更新对应的 APP 版本和用户安装的当前版本不对应。
    3. 当前 APP 已将安装了最新的更新。
    4. 部署在 CodePush 上可用于当前 APP 版本的更新被标记成了不可用。
    5. 部署在 CodePush 上可用于当前 APP 版本的更新是"active rollout"状态,并且当前的设备不在有资格更新的百分比的设备之内。
  • A RemotePackage instance
    有更新可供下载。

eg:

codePush.checkForUpdate()
.then((update) => {
if (!update) {
console.log("The app is up to date!");
} else {
console.log("An update is available! Should we download it?");
}
});

codePush.disallowRestart

codePush.disallowRestart(): void;
不允许立即重启用于以完成更新。
eg:

class OnboardingProcess extends Component {
...

componentWillMount() {
    // Ensure that any CodePush updates which are
    // synchronized in the background can't trigger
    // a restart while this component is mounted.
    codePush.disallowRestart();
}

componentWillUnmount() {
    // Reallow restarts, and optionally trigger
    // a restart if one was currently pending.
    codePush.allowRestart();
}

...

}

codePush.getUpdateMetadata
codePush.getUpdateMetadata(updateState: UpdateState = UpdateState.RUNNING): Promise<LocalPackage>;
获取当前已安装更新的元数据(描述、安装时间、大小等)。
eg:

// Check if there is currently a CodePush update running, and if
// so, register it with the HockeyApp SDK (
https://github.com/slowpath/react-native-hockeyapp)
// so that crash reports will correctly display the JS bundle version the user was running.
codePush.getUpdateMetadata().then((update) => {
if (update) {
hockeyApp.addMetadata({ CodePushRelease: update.label });
}
});

// Check to see if there is still an update pending.
codePush.getUpdateMetadata(UpdateState.PENDING).then((update) => {
if (update) {
// There's a pending update, do we want to force a restart?
}
});

codePush.notifyAppReady
codePush.notifyAppReady(): Promise<void>;
通知 CodePush,一个更新安装好了。当你检查并安装更新,(比如没有使用 sync 方法去 handle 的时候),这个方法必须被调用。否则 CodePush 会认为 update 失败,并 rollback 当前版本,在 app 重启时。
当使用sync方法时,不需要调用本方法,因为sync会自动调用。

codePush.restartApp
codePush.restartApp(onlyIfUpdateIsPending: Boolean = false): void;
立即重启 app。 当以下情况时,这个方式是很有用的:

  1. app 当 调用 syncLocalPackage.install 方法时,指定的 install mode ON_NEXT_RESTARTON_NEXT_RESUME时 。 这两种情况都是当 app 重启或resume时,更新内容才能被看到。
  2. 在特定情况下,如用户从其它页面返回到 APP 的首页时,这个时候调用此方法完成过更新对用户来说不是特别的明显。因为强制重启,能马上显示更新内容。

4.发布更新

CodePush 支持两种发布更新的方式,一种是通过code-push release-react简化方式,另外一种是通过code-push release的复杂方式。

第一种方式:通过code-push release-react发布更新

这种方式将打包与发布两个命令合二为一,可以说大大简化了我们的操作流程,建议大家多使用这种方式来发布更新。

命令格式:

code-push release-react <appName> <platform>

eg:

code-push release-react MyApp-iOS ios
code-push release-react MyApp-Android android

再来个更高级的:

code-push release-react MyApp-iOS ios  --t 1.0.0 --dev false --d Production --des "1.优化操作流程" --m true

其中参数--t 为二进制(.ipa 与 apk)安装包的的版本;--dev 为是否启用开发者模式(默认为 false);--d 是要发布更新的环境分 Production 与 Staging(默认为 Staging);--des 为更新说明;--m 是强制更新。

关于code-push release-react更多可选的参数,可以在终端输入code-push release-react进行查看。

另外,我们可以通过code-push deployment ls <appName>来查看发布详情与此次更新的安装情况。

第二种方式:通过code-push release发布更新

code-push release发布更新呢我们首先需要将 js 与图片资源进行打包成 bundle。

生成 bundle

发布更新之前,需要先把 js 打包成 bundle,如:

第一步: 在 工程目录里面新增 bundles 文件:mkdir bundles

第二步: 运行命令打包 react-native bundle --platform 平台 --entry-file 启动文件 --bundle-output 打包js输出文件 --assets-dest 资源输出目录 --dev 是否调试
eg:
react-native bundle --platform android --entry-file index.android.js --bundle-output ./bundles/index.android.bundle --dev false
image.png
需要注意的是:

  • 忽略了资源输出是因为 输出资源文件后,会把 bundle 文件覆盖了。
  • 输出的 bundle 文件名不叫其他,而是 index.android.bundle,是因为 在 debug 模式下,工程读取的 bundle 就是叫做 index.android.bundle。
  • 平台可以选择 Android 或者 iOS。
发布更新

打包 bundle 结束后,就可以通过 CodePush 发布更新了。在终端输入

code-push release <应用名称> <Bundles所在目录> <对应的应用版本> --deploymentName: 更新环境 --description: 更新描述 --mandatory: 是否强制更新

eg:

code-push release MbankAndroid ./bundles/index.android.bundle 1.0.0 --deploymentName Production --description "1.更新测试。" --mandatory true

上面仅仅是发布 js 文件,如果要带资源一起发布,用下面方式

code-push release MbankAndroid ./bundles 1.0.0 --deploymentName Production --description "1.更新测试。" --mandatory true

image.png

注意:

  1. CodePush 默认是更新 staging 环境的,如果是 staging,则不需要填写 deploymentName。
  2. 如果有 mandatory 则 Code Push 会根据 mandatory 是 true 或 false 来控制应用是否强制更新。默认情况下 mandatory 为 false 即不强制更新。
  3. 对应的应用版本(targetBinaryVersion)是指当前 app 的版本(对应 build.gradle 中设置的 versionName "1.0.0"),也就是说此次更新的 js/images 对应的是 app 的那个版本。不要将其理解为这次 js 更新的版本。 如客户端版本是 1.0.0,那么我们对 1.0.0 的客户端更新 js/images,targetBinaryVersion 填的就是 1.0.0。
  4. 对于对某个应用版本进行多次更新的情况,CodePush 会检查每次上传的 bundle,如果在该版本下如 1.0.0 已经存在与这次上传完全一样的 bundle(对应一个版本有两个 bundle 的 md5 完全一样),那么 CodePush 会拒绝此次更新。
  5. 在终端输入 code-push deployment history <appName> Staging 可以看到 Staging 版本更新的时间、描述等等属性。
    非强制更新
    强制更新

应用启动之后,从 CodePush 服务器查询更新,并下载到本地,下载好之后,提示用户进行更新,上图分别是非强制更新和强制更新。这就是 CodePush 用于热更新的整个过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值