React Native CodePush热更新(iOS)

接入流程

1.安装 CodePush cli:

1>  npm install -g code-push-cli
2> 安装完毕后,输入 code-push -v  查看版本,如看到版本代表成功

2.创建 CodePush账号:

1> code-push register  
   浏览器会自动打开授权界面, 成功后会返回一个“access key”,复制key到终端 
image.png

3.登陆

code-push login 

4.在CodePush服务器注册app

为了让CodePush服务器知道你的app,我们需要向它注册app: 
在终端输入 code-push app add 工程名 ios react-native 即可完成注册

Production 和staging 的意思 (Production 代表的是发布的版本。Staging 代表的是测试的版本


image.png

备注: 如果你的应用分为Android和iOS版,那么在向CodePush注册应用的时候需要注册两个App获取两套deployment key,如:

code-push app add 工程名 android react-native
code-push app add 工程名 ios react-native

4.RN代码中集成CodePush

1.    
yarn add react-native-code-push 
或 
npm install --save react-native-code-push

2.
react-native link react-native-code-push
或
rnpm link react-native-code-push

终端会让你输入deployment key, 直接enter就可以
   js文件中代码, 目前只是个demo:

 import codePush from 'react-native-code-push';
 class Demo extends Component {

// 这函数可以不看
static navigationOptions = (navigation)=>({
headerStyle: {
// 如果想去掉安卓导航条底部阴影可以添加elevation: 0,
// iOS下用shadowOpacity: 0。
borderBottomWidth: 0,
shadowOpacity: 0,
elevation: 0,
backgroundColor: '#ff2d55',} });

 componentWillMount(){
    // 页面加载的禁止重启,在加载完了可以允许重启
    // codePush.disallowRestart();
 }
 componentDidMount() {
    // 在加载完了可以允许重启
    // codePush.allowRestart();
 }

 /** Update pops a confirmation dialog, and then immediately reboots the app 一键更新,加入的配置项 */
 syncImmediate = () => {
    let deploymentKey = 'rC0WldnclzcbMTsKsvEtlRF0GMz08ae2879f-9331-47b3-a5e0-2466eb275995';

  codePush
      .checkForUpdate(deploymentKey)
      .then((update) => {

         if (!update) {
            Alert.alert("提示", "已是最新版本--", [
               {
                  text: "Ok", onPress: () => {
                     console.log("点了OK");
                  }
               }
            ]);
         } else {
            codePush.sync(
                {
                   deploymentKey: deploymentKey,
                   updateDialog: {
                      // true 表示在发布更新时的描述会显示到更新对话框上让用户可见
                      appendReleaseDescription: true,
                      title: '更新提示',

                      // 非强制更新设置的内容提示信息
                      optionalIgnoreButtonLabel: '稍后',
                      optionalInstallButtonLabel: '立即更新',
                      optionalUpdateMessage: '有新版本了,是否更新?',

                      // 强制更新设置的内容信息
                      mandatoryUpdateMessage:'有新版本了,必须进行更新,才能使用',
                      mandatoryContinueButtonLabel:'立即更新',

                   },
                   /*
                   * installMode (codePush.InstallMode): 安装模式,用在向CodePush推送更新时没有设置强制更新(mandatory为true)的情况下,默认codePush.InstallMode.ON_NEXT_RESTART 即下一次启动的时候安装。
                   * 在更新配置中通过指定installMode来决定安装完成的重启时机,亦即更新生效时机
                     codePush.InstallMode.IMMEDIATE:表示安装完成立即重启更新(强制更新安装模式)
                     codePush.InstallMode.ON_NEXT_RESTART:表示安装完成后会在下次重启后进行更新
                     codePush.InstallMode.ON_NEXT_RESUME:表示安装完成后会在应用进入后台后重启更新
                   *
                   *
                   * 强制更新模式(单独的抽出来设置 强制安装)
                   * mandatoryInstallMode (codePush.InstallMode):强制更新,默认codePush.InstallMode.IMMEDIATE
                   *
                   * minimumBackgroundDuration (Number):该属性用于指定app处于后台多少秒才进行重启已完成更新。默认为0。该属性只在installMode为InstallMode.ON_NEXT_RESUME情况下有效
                   *
                   * */
                   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.");
                }
            );
         }
  }).catch((error)=>{
     alert(error)
  });
};

// styles这里就不写出来
render() {
  return (
      <View style={styles.container}>
         <Image
             source={{uri: 'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo_top_86d58ae1.png'}}
             style={{width: 200, height: 80}}
             resizeMode={'contain'}
         />
          <Text style={styles.welcome}>
            可以在此做修改文本内容, 后打包 更新
          </Text>

          <TouchableOpacity
            // 点击按钮进行更新
             onPress={this.syncImmediate}
          >
            <Text style={styles.syncButton}>点击更新</Text>
         </TouchableOpacity>
      </View>
    );
  }
}
let codePushOptions = {
 //设置检查更新的频率
 //ON_APP_RESUME APP恢复到前台的时候
 //ON_APP_START APP开启的时候
 //MANUAL 手动检查
 checkFrequency : codePush.CheckFrequency.MANUAL
};

// 这一行必须要写
Demo = codePush(codePushOptions)(Demo);

export default Demo;

6.原生应用(xcode)中配置CodePush

关于deployment-key的设置
在我们想CodePush注册App的时候,CodePush会给我们两个deployment-key分别是在生产环境与测试环境时使用的,我们可以通过如下步骤来设置deployment-key:

1>用Xcode 打开项目 ➜ Xcode的项目导航视图中的PROJECT下选择你的项目 ➜ 选择Info页签 ➜ 在Configurations节点下单击 + 按钮 ➜ 选择Duplicate "Release ➜ 输入Staging(名称可以自定义);


Duplicate-Release-Staging.png

2>然后在TARGET下 选择Build Settings页签 ➜ 单击 + 按钮然后选择添加User-Defined Setting

image.png

补充: 2.1> 选择Build Settings tab,搜索Build Location -> Per-configuration Build Products Path -> Staging,将之前的值

  $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 
  改为:  
  $(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)
image.png

3>然后输入CODEPUSH_KEY(名称可以自定义)

image.png
可通过code-push deployment ls APP_NAME -k  命令来查看deployment key

4>打开 Info.plist文件,在CodePushDeploymentKey列的Value中输入$(CODEPUSH_KEY)

image.png
  1. 修改Bundle versions为三位
image.png
  1. AppDelegate.m,单击打开,然后改为如下代码:


    image.png

7.发布更新的版本.

注意点: 如果是测试版本的话选择 Staging(这个build是之前自己加上的, 可以回头去看下)运行; 如果是发布版本的话, 就选择Release模式下


image.png
1> cd到项目文件, 创建文件bundles:
 mkdir bundles

2> 在文件bundles中在创建 ios文件/android文件, 后面可以分别打包在对应文件中. 
   我这里就只创建了ios文件
image.png

3>生成bundle命令 react-native bundle
--platform 平台
--entry-file 启动文件
--bundle-output 打包js输出文件
--assets-dest 资源输出目录
--dev 是否调试

react-native bundle --entry-file index.js --bundle-output ./bundles/ios/index.ios.bundle --assets-dest ./bundles/ios/ --platform ios --dev false

4>将生成的bundle文件和资源文件拖到我们的项目工程

image.png

5>上传bundle
将生成的bundle文件上传到CodePush,我们直接执行下面的命令即可
$ code-push release-react <Appname> <Platform> --t <本更新包面向的旧版本号> --des <本次更新说明>

注意: CodePush默认是更新Staging 环境的(--d Staging 可以不写),如果发布生产环境的更新包,需要指定--d参数:--d Production,如果发布的是强制更新包,需要加上 --m true强制更新.

code-push release-react Appname ios --t 1.0.0 --dev false --d Staging --des "描述" --m true

注意:

  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会拒绝此次更新。

所以如果我们要对某一个应用版本进行多次更新,只需要上传与上次不同的bundle/images即可.
因此, 当做了某些修改时, 需要重新打包bundle, 然后再进行更新
eg:

1. react-native bundle --entry-file index.js --bundle-output ./bundles/ios/index.ios.bundle --assets-dest ./bundles/ios/ --platform ios --dev false

2. code-push release-react Appname ios --t 1.0.0 --dev false --d Staging --des "描述" --m true

备注:
在终端输入 code-push deployment history appName Staging 可以看到Staging版本更新的时间、描述等等属性

PS.相关命令
code-push app add 工程名 ios/android react-native 在账号里面添加一个新的app
code-push app remove 或者 rm 在账号里移除一个app
code-push app rename 重命名一个存在app
code-push app list 或则 ls 列出账号下面的所有app
code-push app transfer 把app的所有权转移到另外一个账号
code-push loout 注销
code-push access-key ls 列出登陆的token
code-push access-key rm <accessKye> 删除某个 access-key

code-push deployment add <appName> 部署
code-push deployment rename <appName> 重命名
code-push deployment rm <appName> 删除部署
code-push deployment ls <appName> 列出应用的部署情况
code-push deployment ls <appName> -k 查看部署的key
code-push deployment history <appName> <deploymentName> 查看历史版本(Production 或者 Staging)

结果演示:


视频1.gif

视频2.gif
视频3.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容