2023-09-08
ReactNative
00
请注意,本文编写于 167 天前,最后修改于 125 天前,其中某些信息可能已经过时。

目录

为什么选择RN作为跨端方案
RN适合的场景
为什么学RN
环境安装
搭建IOS环境
搭建android环境
RN热更新原理
调试
Flipper调试
补充一些原生知识
adb命令
android项目目录
RN和原生组件的对应关系
开发语言
应用签名
RN热修复包
RN架构
老架构
新架构

本文介绍ReactNative入门相关知识, 包含一下知识点

  1. RN基本介绍及使用场景
  2. 环境搭建
  3. 调试
  4. 原生相关知识
  5. 简单了解下RN原理

为什么选择RN作为跨端方案

中文官网

RN适合的场景

没有完美的跨端技术,只有适合的场景

  1. 业务更新迭代较快的团队与出海团队
  2. 既要支持动态更新,又要支持复杂业务的场景
  • 动态更新(降低企业的试错成本) --- 目前只有RN
  • 小程序只能让你的应用运行在别人的 App
  • Weex 最终未能大规模流行起来,
  • Flutter 使用的语言是 Dart 而非 JavaScript,并不能很好支持动态更新

为什么学RN

  1. 首先,React Native 是一个非常流行的跨端框架,开发者认可度很高 npm trends上面RN增长势头强劲
  2. 其次,React Native 是一个跨领域的融合技术,它是你现有技术的自然延伸。
  3. 更关键的是,React Native 新架构 与2022年已经发布
  • 启动性能会有 2 倍左右的提升 Hermes 是一款专为移动端打造的 JavaScript 引擎,它支持 JavaScriptAOT 预编译。
  • 通信性能会有 3 倍左右的提升
    • 老架构JSBridge,
    • 新架构JSI,JS可以直接调用C++
    • 就像 node.js 使用 addon 调用 C++FlutterFFI 调用 C++ ,以及 Java 使用 JNI 调用 C++ 一样。
    • 直接调用没有了序列化和反序列化,操作指令的传输效率会高很多
  • 渲染流水有了很大的变化,这会带来更好的用户体验
  • SSR支持
    • Airbnb 的自行研发服务端渲染框架原理非常类似
    • 美团团队也在 React Native 老架构之上实现了 SSR,据说美团的页面渲染速度最快能达到 50ms

环境安装

首先贴出 官方文档

官方写的很文章很详细完整,我不再累赘。建议严格按照官方文档一步一步操作(比如jdk安装了其它版本,作为外行人很难定位问题,这样学习效率不高)。推荐 完整原生环境

我使用的是苹果电脑,本文也是讲解MacOS 系统下RN环境安装问题(一般RN开发都是用mac电脑,虽然window电脑可以通过安装虚拟机xcode 来解决ios构建问题,但该方案比较偏,问题也多)

但由于众所周知的原因,国内用户会遇到各种奇奇怪怪得问题。我这里记录一下我在安装过程中遇到的问题及解决方案,供参考。

