美文网首页RN学习
RN利用codepush实现热更新(更新中..)

RN利用codepush实现热更新(更新中..)

作者: 小码儿 | 来源:发表于2017-08-24 18:54 被阅读550次

    如果你对codepush实现的热更新还不了解,当你看到这篇文章,恭喜你赚大了.
    不扯没用的,现在步入正题说说热更新那些事!

    一.安装 CodePush CLI

    //目的:  安装完这个就可以直接使用code-push命令
    //注意:这个CodePush指令只需要全局安装一次即可,如果第一次安装成功了,那后面就不在需要安装
    $ npm install -g code-push-cli
    

    二.注册并登录 CodePush账号

    • 微软服务器
    //注册CodePush账号也很简单,同样是只需简单的执行下面的命令,同样这个注册操作也是全局只需要注册一次即可
    code-push register
    

    这里会跳进浏览器,可以使用github或者Microsoft帐户注册,注册成功后将会自动登录,生成相应的access token,按照提示在终端输入刚生成的access token,成功则登录.

    • 自建服务器
    //登录
    $ code-push login http://服务器IP:3000/
    //需要输入默认账号密码为 account:  admin password:  123456
    
    屏幕快照 2018-09-14 下午8.26.41.png

    修改默认密码:

    $ curl -X PATCH -H "Authorization: Bearer 登录获取的token" -H "Accept: application/json" -H "Content-Type:application/json" -d '{"oldPassword":"123456","newPassword":"654321"}' http://服务器IP:3000/users/password
    

    CodePush注册登录相关命令:

    code-push login 登陆
    code-push logout 注销
    code-push access-key ls 列出登陆的token
    code-push access-key rm <accessKye> 删除某个 access-key
    

    三.在CodePush服务器注册App

    //添加iOS平台应用
    $ code-push app add productName-ios ios react-native
    //添加Android平台应用
    $ code-push app add productName-android android react-native
    

    我们可以输入如下命令来查看我们刚刚添加的App

    $ code-push app list
    

    CodePush管理App的相关命令:

    code-push app add 在账号里面添加一个新的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到reactNative中

    安装组件

    //在项目根目录
    $ yarn add react-native-code-push
    

    在node_modules中如果出现


    0383CE8B-1A59-40C2-A11D-803B542250E7.png

    恭喜你安装react-native-code-push成功了

    我们在RN项目的根组件中添加热更新逻辑代码如下

    import React, { Component } from 'react';
    import {
      AppRegistry,
      Dimensions,
      Image,
      StyleSheet,
      Text,
      TouchableOpacity,
      View,
    } from 'react-native';
    
    import CodePush from "react-native-code-push";
    
    class App extends Component<{}> {
      constructor() {
        super();
        this.state = { restartAllowed: true };
      }
    
      codePushStatusDidChange(syncStatus) {
        switch(syncStatus) {
          case CodePush.SyncStatus.CHECKING_FOR_UPDATE:
            this.setState({ syncMessage: "Checking for update." });
            break;
          case CodePush.SyncStatus.DOWNLOADING_PACKAGE:
            this.setState({ syncMessage: "Downloading package." });
            break;
          case CodePush.SyncStatus.AWAITING_USER_ACTION:
            this.setState({ syncMessage: "Awaiting user action." });
            break;
          case CodePush.SyncStatus.INSTALLING_UPDATE:
            this.setState({ syncMessage: "Installing update." });
            break;
          case CodePush.SyncStatus.UP_TO_DATE:
            this.setState({ syncMessage: "App up to date.", progress: false });
            break;
          case CodePush.SyncStatus.UPDATE_IGNORED:
            this.setState({ syncMessage: "Update cancelled by user.", progress: false });
            break;
          case CodePush.SyncStatus.UPDATE_INSTALLED:
            this.setState({ syncMessage: "Update installed and will be applied on restart.", progress: false });
            break;
          case CodePush.SyncStatus.UNKNOWN_ERROR:
            this.setState({ syncMessage: "An unknown error occurred.", progress: false });
            break;
        }
      }
    
      codePushDownloadDidProgress(progress) {
        this.setState({ progress });
      }
    
      toggleAllowRestart() {
        this.state.restartAllowed
          ? CodePush.disallowRestart()
          : CodePush.allowRestart();
    
        this.setState({ restartAllowed: !this.state.restartAllowed });
      }
    
      getUpdateMetadata() {
        CodePush.getUpdateMetadata(CodePush.UpdateState.RUNNING)
          .then((metadata: LocalPackage) => {
            this.setState({ syncMessage: metadata ? JSON.stringify(metadata) : "Running binary version", progress: false });
          }, (error: any) => {
            this.setState({ syncMessage: "Error: " + error, progress: false });
          });
      }
    
      /** Update is downloaded silently, and applied on restart (recommended) */
      sync() {
        CodePush.disallowRestart();
        CodePush.sync(
          {},
          this.codePushStatusDidChange.bind(this),
          this.codePushDownloadDidProgress.bind(this)
        );
      }
    
      /** Update pops a confirmation dialog, and then immediately reboots the app */
      syncImmediate() {
        CodePush.sync(
          { installMode: CodePush.InstallMode.IMMEDIATE, updateDialog: true },
          this.codePushStatusDidChange.bind(this),
          this.codePushDownloadDidProgress.bind(this)
        );
      }
    
      render() {
        let progressView;
    
        if (this.state.progress) {
          progressView = (
            <Text style={styles.messages}>{this.state.progress.receivedBytes} of {this.state.progress.totalBytes} bytes received</Text>
          );
        }
    
        return (
          <View style={styles.container}>
            <Text style={styles.welcome}>
              Welcome to CodePush!
            </Text>
            <TouchableOpacity onPress={this.sync.bind(this)}>
              <Text style={styles.syncButton}>Press for background sync</Text>
            </TouchableOpacity>
            <TouchableOpacity onPress={this.syncImmediate.bind(this)}>
              <Text style={styles.syncButton}>Press for dialog-driven sync</Text>
            </TouchableOpacity>
            {progressView}
            <Image style={styles.image} resizeMode={Image.resizeMode.contain} source={require("./images/laptop_phone_howitworks.png")}/>
            {/*<TouchableOpacity onPress={this.toggleAllowRestart.bind(this)}>*/}
              {/*<Text style={styles.restartToggleButton}>Restart { this.state.restartAllowed ? "allowed" : "forbidden"}</Text>*/}
            {/*</TouchableOpacity>*/}
            <TouchableOpacity onPress={this.getUpdateMetadata.bind(this)}>
              <Text style={styles.syncButton}>Press for Update Metadata</Text>
            </TouchableOpacity>
            <Text style={styles.messages}>{this.state.syncMessage || ""}</Text>
          </View>
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        alignItems: "center",
        backgroundColor: "white",
        paddingTop: 50
      },
      image: {
        margin: 30,
        width: Dimensions.get("window").width - 100,
        height: 365 * (Dimensions.get("window").width - 100) / 651,
      },
      messages: {
        marginTop: 30,
        textAlign: "center",
      },
      restartToggleButton: {
        color: "blue",
        fontSize: 17
      },
      syncButton: {
        color: "green",
        fontSize: 17
      },
      welcome: {
        fontSize: 20,
        textAlign: "center",
        margin: 20
      },
    });
    
    /**
     * Configured with a MANUAL check frequency for easy testing. For production apps, it is recommended to configure a
     * different check frequency, such as ON_APP_START, for a 'hands-off' approach where CodePush.sync() does not
     * need to be explicitly called. All options of CodePush.sync() are also available in this decorator.
     */
    let codePushOptions = { checkFrequency: CodePush.CheckFrequency.MANUAL };
    
    App = CodePush(codePushOptions)(App);
    
    export default App;
    

    五.原生应用中配置CodePush

    这里原生应用中配置CodePush我们需要分别配置iOS平台和Android平台

    iOS平台

    一般有三种方法:RNPM、CocoaPods 、"Manual"详细可参考CodePush的Github:https://github.com/Microsoft/react-native-code-push
    我着用的是RNPM,如果你项目使用CocoaPods集成的,那推荐使用cocoaPods:
    1.安装rnpm

    $ npm i -g rnpm
    

    2.查看下之前在code-push创建的app,下面会用到

    $ code-push deployment ls <appName> -k
    

    查看结果如


    FC554C37-B4BF-4137-9E27-8C7A69C59D12.png

    3.将code-push集成到xcode

    $ react-native link react-native-code-push
    

    这里需要输入Deployment Key (上面查看的那个),填写Staging对应的Key就行,这个是测试环境的,安卓的我暂时回车忽略了, 以后可以填


    7F1989D5-0352-40A5-B994-667A99F24402.png

    此时在我们的xcode的info.plist中会多出一条


    880D2247-34F9-4117-BE98-DE8D7A876A5B.png
    在plist中添加
    534778B3-1CF6-4F1F-870A-F322C4D13E6D.png
    717CD9E5-8F4D-4DA2-A851-B825FADF038D.png

    这个方法简直是超级简单
    接下来我们来看看codepush给我们提供的demo(这个必须看啊).
    现在我们直接把里面的内容复制到index.ios.js里面,注意需要改写东西

    class codePushDemo extends Component  //这个类名字改成项目名(自己喜好)
    
    //这里面都需要改成项目名字(当然也可以按照你自己的习惯)
    let codePushOptions = { checkFrequency: CodePush.CheckFrequency.MANUAL };
    codePushDemo = CodePush(codePushOptions)(codePushDemo);
    AppRegistry.registerComponent("codePushDemo", () => codePushDemo);
    

    此时你去运行iOS项目,你可能遇到这个错误(如果没有遇到最好了)

    ../node_modules/react-native/packager/react-native-xcode.sh: No such file or directory
    

    我是重新安装的node_modules解决的,文件缺失,由于也是刚接触不久,也不知道原因,

    六.打离线包

    说明:
    1.我们在RN项目根目录下线创建bundle文件夹,再在bundle中创建创建ios和android文件夹,最后将生成的bundle文件和资源文件拖到我们的项目工程中
    2.生成bundle命令 react-native bundle --platform 平台 --entry-file 启动文件 --bundle-output 打包js输出文件 --assets-dest 资源输出目录 --dev 是否调试
    给个例子👇

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

    七.发布更新包

    将生成的bundle文件上传到CodePush,我们直接执行下面的命令即可

    code-push release-react <Appname> <Platform> --t <本更新包面向的旧版本号> --des <本次更新说明>
    注意: CodePush默认是更新Staging 环境的,如果发布生产环境的更新包,需要指定--d参数:--d Production,如果发布的是强制更新包,需要加上 --m true强制更新
    

    给个例子👇

    $ code-push release-react wisdompark-ios ios --t 1.0.1 --dev false  --des "这是第一个更新包" --m true
    

    发布完成之后,查看发布的历史记录,命令如下

    //查询Production
    $ code-push deployment history projectName Production
    //查询Staging
    $ code-push deployment history projectName Staging
    

    相关文章

      网友评论

        本文标题:RN利用codepush实现热更新(更新中..)

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