react-native-code-push热更新流程(Android)

安装与注册CodePush

安装 CodePush CLI

在终端输入如下:

 npm install -g code-push-cli
 code-push -v //查看版本 

创建一个CodePush 账号

 code-push register//注册
 code-push login//登录

在终端输入code-push register,会打开注册页面让你选择授权账号。授权通过之后,CodePush会告诉你“access key”,复制此key到终端即可完成注册。 https://appcenter.ms/

集成CodePush SDK

第一步:在项目中安装 react-native-code-push插件,终端进入你的项目根目录然后运行

 npm install react-native-code-push --save

Android集成SDK

第二步: 运行 npm link react-native-code-push。这条命令将会自动帮我们在anroid文件中添加好设置

第三步: 在 android/app/build.gradle文件里面添如下代码:

 apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"

如果第二步没有成功,则手动配置

... 
dependencies { 
...  
  implementation project(':react-native-code-push') 
... 
} 
...

在/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')

在/android/app/src/com/.../.../MainApplication.java中添加如下代码:

 ...
 import com.microsoft.codepush.react.CodePush; 
 ...
 @Override
 protected String getJSBundleFile() { 
     return CodePush.getJSBundleFile(); 
}
... 
@Override 
protected List<ReactPackage> getPackages() { 
  return Arrays.<ReactPackage>asList( 
    ...               
    new CodePush(CODEPUSH_KEY_STAGING, getApplicationContext(), BuildConfig.DEBUG) );
}  
...

第四步: 运行 code-push deployment -k ls <appName>获取 部署秘钥。默认的部署名是 staging,所以 部署秘钥(deployment key ) 就是 staging。

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

public class MainApplication extends MultiDexApplication implements ReactApplication { 
  private final String CODEPUSH_KEY_PRODUCTIO = "your Production key";
  private final String CODEPUSH_KEY_STAGING = "your Staging key";
  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
  ...     
    @Override 
     protected String getJSBundleFile() {  
       return CodePush.getJSBundleFile(); 
     } 
     @Override   
     public boolean getUseDeveloperSupport() {  
        return BuildConfig.DEBUG; 
     } 
    @Override    
    protected List<ReactPackage> getPackages() {  
       return Arrays.<ReactPackage>asList(    
         new CodePush(CODEPUSH_KEY_STAGING, getApplicationContext(), BuildConfig.DEBUG)  
       ); 
    } 
    ...
  };  
  @Override 
  public ReactNativeHost getReactNativeHost() {  
    return mReactNativeHost; 
  } 
}

第六步:修改versionName。
在 android/app/build.gradle中有个 android.defaultConfig.versionName属性,我们需要把 应用版本改成 0.0.1(默认是1.0,但是codepush需要三位数)。

android{ 
  ...
  defaultConfig{ 
     versionName "0.0.1" 
  }
  ...
}

使用CodePush

codepush常用命令

  • 安装 CodePush CLI: npm install -g code-push-cli
  • 创建一个CodePush 账号: code-push register
  • 登陆:code-push login
  • 注销:code-push loout
  • 列出登陆的token: code-push access-key ls
  • 删除某个 access-key: code-push access-key rm <accessKye>
  • 创建一个app: code-push app add <appName> <os> <platform> 其中os为ios或android,platform为react-native
  • 在账号里移除一个 app:code-push app remove 或者 rm
  • 重命名一个存在 app: code-push app rename
  • 列出账号下面的所有 app: code-push app list 或则 ls
  • 把app的所有权转移到另外一个账号:code-push app transfer
  • 直接使用下面的命令查到对应应用的deployment key: code-push deployment ls <appName> -k
  • 部署:code-push deployment add <appName>
  • 重命名:code-push deployment rename <appName>
  • 删除部署:code-push deployment rm <appName>
  • 列出应用的部署情况:code-push deployment ls <appName>
  • 查看部署的key:code-push deployment ls <appName> -k
  • 查看历史版本:code-push deployment history <appName> <deploymentNmae> (Production 或者 Staging)
  • 发布热更新:code-push release-react <appName> <os> --description "1.描述"
  • 发布热更新:code-push release-react <appName> <os> -t 版本 -d 环境 --des 描述 -m true (强制更新)
  • 删除部署:code-push deployment rm <appName> <deploymentNmae> deploymentNmae(Production 或者 Staging)
  • 清除历史部署记录 code-push deployment clear <appName> Production or Staging
  • 回滚 code-push rollback <appName> Production --targetRelease v4(codepush服务部署的版本号)

更新方式

1、首先最简单的一种就是 这种无声的热更新,也就是说热更新不会给用户任何提示,都在默默的进行更新,用户完全体会不到整个过程

class MyApp extends Component<{}> {}

MyApp= CodePush(MyApp);

export default MyApp;

2、第二种 也是无声更新,比第一种情况多了一种就是热更新每次会在后台返回前台的时候进行热更新。这里可以看到几个参数,

checkFrequency有三种状态如下

ON_APP_START: //在组件初始化的时候进行热更新

ON_APP_RESUME://在每次app从后台回到前台的时候进行热更新

MANUAL://不进行热更新,需要自己手动配置

InstallMode 有如下几种状态

IMMEDIATE :// 安装热更新,并且重启app

ON_NEXT_RESTART: //下次启动的时候启动热更新

ON_NEXT_RESUME //从后台回到前台的时候启动

ON_NEXT_SUSPEND: 在后台的时候进行热更新

