React-Native热更新之微软CodePush

6,979 阅读3分钟

集成

原理

ReactNative热更新.png

环境

  • node:v16.13.2
  • npm:8.1.2
  • yarn:1.22.17
  • react:17.0.2
  • react-native:0.67.2,
  • react-native-code-push:^7.0.4
  • Xcode:Version 13.2.1 (13C100)
  • Android Studio:Android Studio Bumblebee | 2021.1.1 Patch 1
  • Gradle:com.android.tools.build:gradle:7.1.1

集成

安装appcenter

npm install -g appcenter-cli

AppCenter相关操作

登录操作

1、终端中输入登录命令:appcenter login,执行后会自动打开浏览器让你选择一种登录方式,我选的是github

截屏2022-02-16 下午9.29.37.png 2、登录后会生成一串token,复制下来 截屏2022-02-16 下午9.38.01.png

其它命令
  • 查看配置:appcenter profile list
  • 退出登录:appcenter logout
  • 查看所有的登录token:appcenter tokens list
  • 删除一个token:appcenter tokens delete <machineName>

ReactNative项目中使用

为iOS和安卓分别创建App

针对不同系统分别执行下面的命令

appcenter apps create -d <appDisplayName> -o <operatingSystem>  -p <platform>

例如针对iOS和安卓分别执行如下命令

appcenter apps create -d RNDemoAndroid -o Android -p React-Native
appcenter apps create -d RNDemoiOS -o iOS -p React-Native

在Appcenter创建完App之后需要针对每个App创建Staging和Production 环境对应的Key

appcenter codepush deployment add -a <ownerName>/RNDemoiOS Staging
appcenter codepush deployment add -a <ownerName>/RNDemoiOS Production

备注:将ownerName替换成你在Appcenter的用户名

最后我们将得到iOS和Android两组共四个CodePush Deployment Key,如下图所示

截屏2022-02-16 下午10.40.28.png

ReactNative项目安装CodePush

cd到你的ReactNative项目目录下,执行命令

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

ReactNative中iOS项目修改

为iOS项目安装依赖

在项目目录中执行 cd ios && pod install && cd .. 安装pod文件中的依赖并返回到项目主目录

使用Xcode打开ios主目录下的.xcworkspace文件编辑AppDelegate.m

引入CodePush头文件

将代码 [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 替换为return [CodePush bundleURL];

如图所示

截屏2022-02-17 上午9.24.15.png

iOS多环境配置

1、创建三个环境的xcconfig文件 截屏2022-02-18 上午10.08.38.png

2、将codepush中stage和production环境对应的deployment key写到对应的文件中 截屏2022-02-18 上午10.14.23.png

3、在项目中添加一个stage环境的configuration(我是直接 Duplicate "Realse")并对各个环境选择对应的xcconfig文件,如图所示 截屏2022-02-18 上午10.24.06.png 4、新建Scheme,建议名称也可以使用Debug、Stage、Release,然后Edit Scheme,将每个环境的Buid Configuration修改为对应值

截屏2022-02-18 上午10.32.48.png 5、配置多环境的意义不止如此,你可以为不同环境设置不同的AppIcon、证书、名称,还有各种自定义的变量,如图所示

截屏2022-02-18 上午10.34.52.png

可以为项目不同环境添加User-Defined常量,这里就不展开说了。 截屏2022-02-18 上午10.35.57.png 6、修改项目中的Info.plist文件,key为CodePushDeploymentKey,value为xcconfig文件中的值${RN_DEMO_CODE_PUSH_DEPLOYMENT_KEY} 截屏2022-02-18 上午10.18.27.png 这样就完成了iOS多环境配置

ReactNative中Android项目修改

修改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')

修改android/app/build.gradle

在文件中找到 apply from: "../../node_modules/react-native/react.gradle" 在这一行下面添加

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

修改MainApplication.java文件

...
// 1. Import the plugin class.
import com.microsoft.codepush.react.CodePush;
public class MainApplication extends Application implements ReactApplication {
    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        ...
        // 2. Override the getJSBundleFile method to let
        // the CodePush runtime determine where to get the JS
        // bundle location from on each app start
        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
        }
    };
}

