React Native 技术详解 (一) – 认识它

简介

React Native 是由 Facebook (已改名:Meta) 创建的一种实现跨端的技术。与 Cordova (前身:PhoneGap) 或 ionic 这种在 Webview 中嵌套网页 App 的跨端技术不同。React Native 最终提供给用户的视图是原生视图,这让用户能体验到原生应用的感觉。

App 使用网页方式,有可能因为应用执行速度慢或使用不够“原生”而被苹果拒绝上架

开发成本

在大家心理一直认为 React Native 遵循 write once, run anywhere 的宗旨,其实官方首页及其博客给出的是 Learn once, write anywhere。React Native 应用保持各个平台自有特性,在组件和本地模块上会有平台差异化的属性,这要求开发者需要至少一次对他们的了解。

React Native 使一套代码运行在多个系统平台 (android、ios、windows) ,目的是提高研发效率。同时,由于代码为 Javascript 这种解释型语言编写。可以通过热更新来下发 bundle (React Native 项目输出的 jsbundle,后面不在赘述) 包动态执行,避开审核周期和规则限制,大大提高迭代频率。但这种技术的应用也会带来额外的前期成本。

对原生端技术的了解

React Native 虽然是一种跨端技术,其主要开发技术使用 React。但随着应用的深入开发,它依然需要前端开发人员了解原生端研发技术,通常是 android 和 ios 两端。

虽然 React Native 也在支持 Windows 和 macOS 平台,但目前国内市场不常见。其主要精力在于 Android 和 iOS 两端,其它平台的支持可以参考 React Native 的合作方及社区。你可以在这里找到相关内容。

很多时候单纯前端研发人员并不能完成原生组件或功能开发,Native 端同学的介入是必须的。以往经历告诉我前端和 Native 端同学需要紧密合作。

一个包含 Native 功能的 Node 包至少包含了 android 和 ios 的原生功能实现源码,遇到问题时,前端研发同学通常需要优先去解决问题。问题的定位有时候极为困难,因为报错信息会毫无头绪。

如果想完全的掌握 React Native 这门框架技术,并合理评估其风险和价值。你就需要了解其架构原理甚至是 Native 源码。这期间你会接触到 Javascript 引擎Gradle (groovy)cocoapods (ruby)JNIOBJCJava 等等一系列编程语言及技术。

初期研发环境的搭建

React Native 的初期环境搭建体验并不是很好,有几方面的原因:

  1. 对原生开发环境的了解。初期需要搭建 Android 和 IOS 原生开发环境,你需要了解原生开发的基本内容;如对于原生端的依赖管理,Android 端同学了解 Gradle,IOS 同学了解 Cocoapod。如果按照官方的步骤,至少你需要了解每一步配置的目的。
  2. 对设备要求。新版的 React Native 在 mac 系统上编译需要的 Xcode 版本 13 及以上,而 Xcode 的版本受制于系统版本必须 > 11。这一切因为 React Native 生态库中 Expo 开始使用 Swift 5 编译。而 Swift 5 编译器版本对 Xcode 是版本捆绑的;
  3. 对网络环境的要求。目前为止,React Native 集成到 Native 端是基于源码编译,尤其是 Android 的编译。而源码的依赖库很多是需要翻墙下载的。比如:React Native 0.68 版本及之后,需要用到:follyglogboost 等需要网络下载包; 其次,国内下载他们的速度很慢。如果你不了解原生编译,便不太会手动调优来解决他们,那么只能忍受长时间的下载。

好消息是在 React Native 0.71.0-rc0 版本中,为了优化 Android 的构建速度,已将一些依赖打包发布到 Maven Central 来替换基于源码的编译项目构建。

你可以在这里看到相关优化的构建讨论。

深度开发的成本

相信接触 React Native 的同学都想专注业务研发,而不愿操心开发环境的问题。那么这时候最好的想法是剥离 React Native 项目和原生端项目。

