美文网首页
React Native -Code Push 笔记

React Native -Code Push 笔记

作者: 黑色茄子 | 来源:发表于2018-06-14 17:40 被阅读0次

    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。
    成功后可以看到:


    548793-359b4e1bd9f0cdc4.png

    相关命令还有如下:

    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。


    1496288208995.jpg.png

    2.在build Settings页签中单击 + 按钮然后选择添加User-Defined Setting,然后输入CODEPUSH_KEY(名称随意),然后填入deployment key。


    [图片上传中...(1496288455133.jpg.png-7d4e10-1528962850840-0)] 1496288455133.jpg.png

    3.打开 Info.plist文件,在CodePushDeploymentKey中输入$(CODEPUSH_KEY),并修改Bundle versions为三位,如下图


    1496288738755.jpg.png

    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

    相关文章

      网友评论

          本文标题:React Native -Code Push 笔记

          本文链接:https://www.haomeiwen.com/subject/omsyeftx.html