React Native--搭建本地Code Push Server实现高效热更新

CodePush 简介

CodePush是一个微软开发的云服务器。通过它,开发者可以直接在用户的设备上部署手机应用更新。

CodePush相当于一个中心仓库,开发者可以推送当前的更新(包括JS/HTML/CSS/IMAGE等)到CoduPush,然后应用将会查询是否有更新。

热更新的原理大致可以的理解为这样,由于 React Native 会将所有需要加载的 js 文件都打包在一个 bundle 文件中,而 app 运行时会加载该文件。所以,如果要升级 app,一个可行的思路就是动态替换该 bundle 文件,然后重启该 app 即可(如果修改了底层 native 代码则需要重新安装该 app )。

实际上在开发时使用的更新模式就是上面所说的这种,直接替换 bundle 文件。开发环境时使用调试工具可以 Reload JS(替换 bundle 文件),但是在生产环境却不存在该调试工具,需要自己手动实现动态替换 bundle 的功能,而 CodePush 就是实现了该功能的一个工具。

然而 CodePush 服务器是在国外的,国内使用的话速度并不理想,所以自建本地CodePush 服务是最理想的。

自建 CodePush 服务

CodePush 服务主要分为三个部分:服务端、客户端、React Native 项目。

一、服务端

服务端需要使用 code-push-serverMySQL 所以需要先将这两个安装好。

1. 安装MySQL

  • 官网下载后直接双击安装,下载地址
  • 打开“系统设置”,看到最新安装的MySQL,进入并启动服务。

2. 安装 code-push-server

作者发布了两种安装方式(npm安装或源码安装),在此我推荐使用源码安装,为后期我们要基于这个服务修改自己的网页,源码安装方便些。

  • (1)、下载code-push-server代码
// clone代码
git clone https://github.com/lisong/code-push-server.git

// 进入项目并安装资源
cd code-push-server && npm install
  • (2)、修改config/config.js 文件,在 db 对象中添加数据库信息,参考如下:
 db: {
    username: process.env.RDS_USERNAME || "root", // 数据库账户
    password: process.env.RDS_PASSWORD || "root", // 数据库账户密码
    database: process.env.DATA_BASE || "codepush", // 新建的数据库表名
    host: process.env.RDS_HOST || "127.0.0.1",
    port: process.env.RDS_PORT || 3306,
    dialect: "mysql",
    logging: false
  },
  • (3)、创建数据库表
// 初始化mysql数据库
./bin/db init --dbhost localhost --dbuser root --dbpassword 数据库密码

eg..
./bin/db init --dbhost 127.0.0.1 --dbuser root --dbpassword  root
  • (4)、配置打包后的,bundle存储地址,这里配置loal本地也可以配置qiniuOSS

创建storagedata文件夹,用来保存打包好的资源,供用户更新下载,downloadUrl地址必须为服务器所在的地址,不然用户无法下载到包。主要配置如下:

   // 如果存储类型“storageType”为“qiniu”如果更新包放在七牛,需要配置相关信息 (http://www.qiniu.com/) 。
  qiniu: {
    accessKey: "",
    secretKey: "",
    bucketName: "",
    downloadUrl: "" //文件下载域名地址
  },

  //阿里云存储配置 当storageType为oss时需要配置
  oss: {
    accessKeyId: "",
    secretAccessKey: "",
    endpoint: "",
    bucketName: "code-push-server",
    prefix: "storage", // Key prefix in object key
    downloadUrl: "https://code-push-server.oss-cn-shenzhen.aliyuncs.com/storage", // binary files download host address.
  },

  //文件存储在本地配置 当storageType为local时需要配置
  local: {
    storageDir: "/Users/lisilong/Desktop/workspaces/storage",
    //文件下载地址 CodePush Server 地址 + '/download' download对应app.js里面的地址
    downloadUrl: "http://localhost:3000/download",
    // public static download spacename.
    public: '/download'
  },

  jwt: {
    // 登录jwt签名密钥,必须更改,否则有安全隐患,可以使用随机生成的字符串
    // Recommended: 63 random alpha-numeric characters
    // Generate using: https://www.grc.com/passwords.htm
    tokenSecret: 'INSERT_RANDOM_TOKEN_KEY'
  },
  
  common: {
    dataDir: "/Users/lisilong/Desktop/workspaces/data",
    //选择存储类型,目前支持local,oss,qiniu,s3配置
    storageType: "local"
  },
  • (5)、改好之后,启动服务
// 在根目录中执行
./bin/www

在浏览其中输入:http://127.0.0.1:3000 能加载到CodePushServer登录界面即表示启动完成。

二.客户端

1. 客户端需要安装 code-push-cli 参考文档

npm install -g code-push-cli

2. 登录code-push-server,使code push和自建的服务器关联

执行命令查看当前是否登录,因为是新服务,所以要先保证没有别的账号正在登录

 code-push whoami

如果报错如下,表示没有登录

[Error]  You are not currently logged in. Run the 'code-push login' command to authenticate with the CodePush server.

如果没有报错 并且显示邮箱账号,则表示已经登录账户,则我们要先注销当前账号

code-push logout

