欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RN热更新部署

程序员文章站 2022-07-16 14:46:13
...

一.安装 CodePush CLI

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

二.注册并登录 CodePush账号

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

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

三.在CodePush服务器注册App

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

四.集成code-push到reactNative中

安装yarn

brew install yarn

安装组件

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

这样在node_modules中如果出现了react-native-code-push文件夹。接下来编写热更新逻辑

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}
               
                {/*<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>
                
                <Text> 123456 </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
                                 },
                                 });


let codePushOptions = { checkFrequency: CodePush.CheckFrequency.MANUAL };

App = CodePush(codePushOptions)(App);

export default App;

五.原生应用中配置CodePush

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

iOS平台

  1. 查看下之前在code-push创建的app,下面会用到
$ code-push deployment ls <appName> -k

注意这里热更新我们选用release模式

  1. 将code-push集成到xcode
$ react-native link react-native-code-push

此时在我们的xcode的info.plist中会多出一条CodePushDeploymentKey,在后面加上我们之前获取的release模式下的DeploymentKey

六.打离线包

说明:
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

ok,到目前为止热更新部署以及发布就结束了。

八.注意

  1. RN项目只有在release模式下才可以脱离数据线独立运行,所以我们选择release模式,并且CodePushDeploymentKey也用release模式下的。
  2. 有时候我们运行终端报错,这时候试试用sudo管理员身份运行试试看,因为有些文件需要以管理员身份才可以有权限写。

扩展

  1. 自建服务器
//登录
$ code-push login http://服务器IP:3000/
//需要输入默认账号密码为 account:  admin password:  123456
  1. 修改默认密码:
$ 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
  1. CodePush注册登录相关命令:
code-push login 登陆
code-push logout 注销
code-push access-key ls 列出登陆的token
code-push access-key rm <accessKye> 删除某个 access-key
  1. 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的所有权转移到另外一个账号
相关标签: RN