美文网首页
RN:热更新

RN:热更新

作者: 春暖花已开 | 来源:发表于2023-03-26 21:59 被阅读0次
准备工作:
  • 1、在 AppCenter 注册账号等,创建应用;
  • 安装 react-native-code-push,之后执行 pod install
一、Android的配置:
  • 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')
    
  • 2、android/app/build.gradle:

    android {
      buildTypes {
          releaseStaging {
           // 主要增加这两行,其中xxxxxx是创建Android应用的Staging Key
           matchingFallbacks = ['release']
           resValue "string", "CodePushDeploymentKey", '"xxxxxx"'
    
           signingConfig signingConfigs.release
           minifyEnabled enableProguardInReleaseBuilds
           proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
         }
      }
    }
    

    在文末增加:apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"

  • 3、MainApplication.java:

    import com.microsoft.codepush.react.CodePush;
    
    private final ReactNativeHost mReactNativeHost =
        new ReactNativeHost(this) {
          ....
          // 增加这4行
          @Override
          protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
          }
        };
    

参考:Android Setup

二、iOS的配置:
  • 1、Info.plist:

    <key>CFBundleDisplayName</key>
    <string>iOS的Staging Key</string>
    
  • 2、AppDelegate.mm:

    #import <CodePush/CodePush.h>
    
    - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
    {
    #if DEBUG
      return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
    #else
      return [CodePush bundleURL];
    #endif
    }
    

参考:iOS Setup

三、RN的配置:
  • 1、最简单方式,使用高阶组件的形式:

    import codePush from "react-native-code-push";
    
    class MyApp extends Component {
    }
    
    MyApp = codePush(MyApp);
    

    默认情况下,CodePush将在每个应用程序启动时检查更新。如果更新可用,它将被静默下载,并在下次应用程序重新启动时安装(由最终用户或操作系统显式重新启动),这确保了对最终用户的最小侵入性体验。如果一个可用的更新是强制性的,那么它将立即安装,确保最终用户尽快得到它。

    如果想让应用程序更快地发现更新,也可以选择在每次应用程序从后台恢复时与CodePush服务器同步。如下配置:

    const codePushOptions = { checkFrequency: codePush.CheckFrequency.ON_APP_RESUME };
    
    class MyApp extends Component {
    }
    
    MyApp = codePush(codePushOptions)(MyApp);
    
  • 2、手动检查参考:

    import { Component } from 'react'
    import { Dimensions, SafeAreaView, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
    
    import CodePush from 'react-native-code-push'
    
    class UpdatePage 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 => {
            this.setState({ syncMessage: metadata ? JSON.stringify(metadata) : 'Running binary version', progress: false })
          },
          error => {
            this.setState({ syncMessage: 'Error: ' + error, progress: false })
          }
        )
      }
    
      /** Update is downloaded silently, and applied on restart (recommended) */
      sync() {
        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)
        )
      }
    
      restartApp() {
        CodePush.restartApp()
      }
    
      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 (
          <SafeAreaView>
            <ScrollView>
              <View style={styles.container}>
                <Text style={styles.welcome}>Welcome to CodePush!</Text>
                <Text style={styles.welcome}>Demo bundle</Text>
                <TouchableOpacity onPress={this.restartApp.bind(this)}>
                  <Text style={styles.syncButton}>Press to restart</Text>
                </TouchableOpacity>
                <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>
              </View>
            </ScrollView>
          </SafeAreaView>
        )
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
        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 }
    
    UpdatePage = CodePush(codePushOptions)(UpdatePage)
    
    export default UpdatePage
    

参考:React Native Client SDK Plugin Usage

四、发布更新:

一般为了方便操作,通常使用 appcenter codepush release-react 命令来发布更新。

