CodePush简介
CodePush 是微软提供的一套用于热更新 React Native 和 Cordova 应用的服务。
CodePush 是提供给 React Native 和 Cordova 开发者直接部署移动应用更新给用户设备的云服务。CodePush 作为一个中央仓库,开发者可以推送更新 (JS, HTML, CSS and images),应用可以从客户端 SDK 里面查询更新。CodePush 可以让应用有更多的可确定性,也可以让你直接接触用户群。在修复一些小问题和添加新特性的时候,不需要经过二进制打包,可以直接推送代码进行实时更新。
第一步 安装CodePush终端
npm install -g code-push-cli
第二步 注册登录
code-push register
code-push login
注册登录的时候会打开浏览器 这个时候选择相应的第三方登录认证就好,我觉得每个程序员基本都会选择github
接着拷贝注册得到的token,复制到终端,按回车键登录即可
登录成功后可以看到如下内容:
Successfully logged-in. Your session file was written to /Users/hfmoney/.code-push.config. You can run the code-push logout command at any time to delete this file and terminate your session.
第三步 安装Code-Push SDK
以下集成以RNPM方式集成 个人觉得比较方便
在终端cd到你的RN项目目录下
npm install --save react-native-code-push@latest
react-native link react-native-code-push
第四步 添加你的项目 (以下以<appName>代替你的项目名称)
运行
code-push app add <appName> ios react-native
来创建iOS端的App,
或者运行
code-push app add <appName> android react-native
创建Android端的App。
成功后可以看到:
相关命令还有如下:
Usage: code-push app <command>
命令:
add 创建一个新的App
remove 删除App
rm 删除App
rename 重命名已经存在App
list 列出与你账户关联的所有App
ls 列出与你账户关联的所有App
transfer 将一个App的所有权转让给另一个帐户
第五步 在项目中集成Code Push
因本人是iOS开发者,故而下面安卓项目的集成为网上资料查得,未经验证,如有纰漏,还望指正.
iOS端集成
1.使用Xcode打开项目,Xcode的项目导航视图中的PROJECT下选择你的项目, 选择Info页签 ,在Configurations节点下单击 + 按钮 ,选择Duplicate "Release Configaration , 输入Staging。
2.在build Settings页签中单击 + 按钮然后选择添加User-Defined Setting,然后输入CODEPUSH_KEY(名称随意),然后填入deployment key。
3.打开 Info.plist文件,在CodePushDeploymentKey中输入$(CODEPUSH_KEY),并修改Bundle versions为三位,如下图
Android端集成
1.在 android/app/build.gradle文件里面添如下代码
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
2.然后在/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')
3.运行 code-push deployment -k ls <appName>获取 部署秘钥。默认的部署名是 staging,所以 部署秘钥(deployment key ) 就是 staging。
4.添加配置。当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)
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}
5.在上述代码中我们在创建CodePush实例的时候需要设置一个deployment-key,因为deployment-key分生产环境与测试环境两种,所以建议大家在build.gradle中进行设置。在build.gradle中的设置方法如下:
buildTypes {
debug{
//省略了其他配置
buildConfigField "String", "CODEPUSH_KEY", '""'
}
releaseStaging {
buildConfigField "String", "CODEPUSH_KEY", '"此处填写Staging key"'
}
release {
//省略了其他配置
buildConfigField "String", "CODEPUSH_KEY", '"此处填写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), // Add/change this line.
...
);
}
6.修改VersionName
在 android/app/build.gradle中有个 android.defaultConfig.versionName属性,我们需要把 应用版本改成 三位,比如1.0,需要修改成1.0.0
android{
defaultConfig{
versionName "1.0.0"
}
}
第六步 JS代码
最为简单的使用方式在React Natvie的根组件的componentDidMount方法中通过
codePush.sync()(需要先导入codePush包:import codePush from 'react-native-code-push')方法检查并安装更新,如果有更新包可供下载则会在重启后生效。不过这种下载和安装都是静默的,即用户不可见。如果需要用户可见则需要额外的配置。具体可以参考codePush官方API文档,下面是个人的一些实践过的配置:
codePush.sync({
updateDialog: {
appendReleaseDescription: true,
descriptionPrefix:'\n\n更新内容:\n',
title:'更新',
mandatoryUpdateMessage:'',
mandatoryContinueButtonLabel:'更新',
},
mandatoryInstallMode:codePush.InstallMode.IMMEDIATE,
deploymentKey: CODE_PUSH_PRODUCTION_KEY,
});
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。该属性只在installMode为InstallMode.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”.
或者是在用户点击检查更新按钮后进行检查,如果有更新则弹出提示框让用户选择是否更新,如果用户点击立即更新按钮,则会进行安装包的下载(实际上这时候应该显示下载进度,这里省略了)下载完成后会立即重启并生效(也可配置稍后重启)
let deploymentKey = '这里写入你的key值'
codePush.checkForUpdate(deploymentKey).then((update) => {
if (!update) {
Alert.alert("提示", "已是最新版本--", [
{
text: "Ok", onPress: () => {
console.log("点了OK");
}
}
]);
} else {
codePush.sync({
deploymentKey: deploymentKey,
updateDialog: {
optionalIgnoreButtonLabel: '稍后',
optionalInstallButtonLabel: '立即更新',
optionalUpdateMessage: '有新版本了,是否更新?',
title: '更新提示'
},
installMode: codePush.InstallMode.IMMEDIATE,
},
(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.");
}
);
}
})
第七步 打包
首先 要打包bundle 以下以iOS端为例 在项目中的ios目录下 新建一个bundle文件夹,然后在终端运行(注意是项目的路径下,不是ios的路径下)
react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle
react-native bundle --entry-file 启动文件 --platform 平台 --dev 是否调试 --bundle-output 打包js输出文件 --assets-dest 资源输出目录
然后在xcode中 加入bundle文件夹 右键菜单 点击Add Files to'<appName>'把文件夹加入到项目中
此外,还需要对AppDelegate.m文件进行修改:
// #ifdef DEBUG
// jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
// #else
jsCodeLocation = [CodePush bundleURL];
// #endif
否则更新重启后还是旧版的App。
然后在用xcode打包上架或者发测试包
第八步 更新
code-push release-react <appName> <platform>
例如
code-push release-react <appName>-iOS ios
code-push release-react <appName>-Android android
详细操作可以是
code-push release-react <appName>-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 <appName> <bundle目录> <targetBinaryVersion>
[--deploymentName <deploymentName>]默认staging
[--description <description>]更新描述(string)默认为null
[--mandatory]是否强制更新,默认false
[--disabled] 该版本客户端是否可以获得更新,默认为false
[--rollout]此更新推送的用户的百分比(string),默认值为null
修改更新
code-push patch <appName> <deploymentName>
--label, -l 指定标签版本更新,默认最新版本 [string] [默认值: null]
--description, --des 描述 [string] [默认值: null]
--disabled, -x 该修改更新,客户端是否可以获得更新 [boolean] [默认值: null]
--mandatory, -m 是否强制更新 [boolean] [默认值: null]
--rollout, -r 此更新推送用户的百分比,此值仅可以从先前的值增加。 [string] [默认值: null]
示例:
code-push patch <appName> Production --des "Updated description" -r 50 修改"<appName>"的"Production"部署中最新更新的描述 ,并且更新推送范围为50%
code-push patch <appName> Production -l v3 --des "Updated description for v3" 修改"<appName>"的"Production"部署中标签为v3的更新的描述
总结
CodePush也存在着一些缺点:
服务器在国外,在国内访问,网速不是很理想。
其升级服务器端程序并不开源的,后期微软会不会对其收费还是个未知数。
如果在没有更好的动态更新React Native应用的方案的情况下,并且这些问题还在你的接受范围之内的话,那么CodePush可以作为动态更新React Native应用的一种选择。
后期会向大家分享不采用CodePush,自己搭建服务器并实现React Native应用的动态更新相关的方案。
官方文档
code push github: https://github.com/Microsoft/react-native-code-push
code push官网:http://microsoft.github.io/code-push/
code push cli手册:http://microsoft.github.io/code-push/docs/cli.html
code push javaScript Api: https://github.com/Microsoft/react-native-code-push/blob/master/docs/api-js.md#codepush
参考相关
https://www.jianshu.com/p/9e3b4a133bcc
https://www.jianshu.com/p/67de8aa052af
https://www.jianshu.com/p/e1a9302cfdff
https://blog.csdn.net/sinat_17775997/article/details/74016662