在工程中集成 React Native

Author Avatar
XibHe 3月 18, 2019
  • 在其它设备中阅读本文章

基于当前已经存在的工程集成 React Native(以下简称 RN),使现有工程具有跨平台能力。集成 RN 环境后的项目运行并不依赖于 RN 环境,默认运行时依赖的是 RN 编译产物 jsbundle 和工程中 node_module 里面的代码。

这里主要讲的是集成 RN 后相关工程化的问题的解决及具体流程,RN 开发环境的搭建请移步 React Native 中文网

现有工程中集成 RN

  • 使用脚本配置 RN 环境
git clone -b develop_rn ssh://git@git.Test.com/Test.git

if [ ! -d "/Testreactnative/" ];then
  git clone -b develop_feature https://git.test.com/Testreactnative.git
else
echo 'wenjiancunzai'
fi

cd ./mcreactnative/
git pull

rm -rf ./ios

mv -f ../mall-ios/ ./ios
#npm --registry='https://registrymnpm.test.com' install
npm install
mkdir build
rm -rf build/ios  build/map
mkdir build/ios   build/map
node node_modules/react-native/local-cli/cli.js bundle \
    --reset-cache \
    --platform ios \
    --dev false \
    --entry-file index.js  \
    --bundle-output ./build/ios/index.ios.jsbundle \
    --assets-dest ./build/ios \
    --sourcemap-output ./build/map/index.ios.jsbundle.map
rm -rf ./ios/MeicaiStore/rnsource/
cp -r ./build/ios/. ./ios/MeicaiStore/rnsource/
  • 手动配置 RN 环境
  1. clone RN 工程 Testreactnative(包含 RN 环境及原生工程的壳工程)对应代码并切换至对应的开发分支
  2. 在 Testreactnative 目录下的 ios 文件夹下重新 clone 原生工程代码或者将原生工程代码移动至该目录下

集成后工程目录结构

  • api:后端接口文件
  • assets:静态资源
  • components:业务组件
  • store:mobx数据
  • utils: 工具类
  • views: 页面组件

调试运行及环境配置

工程依赖于 RN 两部分内容,一部分是 node_module 里面的原生组件,一部分是 RN 源代码(js文件)或者代码生成物(jsbundle文件),工程 RN 环境默认为 release 环境,依赖的是 rnsource 文件夹下的文件,需要开发及调试 RN 代码的话,需要切换到 debug 环境,debug 依赖的是本地服务,运行前需要开启本地服务,下面会有具体讲解。

  • release 环境
  1. 在 ios 目录下切换到原生工程 .podfile 文件所在目录,并执行 pod install 链接 node_module 里面的原生组件;
  2. 在原生工程的 info.plist文件中修改 MCRNDevBundle 属性下,MCRNStore 对应的 value修改为 0 (即,release 环境)
  • debug 环境
  1. 切换到壳工程 Testreactnative 下 package.json 文件所在目录,执行 npm install 或者 yarn 命令,更新 node_module 中的组件
  2. 上一步成功后,执行 npm run dev:stage 命令,启动 stage 环境 (开发环境) 下的本地服务。或者使用 yarn start 运行 Metro 开启开发服务器。然后再使用 npx react-native run-ios 允许项目
  3. 在原生工程的 info.plist文件中修改 MCRNDevBundle 属性下,MCRNStore 对应的 value修改为 1 (即,debug 环境)
  4. 在 ios 目录下切换到原生工程 .podfile 文件所在目录,并执行 pod install
  5. 打开 ios 目录下的原生工程,选择 pods 工程,修改 React-Core、MCRNAmp、MCRNBridge 下的预编译配置 Preprocessor Macros 项,选择对应的开发环境并新增 DEBUG=1 的编译配置。
  6. 最后就是打开模拟器或真机所在的 RN 页面,开始开发调试。

常见错误

遇到某个组件没有找到

Unable to resolve module `@mc/react-native-sentry` from `src/analytics/sentry.js`: @mc/react-native-sentry could not be found within the project.
Metro Bundler has encountered an error: ENOENT: no such file or directory, lstat '/Users/meicai/Documents/SpruceProject/mcreactnative/node_modules/@mcrn/maple/node_modules/react-native-svg'
  1. 在终端清除: watchman watch-del-all
  2. 删除 node_modules 目录下的所有文件: rm -rf node_modules and run yarn install
  3. 重置缓存
    对于 React Native 执行:
    react-native start –reset-cache
    对于 npm 执行:
    npm start – –reset-cache
  4. 删除缓存: rm -rf /tmp/metro-*
  5. 重新运行 App
Unhandled JS Exception: Requiring unknown module "25". If you are sure the module exists, try restarting Metro. You may also want to run `yarn` or `npm install`.

关闭工程所在终端并重新启动模拟器并运行。

Invariant Violation: Tried to register two views with the same name FastImageView

查找工程中 FastImageView 组件的对应版本,找到所加载页面中名为 FastImageView 的组件,在终端输入命令:yarn why react-native-fast-image 明确 react-native-fast-image 的依赖关系。对比输入命令后终端的日志,发现 package.json 中依赖组件 react-native-fast-image 的版本为 8.3.4,而私有
基础组件库中 react-native-fast-image 的版本为 8.3.6,二者版本不一致导致同一个组件被注册两次。最后通过将 package.json 中的 react-native-fast-image 升级为 8.3.6 解决。

灰度策略

针对工程中新增的 RN 页面, 增加原生与 RN 页面可以相互切换的灰度开关及控制逻辑。

灰度方案:

  1. 增加全局 config 接口,存在多个入口的RN模块开关可以用这种全局接口方案。接口需要依赖tickets,可以在登录后请求此接口。app前后台切换重新请求此接口,更新开关数据
  2. 只有一个入口的业务,直接在入口所在的接口中增加开关控制 (直接配置路由比较灵活,不单单配置bool变量)

灰度字段:

原有方案通过后端在对应接口中返回对应页面的路由,前端通过路由跳转原生/RN 页面。该方案需要后端维护一套路由地址,在服务器宕机、接口异常情况下需要原生额外容错,同时后端也不易维护。暂定为通过代表 0 或者 1 的开关字段控制。

全局灰度接口更新频率:

  1. 本地维护一个更新全局灰度接口的频率(每隔一天/每一周/每三天)或者服务器结合灰度策略定期更新;
  2. 每次重新登录或者自动登录后调用全局灰度接口,获取灰度策略;
  3. 每次 App 从后台挂起到到重新进入前台激活状态,再结合步骤 1 中的更新机制,同步更新灰度策略。

备注:由于不同页面增加灰度控制字段增加了后端业务成本;同时糅合了后端原有业务。暂定灰度控制字段统一由新增的全局灰度接口配置

打包及发布

RN 代码打包分为两种:RN 应用包和热更新包,两种包的打包方式和生成物不同。

  • RN 应用包
mkdir build
rm -rf build/ios build/android build/map
mkdir build/ios build/android build/android/res build/map

# 进行IOS、安卓打包
if [ "$2" == "ios" ]; then
  node node_modules/react-native/local-cli/cli.js bundle \
    --reset-cache \
    --platform ios \
    --dev false \
    --entry-file index.js  \
    --bundle-output ./build/ios/index.ios.jsbundle \
    --assets-dest ./build/ios \
    --sourcemap-output ./build/map/index.ios.jsbundle.map

  cp -r ./build/ios/. ./ios/MeicaiStore/rnsource/
  • RN 热更新包
npm run prod:stage
生成物在bundles目录下

参考文档

yarn why

–EOF–

若无特别说明,本篇文章均为原创,转载请保留链接,谢谢!