class MyApp extends Component<{}> {}

MyApp= CodePush({ 
checkFrequency: codePush.CheckFrequency.ON_APP_RESUME,
installMode: codePush.InstallMode.ON_NEXT_RESUME
})(MyApp);

export default MyApp;

updateDialog 当为true 是,可以在更新的时候提示用户需要更新

** 关于部署秘钥的检测更新(已配置可忽略deploymentKey)和更新包下载进度提示modal

import React, {Component} from 'react';
import { Platform,Modal,View,Text } from 'react-native';
import {Provider} from 'mobx-react/native';
import stores from './store/';
import Routers from './routers/';
import CodePush from 'react-native-code-push';

const Dimensions = require('Dimensions');
const screenW = Dimensions.get('window').width;

const CODEPUSH_KEY = {
  Android:{
    Staging:'YOUR_ANDROID_STAGING_KEY',
    Production:'YOUR_ANDROID_PRODUCTION_KEY'
  },
  Ios:{
    Staging:'YOUR_IOS_STAGING_KEY',
    Production:'YOUR_IOS_PRODUCTION_KEY'
  }
}

class App extends Component<Props> {
  state = {
    modalVisible: false,
    downloadProgess:0
  }
  componentDidMount(){
    CodePush.sync({
      deploymentKey:Platform.OS=='android'?CODEPUSH_KEY.Android.Production:CODEPUSH_KEY.Ios.Production,
      installMode: CodePush.InstallMode.IMMEDIATE,
      updateDialog : {
        //是否显示更新描述
        appendReleaseDescription : true ,
        //更新描述的前缀。 默认为"Description"
        descriptionPrefix : "\n\n更新說明:\n" ,
        //强制更新按钮文字,默认为continue
        mandatoryContinueButtonLabel : "立即更新" ,
        //强制更新时的信息. 默认为"An update is available that must be installed."
        mandatoryUpdateMessage : "發現重要更新,必須更新後才能使用!" ,
        //非强制更新时,按钮文字,默认为"ignore"
        optionalIgnoreButtonLabel : '稍後' ,
        //非强制更新时,确认按钮文字. 默认为"Install"
        optionalInstallButtonLabel : '立即更新' ,
        //非强制更新时,检查到更新的消息文本
        optionalUpdateMessage : '發現新版本,是否更新?' ,
        //Alert窗口的标题
        title : '更新提示'
      }
    },(status) => {
      switch(status) {
          case CodePush.SyncStatus.CHECKING_FOR_UPDATE:
            // console.warn("Checking for updates.");
          break;
          case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
            this.setState({ modalVisible:true })
            // console.warn("Downloading package.");
          break;
          case CodePush.SyncStatus.INSTALLING_UPDATE:
            this.setState({ modalVisible:false })
            // console.warn("Installing update.");
          break;
          case CodePush.SyncStatus.UP_TO_DATE:
            this.setState({ modalVisible:false });
            // console.warn("Installing uptodate.");
          break;
          case CodePush.SyncStatus.UPDATE_INSTALLED:
            this.setState({ modalVisible:false });
            // console.warn("Update installed.");
          break;
        }
      },(progress) => {
        let receivedBytes = progress.receivedBytes;
        let totalBytes = progress.totalBytes;
        let downloadProgess = (receivedBytes/totalBytes).toFixed(2) ;
        this.setState({ downloadProgess:downloadProgess });
        // console.warn(progress.receivedBytes + " of " + progress.totalBytes + " received.");
      }
    )
  }
  render() {
    let { modalVisible,downloadProgess } = this.state;
    let percentProgess = String(parseInt(downloadProgess*100)) + '%';
    return <View style={{flex:1}}>
      <Provider {...stores}><Routers/></Provider>
      <Modal
        visible={modalVisible}
        animated={'slide'}
        transparent={true}
        onRequestClose={()=>this.setState({ modalVisible:false })}
      >
        <View style={{flex:1,backgroundColor:'rgba(0,0,0,0.4)',flexDirection:'row',alignItems:'center',justifyContent:'center'}}>
          <View style={{alignItems:'center',justifyContent:'center'}}>
            <View style={{flexDirection:'row',alignItems:'center',justifyContent:'center'}}>
              <View style={{width:screenW*0.6,height:20,borderRadius:10,backgroundColor:'#e5e5e5'}}>
                <View style={{width:screenW*0.6*downloadProgess,height:20,borderRadius:10,backgroundColor:'#ff6952'}}></View>
              </View>
              <Text style={{color:'#fff',marginLeft:10,fontSize:14}}>{percentProgess}</Text>
            </View>
            <Text style={{color:'#fff',marginTop:12}}>{downloadProgess<1?'正在下載更新資源包,請稍候。。。':'下載完成,應用即將重啟'}</Text>
          </View>
        </View>
      </Modal>
    </View> ;
  }
}

App=CodePush({checkFrequency: CodePush.CheckFrequency.ON_APP_START})(App);

export default App;

发布更新

code-push release-react <appName> <os> --description "1.描述"

1.code-push release-react MyApp-ios ios --description "1.测试热更新"
2.code-push release-react MyApp-android android --description "1.测试热更新"

以下发布更新需手动打包:
code-push release <应用名称> <Bundles所在目录> <对应的应用版本> --deploymentName: 更新环境 --description: 更新描述 --mandatory: 是否强制更新

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

推荐阅读更多精彩内容