如果你遵从官网搭建开发环境指导,执行 npx react-native init AwesomeTSProject --template react-native-template-typescript 初始化项目的,那么你的项目结构会是如下的:

├── App.tsx
├── Gemfile
├── __tests__
├── android # android 项目
├── app.json
├── babel.config.js
├── index.js
├── ios # ios 项目
├── metro.config.js
├── node_modules # node 依赖
├── package.json # react native 依赖配置文件
├── tsconfig.json
└── yarn.lock

由此,我们的工作流如下图所示:

react-native.svg

以上的工作方式,有几个问题值得考虑:

  1. 每个 React Native 项目包含原生项目的副本,是不利于项目可维护性的;
  2. 对于前端同学,尤其是没有接触过 React Native 同学而言,最好的开始不是环境搭建,而是一步到位安装已经集成了 React Native 原生端壳子,并运行一个纯粹的 React Native 项目。

所以我们需要做几件事情:

  1. 壳子工程 (Android 项目、IOS 项目) 从 React Native 项目中剥离。后续所有 React Native 项目将统一使用该壳子工程开发;
  2. 统一 package.json 配置,这个配置我们称为基础依赖配置,React Native、Android、IOS 共享,保证三端的依赖包使用的版本都是相同的;
  3. 在完成这些后,我们就可以考虑原生端自动化集成 bundle 包的方案了,通常也包含 CI 环境的自动化集成。

虽然在技术上的有其一定成本,但依然阻挡不了跨端技术能够降低人力资源成本和提高产能的巨大魅惑,并且这种新架构的实现,也很容易引起开发者探索和关注。

React Native vs Flutter

Google 的 Flutter 跨平台框架从 2017 年 5 月发布以来,就被人们拿来和 React Native 做比较。我知道很多人会拿表格列出他们在性能开发调试体验技术复杂度等维度的不同点,但这样并不能真正区分他们在技术上实质性差异。

例如:在开发体验上,Flutter 对于新手而言非常容易上手,并能快速运行一个 demo App,无需额外的依赖安装和过渡的跨端知识。相比之下由于 React Native 对于开发设备和网络环境的要求,会显得慢很多。但这并不是开发障碍。

对于开发者而言,关注的是更为本质且影响技术选型的差异。我将从技术架构的部件和功能来描述他们之间的差异点,让我们能够技术选型时,做出更为理性的选择。

语言

Dart-platforms.svg

在开发时,Flutter 无论是在 android 端或 iOS 端都将使用 Dart VM 来作为 Dart 的运行时,这点使其具备hot reload的功能,而在部署应用时,Dart 代码以 AOT 方式编译成 Native 语言。所以本质上,Flutter 应用无异于一个原生端应用。相比之下,React Native 需要 JavaScript 执行引擎来解释执行源码,并通过桥接方式和 Native 环境进行通信。因此,性能上 Dart 有明显的优势。

Flutter Android 端应用的性能要比普通应用 (使用 Java 开发的应用) 更高。Android 生态中,大部分 App 都是使用 Java 作为开发语言,运行在系统的 DVM 上。而 Flutter 直接编译成 C/C++ 代码,调用 Android NDK 运行。

rn-vs-flutter.png

React Native 框架使用 Javascript 语言,其运行在 Javascript 执行引擎上。要想实现原生视图及交互,必须和宿主平台 Native 环境进行交互,而他们之间的通信手段使用很传统的 JSON 序列化 方式交换数据。这种方式会在应用初始化时,一次性传递较多的渲染数据,而导致 TTI 时间变成长。相比 iOS 端,在 Android 端很容易形成首次加载的白屏现象。虽是硬伤,但新架构会有所改进。

实践中,6 MB 的 jsbundle 文件,首次加载有较多丰富交互视图时,在 Android 中高端机型中会有 2-3 s 的白屏。

执行环境

在开发调试时,Flutter 的 Dart 代码执行在 Dart VM 中。在应用部署时,Dart 会编译成 C/C++ 代码,运行在原生平台环境中。而 React Native 开发调试时和运行时都在 Javascript 引擎中。调用原生能力时,需要通过 Javascript 桥接 (Bridge) 的方式。所以运行效率上,Flutter 有着绝对的优势。