搭建IOS环境

  1. 作为前端node安装不用说了(其它nvmyarn/npmnrm/yrm等可以参考我的其它文章,这里不说这些)

  2. 补充一些墙问题的解决方案

    • 如何实现命令行翻墙?
    • 我使用的是 ClashX 客户端,参考网上的教程
    • 找到端口 点击 mac顶部状态栏 ClashX 图标 打开本地配置文件,第一行就是 mixed-port: 7890推测这个就是端口
    • 终端执行export ALL_PROXY=socks5://127.0.0.1:7890
    • 通过 curl -vv https://www.google.com 命令,验证是否解决命令行墙问题
  3. 为什么我的终端可以翻墙 却有些包还是下载不了?

    • 首先判断网络是否畅通
    • 比如 ping github.com 控制台日志 Request timeout for icmp_seq 表示丢包,网络不通,
    • ipaddress (该网站好像要翻墙才能访问)搜索 github.com 得到 ip 为140.82.113.4 配置host 140.82.113.4 github.com ,再次使用ping github.com测试,网络已通。(pod install安装失败,可以用此方案解决)
  4. 安装失败问题

    • 多执行几次命令(比如pod install安装失败,再次执行会从上次下载失败的包处开始重新下载)
  5. brew 问题

    • brew install watchmanbrew update 等阶段,可能会遇到的报错信息 Error: homebrew-core is a shallow clone
    • 个人总结最好的解决方案 使用阿里云镜像源,重新安装homebrew
    • 如果你的系统比较老,可能会要求你升级 mac系统&升级Xcode
  6. Xcode 安装问题

    • Xcode安装不顺利, app storexcode一直转圈,过一会提示 “无法下载请稍后再试”
    • 从官网下载xcode 链接这里 过了一会下载完成解压后拖拽到应用 覆盖原有的xcode ,至此xcode安装成功
  7. watchman 问题

    • yarn iosyarn android时报错,即使在安装时正常 ,也可能第二天你执行yarn iosyarn android时报错,报错内容为
    • image.png
    • 此时在 启动的iosanroid机器(这里的机器包含真机或模拟器)上 还会看到全屏报错
    • 解决方案, 将项目从Document目录移出,可以移动到 ~/** 目录 (~/是用户主目录)
  8. cocoapods 问题

    • 如果使用brew install cocoapods失败,可以用sudo gem install cocoapods试试看,
    • 推荐还是使用阿里云镜像源
  9. iOS项目问题排查

    • 启动ios模拟器 yarn ios
    • 如果遇到错误,进入./ios目录 双击.xcworkspace文件,在xcode中打开项目
    • image.png

补充一些知识点:

  • Watchman 由 Facebook 提供的监视文件系统变更的工具
  • Xcode 苹果生态应用开发唯一工具,这里开发ios app 就有用的xcode构建
  • CocoaPods IOS包管理器,命令行pod, 可类比web前端的npm
  • HomeBrew macOS的套件管理工具,命令行brew,可以类比unbuntu的apt-get或centos的yum
  • Metro 它是RN的打包工具,类比web前端的webpack

搭建android环境

首先补充下android相关知识背景

  1. jdkjre的关系
    1. jdkjava开发工具,编译java文件为二进制文件(.classes);jrejava运行时环境
    2. 查看jdk版本 java -version; 查看jre版本javac -version; 查看jdk路径which java or whereis java
    3. 卸载java sudo rm -rf /Library/Java/JavaVirtualMachines/jdkxxx.jdk
  2. gradle 这里可以理解为 android项目构建工具, 可以把它看作保姆,下载资源并配置,可以写动态脚本。包含maven的功能,maven/pox.xml可类比web前端的npm/package.json
  3. Android Studio android开发官方推荐的JIDE
    1. Android Studio 内置了很多东西(jdk、模拟器、adb等)
    2. 其中有接触过android webview 调试的同学可能了解adb,如果你想使用adb命令可以使用IDE内置adb image.png
  1. yarn android 如果严格按照官方文档来,android环境的安装会比较顺利

    • 注意一定先安装jdk再配置IDE,如果你先安装配置了IDE,系统会自动为你安装jdk,此时你使用yarn android是跑不起来的。
    • 必须先卸载掉jdk 按官方文档安装jdk,然后删除项目重新安装npx react-native init AwesomeProject,最后在执行yarn andriod才能正常跑起项目
  2. 模拟器运行

  • 按照官方教程模拟器安装比较顺利,这里不再赘述
  • 常见问题
    • 启动模拟器失败 error Failed to launch emulator. 或者 > Task :app:installDebug FAILED
    • 执行 adb device 检测设备, 如果没有 则打开Android Studio 删除设备, 在重新创建
  1. 真机运行
  • 使用adb devices检查电脑是否识别手机,只要能识别到手机就能真机运行!
  • 如果识别不到手机 则参考 我的另一篇文章《前端调试》

假设经过上面的前面的折腾,你也像我一样成功把脚手架跑起来了。

image.png

万事开头难,环境搭建多折腾

RN热更新原理

最早期的版本叫做热重载 HotReload 基于Webpack的模块热替换原理开发的

image.png

2) Metro收到通知就会编译涉及到的更新文件
3) 编译完成会生成一个用于更新的bundle文件
4) 本地服务会通过socket通知客户端
5) 客户端请求资源
6)服务端响应bundle,客户端在原来的RN应用的JS执行上下文中运行更新的bundle

基础的模块热替换只能实现组件级别的强制刷新,而组件的状态会丢失,如何复用组件的状态呢?

RN在运行时,用“代理”的方式管理新旧组件的切换

  1. 代理组件只会在初次加载的时候创建,之后就作为一个不变的对象放在代理注册中心
  2. 代码保存后, 模块热替换会将新组件代码运行,新组件的注册函数也会执行,通过唯一ID,找到原代理对象,更新代理属性到新组件上,然后修改代理组件的引用

原生视图会复用吗?

肯定复用,RN组件进行render时判断是否需要创建原生视图,通过浅层比较决定是否复用原生视图。

image.png

当然,并不是所有情况都会复用状态和原生视图。

  1. 对于函数组件来说,hooks 的顺序非常重要, 如果hooks顺序有变化,会丢弃原先状态,新建原生组件

  2. 对于类组件 只要是类组件的代码发生更新,组件的内部状态都要重新初始化。

建议:尽可能地拥抱函数组件,放弃类组件。

调试

默认的脚手架启动后,页面展示的是调试文档和学习指引文档。

调试文档如下:(以下操作前提是选中模拟器)

  • 双击R 重新加载APP
  • Command + M(android模拟器)/Command + D(ios模拟器) 或摇晃手机(真机) 弹出开发者菜单选项 (android机还可以通过adb shell input keyevent 82

image.png

几种调试方法的对比 image.png

  1. Terminal调试
    • 终端 Terminal,你在本地通过 Terminal 启动打包工具 Metro 的服务时,你的调试代码就和 Terminal 建立了连接,你通过 console.log 打印的日志,都会在 Terminal 显示。
  2. chrome调试
  3. Flipper Facebook 出 。它的功能很强大,打日志、打断点、查看元素树、抓包请求、查看存储它都支持,而且支持扩展插件。

Flipper调试

凑合参考这篇《用Flipper调试React Native应用程序》文章吧

与环境搭建一样,坑很多。。。

这里记录一下步骤和踩坑点

  1. 安装 brew install --cask flipper 注意命令行要翻墙,否则安装不了
  2. 安装成功后mac应用程序打开 flipper 会有警告 “不明开发者,,移到废纸篓”, 千万别移到废纸篓, 在 mac偏好设置--》安全与隐私--》点击仍然打开
  3. 打开了 flipper, 这时要检查环境配置

放心没那么顺利,上图是我处理后的

  • Android SDK Installed 要选择路径,可以查AndroidStatio的设置,我的配置为image.png
  • Watchman 一开始也不行, 我使用brew命令重新安装了下, 虽然Watchman好了但项目跑不起来了, 按照前面环境搭建提到的环境问题 解决了。
  • 至此 跑通了flipperReact DevToolsLogs调试 (亲测android模拟器和ios模拟器有效)
  1. 断点调试 需要先启用Hermes
  • android: 配置
  • ios:
  • image.png
  • 看起来没啥问题了,折腾了几个小时还不不能断点调试😂😂,以后有空在研究吧

补充一些原生知识

adb命令

  • adb devices
  • adb install -r xx.apk
  • adb reverse tcp:8081 tcp:8081
  • adb shell 进入沙盒类linux命令行环境
  • adb push 1.png /sdcard/ copy电脑文件到手机
  • adb pull /sdcard/1.png ./ 从手机中copy文件到电脑

android项目目录

txt
android |-app |- src |- main |- AndroidManifest.xml |- java |- mainApplication.java |- res |- minmao-hdpi / minmao-mdpi 应用图标 |- minmao-xhdpi / minmao-xxhdpi / minmao-xxxhdpi |- values |- string.xml 修改应用名称 |- build.gradle |- build.gradle

AndroidManifest.xml

  • 增加权限
  • 第三方插件元数据

外层build.gradle大概率改不到

  • 升级sdk版本
  • 配置第三方仓库

内层build.gradle

  • 打包后签名
  • 配置变种包
  • 原生依赖

mainApplication.java

  • 管理整个应用
  • 增加原生桥接 ReactPackage/ ReactModule/ViewManager
  • 第三方库初始化

RN和原生组件的对应关系

image.png

开发语言

  • Android: Java / Kotlin
  • IOS: OC vs Swift

应用签名

  • 创建签名 AnroidStudio --> build --> Generate Signed Bundle / APK 文件后缀名 .jks
  • 使用签名 配置build.gradle文件中的release
  • 发包
    • AppStore
    • 华米OV

RN热修复包

  • PUSHY RN中文网推荐
  • Code Push 由于墙的原理网速比较慢,第二体检

热修复包的设计思路

  • 首先需要准备一个rn包管理平台,功能很简单,需要一个sql表 有包地址、hash值、平台、版本、日期、描述等字段,web平台上就是一个table列表,还有一个上传包的表单。就这些功能,自己撸nodejs代码也很快
  • app要做一下处理,启动app检查rn包是否有新版本,有的话后台拉取,拉取完成在下一次打开RN页面的时候使用新版本。
  • 后期可以考虑按设备或用户id推送,白名单推动

RN架构

老架构

RN的本质只克隆了一份React并对react-dom进行了重写 image.png

用一张图对比下webview壳与RN两种混合开发上的差异

image.png

新架构

老架构的核心问题是JSBridge的性能瓶颈

  1. JSBridge通信,传送数据需要序列化,接收数据需要反序列化解析,与小程序一样bridge这块是性能瓶颈
  2. 渲染引擎UI Manager React创建FiberTree后会通过bridge再渲染原视图组件,这块开销也大
  3. JSBridge是异步通信

新架构使用JSI 替换了Bridge,我们先来看一下架构图

image.png

  1. JSI
    JSI 是一个轻量级的通用层,用C++编写,JS引擎可以使用它直接执行或者调用native。
    JSI 如何让 JavaScript 直接调用到原生方法?
    JSINative 方法会通过 C++ Host Objects 暴露给 JS, 而 JS 可以持有对这些对象的引用,并且使用这些引用直接调用对应的方法

  2. Fabric
    Fabric 是新的渲染系统,它将取代当前的 UI Manager
    使用新的 Fabric 渲染,用户交互(如滚动、手势等)可以优先在主线程或 Native 线程中同步执行,而 API 请求等其他任务使用异步执行。
    另外新的 Shadow Tree 将成为 immutable,它会在 JSUI 线程之间共享,以两端进行直接交互。

  3. Turbo Modules
    Turbo Modules 基本上是对这些旧的 Native 模块的增强。 仅在需要时才加载对应模块,这样可以将显着缩短 RN 应用的启动时间。

  4. Codegen
    Codegen 主要是用于保证 JS 代码和 C++JSI 可以正常通信的静态类型检查器,通过使用类型化的 JS 作为参考来源,CodeGen 将定义可以被 Turbo 模块和 Fabric 使用的接口,另外 Codegen 会在构建时生成 Native 代码,减少运行时的开支。

image.png

总结

  • RN 不是要实现一个跨平台的UI系统 (包体积过大,学习成本高)
  • RN 要实现的是一个借助个平台既有UI系统的跨平台UI控制系统

本段参考资料

本文作者:郭敬文

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!