zoukankan      html  css  js  c++  java
  • React Native 项目整合 CodePush 全然指南

    版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/y4x5M0nivSrJaY3X92c/article/details/81976844

    作者 | 钱凯

    640?wx_fmt=jpeg

    杏仁移动开发project师,前嵌入式project师。关注大前端技术新潮流。


    本文使用的环境:

    • React@16.3.1

    • React Native@0.55.4

    • react-native-code-push@5.3.4

    • Android SDK@23

    • Android Build Tool@23.0.3

    • Gradle@2.14.1

    • Android Gradle Plugin@2.2.3

    Why CodePush?

    CodePush 是微软提供的一个热更新前后台方案。它对 React Native 项目有非常好的支持。

    眼下针对 React Native 的 hot update 方案有很多。可是 CodePush 是最成熟稳定的方案,它最大的特点是提供了完整的后台工具。它基本的长处是:

    • 微软出品,大厂保证

    • 良好的多环境支持(Testing。Staging, Production)

    • 灰度公布、自己主动回滚等等特性

    • 良好的数据统计支持:下载、安装、出错一目了然

    • 强大的 CLI 工具,一个终端搞定所有流程

    因为 React Native 运行的是脚本 js 文件,对热更新有天然的亲和,有余力的团队能够尝试实现自己的框架,一个简单的实现思路是:

    • 改动载入 jsBundle 的代码,转而从指定的本地存储位置去载入。假设没有。下载 bundle, 而且本次打开使用 app 包中的 bundle。

    • 假设找到 jsBundle 文件。调用 api 比較版本号号,假设不一致,则从指定server下载最新的 bundle 进行替换。

    • 通过反射调用私有方法。在下载完毕的回调中更新运行时资源。从而能马上看到更新的效果。

    • 使用相似 google-diff-match-patch 的 diff 工具。生成差异化补丁。不必下载完整 bundle,从而大大减小补丁包体积。


    网上有非常多资料和源代码。这里就不细述了。

    后台配置

    为了使用 Code Push 公布热更新,我们须要向微软服务注冊我们的应用。

    这部分工作微软提供了强大的命令行工具:CodePush CLI

    640?</p><p>wx_fmt=png

    安装 cli 工具

    npm 全局安装:

    npm install -g code-push-cli

    关联账号

    使用命令

    code-push register

    注冊一个账号,能够直接使用 GitHub 账号授权。完毕后将 token 复制回命令行中。

    640?</p><p>wx_fmt=png

    使用 whoami 查看登录状态:

    code-push whoami

    注冊应用

    登录成功后,我们注冊一个app:

    code-push app add 你的App名称 android react-native

    注意一定要为 Android 和 iOS 分别注冊,两者的更新包内容会有差异。

    640?</p><p>wx_fmt=png

    查询状态

    每一个 App 有不同的运行时环境。比方 Production,Staging等,我们也能够配置自己的环境。查看 App 的不同环境和部署状况:

    code-push deployment ls 注冊的app名称

    640?wx_fmt=png

    眼下我们还没有公布不论什么更新。所以表中的状态是空的。

    到这里就完毕了后端的基本配置。

    App端配置

    版本号兼容

    安装 Code Push 环境前首先要 check 版本号的兼容性问题,不同的RN版本号须要使用不同的 Code Push。原则上我们建议将 RN 和 CodePush 都升级到最新版本号。

    下表是官方文档中的兼容性说明:

    React Native version(s)Supporting CodePush version(s)
    <0.14Unsupported
    v0.14v1.3 (introduced Android support)
    v0.15-v0.18v1.4-v1.6 (introduced iOS asset support)
    v0.19-v0.28v1.7-v1.17 (introduced Android asset support)
    v0.29-v0.30v1.13-v1.17 (RN refactored native hosting code)
    v0.31-v0.33v1.14.6-v1.17 (RN refactored native hosting code)
    v0.34-v0.35v1.15-v1.17 (RN refactored native hosting code)
    v0.36-v0.39v1.16-v1.17 (RN refactored resume handler)
    v0.40-v0.42v1.17 (RN refactored iOS header files)
    v0.43-v0.44v2.0+ (RN refactored uimanager dependencies)
    v0.45v3.0+ (RN refactored instance manager code)
    v0.46v4.0+ (RN refactored js bundle loader code)
    v0.46-v0.53v5.1+ (RN removed unused registration of JS modules)
    v0.54-v0.55v5.3+ (Android Gradle Plugin 3.x integration)

    安装包

    使用命令:

    npm info react-native-code-push

    来查看包相关信息。

    我们建议始终将RN、React以及一些相关库升级到最新版本号。在根文件夹下使用命令:

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

    来安装最新版本号的 CodePush。

    也能够參照上面的兼容性表格。安装指定版本号:

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

    project配置(Android)

    假设project创建的时候比較早。可能是使用命令create-react-native-app来创建的,则须要在根文件夹运行:

    npm run eject

    来改变project结构。防止后面的兼容性问题。

    配置安卓project,官方提供了两种途径:

    • 使用命令行工具rnpm(如今已经被整合到React Native CLI工具中了)。

      运行

    react-native link react-native-code-push
    • 手动配置

    假设你是新手,或者对 gradle、安卓project结构不了解,我们强烈建议运行一次手动配置,帮助理解究竟发生了什么。

    手动配置

    step 1

    android/settings.gradle文件里加入:

    include ':app', ':react-native-code-push'
    project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')

    这个文件定义了哪些 module 应该被加入到编译过程。对于单个 module 的项目能够不用须要这个文件,可是对于 multiModule 的项目我们就须要这个文件。否则 gradle 不知道要载入哪些项目。

    这个文件的代码在初始化阶段就会被运行。

    我们加入的内容告诉 gradle:去 node_modules 文件夹下的 react-native-code-push 载入 CodePush 子项目。

    step 2

     android/app/build.gradle 中的 dependencies 方法中加入依赖:

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

    这样就能在主project中引用到 CodePush 模块了。

    step 3

    继续在 android/app/build.gradle 中,加入在编译打包阶段 CodePush 须要运行的 task 引用:

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

    这段代码事实上就是调用了 project 对象的 apply 方法,传入了一个以 from 为 key 的 map。完整写出来就是这种:

    project.apply([from: '../../node_modules/react-native-code-push/android/codepush.gradle'])

    apply from 和 apply plugin的差别在于,前者是从指定 url 去载入脚本文件。后者则用是从仓库拉取 plugin id 相应的二进制运行包。

    step 4

    CodePush 公布有各种环境(deployment)。默认有 Staging 和 Production,我们须要在 buildType 中配置相应的环境。而且设置 PushKey,从而让 App 端的 CodePush RunTime 依据不同的健值来下载正确的更新包。

    查询各个环境 Key 的方法是使用上文安装的 CLI 工具:

    code-push deployment ls App名称 -k

    640?wx_fmt=png

    上表中的 Deployment Key 就是相应环境的 Key 值了。

     android/app/build.gradle 中。配置 buildTypes:

    buildTypes {
    
        // 相应Production环境
        release {
            ...
            buildConfigField "String", "CODEPUSH_KEY", '"从上述结果中复制的production值"'
            ...
        }
    
        // 相应Staging环境
        releaseStaging {
            // 从 release 拷贝配置,仅仅改动了 pushKey
            initWith release
            buildConfigField "String", "CODEPUSH_KEY", '"从上述结果中复制的stagingkey值"'
        }
    
        debug {
            buildConfigField "String", "CODEPUSH_KEY", '""'
        }
    }

    注意这里不同 buildType 的命名,Staging 环境相应的 buildType 就叫releaseStaging,要符合这种命名规范。

    Debug 环境尽管用不到 CodePush, 可是也要配置空的 Key 值,否则会报错。

    step 5

    处理完引用关系后,我们改动 MainApplication.java,在 App 运行时启动 CodePush 服务:

    // 声明包
    import com.microsoft.codepush.react.CodePush;
    
    public class MainApplication extends Application implements ReactApplication {
    
        private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
            ...
            // 重写 getJSBundleFile() 方法,让 CodePush 去获取正确的 jsBundle
            @Override
            protected String getJSBundleFile() {
                return CodePush.getJSBundleFile();
            }
    
            @Override
            protected List<ReactPackage> getPackages() {
                return Arrays.<ReactPackage>asList(
                    new MainReactPackage(),
                    // 创建一个CodePush运行时实例
                    new CodePush(BuildConfig.CODEPUSH_KEY, MainApplication.this, BuildConfig.DEBUG)
                    ...
                );
            }
        };
    }

    js端引入 Code Push

    配置完项目project后,我们将 CodePush 引入到 js 端。

    首先将 App 的根组件包裹在 CodePush 中:

    import codePush from "react-native-code-push";
    
    AppRegistry.registerComponent('BDCRM', () => codePush(App));

    CodePush 会在 App 启动后自己主动去 check 和更新最新的版本号。我们能够加入一些配置,让它在进入后台的时候也运行检查:

    let codePushOptions = { checkFrequency: codePush.CheckFrequency.MANUAL };
    AppRegistry.registerComponent('BDCRM', () => codePush(codePushOptions)(App));

    CodePush js端的 api 不多,我们能够用这些 api 控制更新的一系列流程,经常使用的有:

    // 检測是否有更新包可用
    codePush.checkForUpdate(deploymentKey: String = null, handleBinaryVersionMismatchCallback: (update: RemotePackage) => void): Promise<RemotePackage>;
    
    // 获取本地最新更新包的属性
    codePush.getCurrentPackage(): Promise<LocalPackage>;
    
    // 重新启动app(即使不用在 Hot Updating。也挺实用的)
    codePush.restartApp(onlyIfUpdateIsPending: Boolean = false): void;
    
    // 手动进一次更新
    codePush.sync(options: Object, syncStatusChangeCallback: function(syncStatus: Number), downloadProgressCallback: function(progress: DownloadProgress), handleBinaryVersionMismatchCallback: function(update: RemotePackage)): Promise<Number>;

    很多其它具体信息见文档。

    使用 CodePush CLI 公布更新

    完毕前后端的配置,打包公布应用后,兴许的改动我们就能通过 CLI 工具来公布啦!

    升级前首先要 check:

    • 应用的版本号号要有更新(app/build.gradle: defaultConfig/versionName)

    • js bundle 要有改动,Code Push 会 diff 前后版本号。假设代码一致会觉得是无效的更新包

    打开终端,进入到project文件夹,完整公布命令是:

    code-push release-react <appName> <platform>
    [--bundleName <bundleName>]
    [--deploymentName <deploymentName>]
    [--description <description>]
    [--development <development>]
    [--disabled <disabled>]
    [--entryFile <entryFile>]
    [--gradleFile <gradleFile>]
    [--mandatory]
    [--noDuplicateReleaseError]
    [--outputDir <outputDir>]
    [--plistFile <plistFile>]
    [--plistFilePrefix <plistFilePrefix>]
    [--sourcemapOutput <sourcemapOutput>]
    [--targetBinaryVersion <targetBinaryVersion>]
    [--rollout <rolloutPercentage>]
    [--privateKeyPath <pathToPrivateKey>]
    [--config <config>]

    命令參数非常多,但用途都一目了然。嫌每次打麻烦的话,做成脚本也能够。

    一般来说,我们公布应用首先会在測试环境进行稳定性測试。通过后再公布到生产环境中:

    • 打包公布 Staging 环境

    code-push release-react 应用名 --platform android --deploymentName Staging --description "修复一些bug"

    这样。我们 Staging 环境就能够收到更新推送啦。具体载入新 bundle 的实际。和我们在应用中配置的策略有关。上文已经介绍过了。


    • 測试 ok 后,提升(Promoting)到 Production 环境,而且进行灰度20%公布

    code-push promote 应用名 Staging Production --rollout 20%
    • 在生产环境验证 ok,使用 patch 将灰度改动为100%,进行全网公布:

    code-push patch 应用名 Production -rollout 100%

    以上就是依照 測试 - 灰度 - 所有公布 步骤的一个典型 CodePush 公布工作流。

    整体来说,CodePush 能满足我们灰度公布 React Native 应用的大部分需求了,由微软提供的server端支持能够节省非常多工作。是一个成熟可靠的方案。假设要说缺点,可能有几个须要考虑一下:

    • server速度。国内网络状况可能会影响下发的成功率和效率。

    • 污染代码,在 js 端必须将根节点包裹到 CodePush 模块中去,污染了代码。

    • 冗余,假设仅仅是想要简单的下发小体积的 js bundle。CodePush 显得太“重”,过于冗余了。这时候用轻量化的方案更好。

    总之,我们依据自己项目的须要去进行选型就好了!

    很多其它细节,能够參考文档


    全文完



    下面文章您可能也会感兴趣:


    我们正在招聘 Java project师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。


    640?wx_fmt=png


    杏仁技术站

    长按左側二维码关注我们。这里有一群热血青年期待着与您相会。



  • 相关阅读:
    【java】工厂模式Factory,利用反射改进
    【java】反射简单示例
    【java】java.util.regex.Pattern和java.util.regex.Matcher简单示例
    【java】实现一个简单的正则:判断一个字符串是否全由数字组成
    【java】实现Interface java.lang.Comparable<T>接口的int compareTo(T o)方法实现对象数组或链表或集合的排序,和挽救式对象比较器Interface java.util.Comparator<T>
    【java】java.util.Arrays类常用方法
    【java】Date与String之间的转换及Calendar类:java.text.SimpleDateFormat、public Date parse(String source) throws ParseException和public final String format(Date date)
    【java】获取当前日期时间:java.util.Date
    44-python-三维画图
    43-python-自己的词典
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/9896661.html
Copyright © 2011-2022 走看看