成功注销后执行登录指令,浏览器会自动打开本地服务登录页面,命令行中会提示输入key。默认账号和密码为: admin 123456, 登录后获取token 并复制token到命令行中,并回车确认

code-push login http://localhost:3000

//提示此表示登录成功
Successfully logged-in…… 

3. 创建应用,获取 DeploymentKey

Usage: code-push app add <appName> <os> <platform>
选项:
  -v, --version  显示版本号  [布尔]

示例:
  app add MyApp ios react-native      Adds app "MyApp", indicating that it's an iOS React Native app
  app add MyApp windows react-native  Adds app "MyApp", indicating that it's a Windows React Native app
  app add MyApp android cordova       Adds app "MyApp", indicating that it's an Android Cordova app

e.g..
code-push app add ReactNativeCodePushDemo-ios ios react-native

结果如下:

│   Name     │ Deployment Key                        │
├────────────┼───────────────────────────────────────┤
│ Production │ EoQ6vVQ19YYXH18JxnoOVDsYtAcT4ksvOXqog │
├────────────┼───────────────────────────────────────┤
│ Staging    │ YO4pnZs4ePEG2F8p7dPWnS3oHDg74ksvOXqog │

其中Production对应的是生产的Deployment Key,Staging是开发时使用。

可以通过命令行查看更多相关命令,请查阅官方文档

code-push deployment ls XunHuiFinance-ios -k

三、React Native 项目端

1. 安装 react-native-code-push

// 项目中导入CodePush代码
npm install --save react-native-code-push
// 关联我们的项目
react-native link react-native-code-push

2.可以把检测更新的入口,添加到componentDidMount方法中:

componentDidMount() {
    CodePush.sync({
        //启动模式三种:ON_NEXT_RESUME、ON_NEXT_RESTART、IMMEDIATE
        installMode: CodePush.InstallMode.ON_NEXT_RESTART,
        // 苹果公司和中国区安卓的热更新,是不允许弹窗提示的,所以不能设置为true
        updateDialog: false  
    });
}

3. Android端配置

  • (1)、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')
  • (2)、build.gradle修改:
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"

dependencies {
    compile fileTree(dir: "libs", include: ["*.jar"])
    compile "com.android.support:appcompat-v7:23.0.1"
    compile "com.facebook.react:react-native:+"  // From node_modules
    compile project(':react-native-code-push')
}
  • (3)、MainApplication文件下修改
 private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {

   @Override
   protected String getJSBundleFile() {
        return CodePush.getJSBundleFile();
   }
    
    @Override
    public boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }

    //第一个参数是刚刚申请的key(可以根据环境配置)
    //第三个参数是服务器的URL
    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),
          new CodePush(" nJ3oSQmb64bxRqTP9mwMhZuZLIm94ksvOXqog ", MainApplication.this, BuildConfig.DEBUG,"http://你的IP:端口/")
      );
    }
  • (4)、修改版本号

将 android/app/build.gradle 中的 android.defaultConfig.versionName 改成3位数的版本号(默认是1.0,但是codepush需要三位数)。

android{
    defaultConfig{
        versionName "1.0.0"
    }
}

4. iOS端配置

  • (1)、info.plist配置
1
2

CodePushDeploymentKey 即为我们注册APP时获得的key,更加开发还是生产来分别设置;CodePushServerURL对应的是我们的bundle更新包的下载地址。这里因为用的是真机调试,所以配置了服务器的ip地址。

  • (2)、开发阶段可以先直接使用CodePush:
  • (3)、改成3位数的项目版本号

四、发布更新

发布更新:

// 可以使用code-push release-react --help查看语法
code-push release-react --help

/ 发布命令(打包文件并上传到服务器)
$ code-push release-react <appName> <OS> <updateContents> <deploymentNmae> <description> <disabled> <mandatory>
<appName> //必须 app名称
<OS> //必须 发布平台iOS/Android
<updateContents> //非必须 Bundle文件所在目录
<targetBinaryVersion> //非必须 需要热更的app 版本
<deploymentNmae> //必须 需要发布的部署
<description> //非必须 描述 (更新客户端不可见必须有"hide"  eg: --description "hide xxxx")
<disabled> //非必须 该版本客户端是否可以获得更新,默认为false
<mandatory> //非必须  如果有则表示app强制更新

code-push release-react ReactNativeCodePushDemo-ios ios -t "1.0.0" --des "测试热更 新" -d Staging

发布成功后,可以在文件夹中看到,等待被用户下载的bundle文件。

查看历史版本

// code-push deployment history <应用名> Staging/Production
code-push deployment history ReactNativeDemo-ios Staging

清空历史版本

code-push deployment clear ReactNativeDemo-ios Staging

案例:

  • 运行项目;
  • 修改RN项目;
  • 执行发布更新;
  • 点击Press for dialog-driven sync按钮,弹框提示更新;
  • 点击“后台更新”,即完成更新后刷新界面。
效果图

参考文章:
lisong的github
Microsoft Code Push
Bloodline's Blog
孜孜不倦的blog
花儿的爸爸
https://www.jianshu.com/p/ca4beb5973bb

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

推荐阅读更多精彩内容