发表在 前端 | React Native 技术详解 (一) – 认识它已关闭评论

写给前端的 react-native 入门指南

前言

本文主要介绍 react-native(下称 RN) 的入门, 和前端的异同点

文章不涉及功能的具体实现

选择优势

我们先说说, 为什么很多人会选择使用 RN 、他对应的特性和普通 Web 的区别

  1. 前端资源, 生态的互通

因为使用的语言是 JS 和 react, 对于前端来说可以无缝切换, 并且他还能使用前端的各类包

在 JS 端, 安卓和 iOS 是同一套代码

  1. 热更新

很多选择使用 RN 的原因就是有热更新

简单解释下热更新, 在运行 APP 时, js 层我们可以通过接受到的通知, 来进行实时替换, 替换完毕之后一般是要重启 APP 的, 这个时候可以询问用户, 也可以在下次重启时重新载入新的 JS 代码

这样可以保证用户使用的 js 环境, 可以是较新的, 如果是原生 APP 的更新则需要让用户去应用商店重新下载

  1. 支持原生

RN 通过桥接与原生进行交互, 页面级别的融入原生 APP

他的许多组件, 方法都是调用了原生方法/组件, 相对 webview 来说性能更好

跨端框架横向对比

RN 和 Flutter 的简单对比

环境

无论是 RN 还是 Flutter ,都需要 Android 和 IOS 的开发环境,也就是 JDK 、Android SDKXcode 等环境配置,而不同点在于:

  • RN 需要 npm 、node 、react-native-cli 等配置 。
  • Flutter 需要 flutter sdk 和 Android Studio / VSCode 上的 Dart 与 Flutter 插件。

针对前端来说 RN 环境相对友好一点

实现原理

在 Android 和 IOS 上,默认情况下 Flutter 和 React Native 都需要一个原生平台的
Activity / ViewController 支持,且在原生层面属于一个“单页面应用”,
 而它们之间最大的不同点其实在于 UI 构建 :

  • RN:

React Native 是一套 UI 框架,默认情况下 React Native 会在 Activity 下加载 JS 文件,然后运行在 JavaScriptCore 中解析 Bundle 文件布局,最终堆叠出一系列的原生控件进行渲染。

简单来说就是 通过写 JS 代码配置页面布局,然后 React Native 最终会解析渲染成原生控件,如 <View> 标签对应 ViewGroup/UIView ,<ScrollView> 标签对应 ScrollView/UIScrollView ,<Image> 标签对应 ImageView/UIImageView 等。

  • Flutter :

Flutter 中绝大部分的 Widget 都与平台无关, 开发者基于 Framework 开发 App ,而 Framework 运行在 Engine 之上,由 Engine 进行适配和跨平台支持。这个跨平台的支持过程,其实就是将 Flutter UI 中的 Widget “数据化” ,然后通过 Engine 上的 Skia 直接绘制到屏幕上 。

类似于前端的 canvas 绘图

缺点

  • RN:
    • 不能完全兼容W3C的规范,比如W3C里面,可以轻易设置圆角的大小,粗细,边框是实现和虚线,但是在客户端,这个实现起来都比较难。所以这类技术都只能有限的支持W3C的标准。
    • js运行性能瓶颈。
    • 数据通信的性能瓶颈。
  • Flutter:
    • 无法动态更新。
    • 内存和包大小占用。
    • 学习成本高,生态不足。
发表在 前端 | 写给前端的 react-native 入门指南已关闭评论

懒熊打卡APP

懒熊打卡

发表在 app | 懒熊打卡APP已关闭评论

喝水熊猫APP

欢迎使用“熊猫喝水”

发表在 app | 喝水熊猫APP已关闭评论

喝水熊猫 APP即将上线,敬请期待

发表在 app | 喝水熊猫 APP即将上线,敬请期待已关闭评论