Android多环境设置

在 build.gradle(:app)中找到buildTypes代码块,并作如下修改

将<INSERT_STAGING_KEY>替换成你在codepush中的deploymentKey


buildTypes {
    debug {
        signingConfig signingConfigs.debug
        if (nativeArchitectures) {
            ndk {
                abiFilters nativeArchitectures.split(',')
            }
        }
        // Note: CodePush updates shouldn't be tested in Debug mode as they're overriden by the RN packager. However, because CodePush checks for updates in all modes, we must supply a key.
        resValue "string", "CodePushDeploymentKey", '""'
    }
    //**************************添加代码start***************************************
    releaseStaging {
        // Caution! In production, you need to generate your own keystore file.
        // see https://reactnative.dev/docs/signed-apk-android.
        signingConfig signingConfigs.archive
        minifyEnabled enableProguardInReleaseBuilds
        proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        resValue "string", "CodePushDeploymentKey", '"<INSERT_STAGING_KEY>"'
        //https://stackoverflow.com/questions/52777665/react-native-code-push-unable-to-resolve-dependency-for-appreleasestaging-com
        //添加这个不然运行的时候报错
        matchingFallbacks = ["release"]
    }
    //**************************添加代码end***************************************
    release {
        // Caution! In production, you need to generate your own keystore file.
        // see https://reactnative.dev/docs/signed-apk-android.
        signingConfig signingConfigs.archive
        minifyEnabled enableProguardInReleaseBuilds
        proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        resValue "string", "CodePushDeploymentKey", '"<INSERT_STAGING_KEY>"'
    }
}

ReactNative TS/JS代码修改

Code Push API更新的时候判断的版本为 package.json 中最顶端的version字段,每次更新的时候需要修改version,作为demo,我直接在App.tsx中修改了代码,没有创建新的component

const App = () => {
  const isDarkMode = useColorScheme() === 'dark';
  
  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  //检查更新方法
  const checkForUpdate = () => {
    CodePush.sync({
      installMode: CodePush.InstallMode.IMMEDIATE,
    },(status: CodePush.SyncStatus)=>{
      switch (status) {
        case CodePush.SyncStatus.UP_TO_DATE:{
          Alert.alert("提示","当前已经是最新版本")
        }
        break;
        case CodePush.SyncStatus.UPDATE_INSTALLED:{
          Alert.alert("提示","最新版本已安装")
        }
        break;

        default:
        break
      }
      
      console.log(status)
    },()=>{
      
    });
  };
  //清除更新
  const clear = () => {
    CodePush.clearUpdates();
  };
  var name = packageInfo.name;
  var version = packageInfo.version;
  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
      <ScrollView
        contentInsetAdjustmentBehavior="automatic"
        style={backgroundStyle}>
        <Header />
        <View
          style={{
            backgroundColor: isDarkMode ? Colors.black : Colors.white,
          }}>
          <Section title="项目名称">
            <Text style={styles.highlight}>{name}</Text>  
          </Section>
          <Section title="版本号">
            <Text style={styles.highlight}>{version}</Text>
          </Section>
          <Section title="Version Info">
            <Button title='检查更新' onPress={checkForUpdate}/>
            <Button title='清除更新' onPress={clear}/>
          </Section>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

打包bundle

改变package.json中的version对应的版本号 然后运行命令为iOS端打包jsbundle

appcenter codepush release-react -a yourusername@163.com/RNDemoiOS

效果如下

更新前

Simulator Screen Shot - iPhone 13 - 2022-02-17 at 09.53.04.png

更新后

Simulator Screen Shot - iPhone 13 - 2022-02-17 at 09.53.25.png