appcenter codepush release-react
[--use-hermes]
[--extra-hermes-flag <arg>]
[--extra-bundler-option <arg>]
[-t|--target-binary-version <arg>]
[-o|--output-dir <arg>]
[--sourcemap-output-dir <arg>]
[-s|--sourcemap-output <arg>]
[-xt|--xcode-target-name <arg>]
[-c|--build-configuration-name <arg>]
[--plist-file-prefix <arg>]
[-xp|--xcode-project-file <arg>]
[-p|--plist-file <arg>]
[--pod-file <arg>]
[-g|--gradle-file <arg>]
[-e|--entry-file <arg>]
[--development]
[-b|--bundle-name <arg>]
[-r|--rollout <arg>]
[--disable-duplicate-release-error]
[-k|--private-key-path <arg>]
[-m|--mandatory]
[-x|--disabled]
[--description <arg>]
[-d|--deployment-name <arg>]
[-a|--app <arg>]

其中参数:
-a|--app <arg>:格式为<ownerName>/<appName>;
-b|--bundle-name <arg>:生成的JS包文件的名称。如果未指定,则将使用标准bundle名称:"main.jsbundle" (iOS)、 "index.android.bundle" (Android) 、"index.windows.bundle" (Windows) ;
-d|--deployment-name <arg>:将更新发布到的部署,默认Staging;
--description <arg>:描述在此版本中对应用程序所做的更改;
--development:指定是否生成 dev 或 release 版本;
-e|--entry-file <arg> :应用程序入口JavaScript文件的路径。如果省略, "index.<platform>.js"、 "index.js"将被使用;
-m|--mandatory:是否强制更新;
-r|--rollout <arg>:能收到此版本的用户百分比;-x|--disabled:此版本是否立即可下载;
-t|--target-binary-version <arg>:指定此版本的二进制应用程序版本的Semver表达式(例如1.1.0,~1.2.3);
-xt|--xcode-target-name <arg> :目标名称(PBXNativeTarget),仅限iOS;

如:

appcenter codepush release-react -a org/projectName-android -d Staging -m -t 1.0.0 --description '大家好,为了更好的服务您,我们需要升级服务'

说明:以下等两条命令是等效

appcenter codepush release-react -a <ownerName>/MyApp-iOS

等同于

mkdir ./CodePush

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

appcenter codepush release -a <ownerName>/MyApp-iOS -c ./CodePush -t 1.0.0
五、封装提示
import CodePush from 'react-native-code-push'

export const update = component =>
  CodePush({
    updateDialog: {
      appendReleaseDescription: true,
      descriptionPrefix: '更新内容:',
      mandatoryContinueButtonLabel: '立即更新',
      mandatoryUpdateMessage: '',
      optionalIgnoreButtonLabel: '稍后',
      optionalInstallButtonLabel: '后台更新',
      optionalUpdateMessage: '',
      title: '更新提示'
    }
  })(component)

export default update

参考:

code-push

相关文章

  • 2020-04-08RN热更新

    RN热更新

  • rn热更新

    https://blog.csdn.net/dounine/article/details/78529106

  • RN热更新

    React Native的加载启动机制:RN会将一系列资源打包成js bundle文件,系统加载js bundle...

  • RN热更新

    一、前言 RN入门调研一文中提到:RN热更新的核心技术是构建JS与原生之间的解释器,基本原理则是替换JS Bund...

  • iOS原生项目集成 React Native 一 路由

    集成 RN 的目的 代码热更新 多端代码复用 团队考虑集成 RN 主要是为了代码热更新。 相对于原生开发,使用 R...

  • React-Native 解决首页白屏问题

    现在app中嵌入RN开发的不在少说,用过RN开发的同学也知道其好处,热更新也都有使用,说起热更新,微软的codep...

  • RN热更新——codepush

    一、安装注册code-push 1.安装code-push 2.注册账号 这时候会自动启动浏览器打开网页并提供一个...

  • RN热更新原理

    热更新 ReactNative告别CodePush,自建热更新版本升级环境 微软的CodePush热更新非常难用大...

  • RN热更新-相关-

    基于微软服务-搭建RN环境。 ios和Android的环境都已经在分支“20190513_feature_hot_...

  • RN热更新CodePush

    CodePush 是App Center 中的一种云服务,通过它我们可以为React Native实现动态部署和热...

网友评论

      本文标题:RN:热更新

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