摘要:
目前流行的两个智能手机操作系统 iOS 和 Android,各自为营,互不相通。一般情况下,开发一款APP需要两支队伍,分别针对 iOS 和 Android 平台进行开发。为了节约人力成本,有人就想到了跨平台开发解决方案。最近几年有多种跨平台开发方案相继出现,其中由 Facebook 推出的 React Native 框架是目前最完善、最受欢迎的一个。本文主要从 React Native 的实现原理、优缺点剖析、技术选型的思考这三个方面进行阐述。
一、 React Native简介
1. React Native 诞生背景
Android 和 iOS 两大阵营共存,同一款 APP,企业需要两支开发队伍。由于企业要考虑开发成本和迭代速度,那么就有人想过跨平台开发方案。在移动开发流行五六年后,2015年4月,FaceBook 开源了自己的跨平台开发框架 React Native,很快就吸引了全球开发者的眼球,众多公司纷纷尝鲜。它的口号是 “Learn once, write anywhere”,听起来很诱人嗷。
可以看出,跨平台开发是民心所向,未来趋势。关键还有热更新功能。
2. React Native 架构设计
RN使用Javascript语言,和类似于HTML的JSX、以及CSS的页面布局来开发移动应用,类似React网页开发。而实际调用的是两个平台的原生控件。所以用户体验很好,可以媲美原生APP。
整体分为三大块:
1)Native, 管理UI更新及交互。界面上显示的所有元素,都是原生控件。安卓平台上就是安卓的控件,iOS上就是iOS的控件。
2)JavaScript,实现业务功能。这里是和开发者直接打交道的部分,我们写的JS代码就在这一部分。
3)Bridge, 在二者之间传递消息(通过JSON消息相互通信)。这个是 React Native 的灵魂所在,它不仅承担了传递消息的角色,而且还有其他重要的工作要做,例如计算图渲染层(由 Shadow Tree 来完成)。
下图可以表示这三个模块的结构:
再来看看这三个模块之间是怎么配合工作的:
举个栗子,屏幕上有个蓝色按钮,点击以下让它变成红色,这个动作在 React Native 程序中是这样完成的:
- 屏幕上的原生按钮接收到点击事件;
- 告诉 Bridge 层,“嘿,我被点击了一下”;
- Bridge 层接收到这个消息,把消息打包成 JSON 数据,扔给 JavaScript 层;
- JavaScript 层知晓后,执行我们写的代码,“把按钮的颜色改成红色”;(这个时候按钮的颜色还没真正改变)
- JavaScript 层“把按钮颜色改成红色”的这个动作发给 Bridge 层;
- Bridge 层把这个动作(命令)打包成 JSON 数据,发给 Native 层;
- Native 层把按钮的颜色改成红色。
3. React Native 线程模型
React Native 主要有三个线程,分别是:
1)UI Thread: 应用中的主线程;为了保证界面的流畅性,所有 UI 执行都是在这个线程。
2)JS Thread: JavaScript 代码在这个线程执行;
3)Shadow Thread: 进行布局计算和构造UI界面的线程。
二、JavaScript (ES6)
React Native 用JavaScript开发,其中ES6 目前基本成为业界标准。(以下是一些ES6特性的介绍,只关心 RN 的可以直接跳过这一节)
一些常用的ES6特性:
1. let + const 块级作用域和常量;
var x = '全局变量';
{
let x = '局部变量';
console.log(x); // 局部变量
}
console.log(x); // 全局变量
// let表示声明变量,而const表示声明常量
const a = 1
a = 0 //报错
const student = { name: 'cc' }
student.name = 'yy';// 不报错 (就是对象所指向的地址没有变就行)
2. 模板字符串
$("body").html(`This demonstrates the output of HTML content to the page, including student's ${name}, ${seatNumber}, ${sex} and so on.`);
3. 箭头函数
var add = (a, b) => a + b;
4. 函数的参数默认值
function printText(text = 'default') {
console.log(text);
}
5. Spread / Rest 操作符
let aaa = [1, 2, 3, 4];
console.log(...aaa); // 1 2 3 4
6. 对象和数组解构
const student = {
name: 'Sam',
age: 22,
sex: '男'
}
// ES6
const { name, age, sex } = student;
console.log(name + ' --- ' + age + ' --- ' + sex);
7. 类中的继承和超集
8. Promise
usePromise(1000).then(() => {
console.log("use promise 1");
return usePromise(1000);
}).then(() => {
console.log("use promise 2");
return usePromise(1000);
}).then(() => {
console.log("use promise 3");
return usePromise(1000);
}).then(() => {
console.log("use promise 4");
})
9. Modules
import:
export var firstName = 'Michael';
export default function () {
console.log('foo');
}
export:
import { firstName, lastName, year } from './profile';
import React, { Component, PropTypes } from 'react';
import * as React from 'react';
以上几个点是 ES6 新特性中的一部分,也是最常用的几条。篇幅原因,写的比较简单。更详细的内容可以参考 Learn ES2015 · Babel
三、开发体验,优缺点总结
优点:
1. 跨平台-最大的优点,代码复用率95%以上;
2.热更新-避免每次迭代提交APP商店审核,和漫长等待;
3. UI调试方便-不用像原生开发那样每次编译;
4. css-layout布局-方便;
5. 有个好爹,Facebook,会越来越完善;
6. 节约公司成本,是‘小而快’团队的最佳选择。
缺点:
1. 整体开发体验不如iOS原生开发;
2. 功能相比原生还不够完善,部分控件缺失,第三方控件不如原生丰富;
3. 两个平台还没完全统一,部分控件平台专属,表现有平台差异;
4. 文档相对粗略,有滞后性,一些细节性问题在官方文档上找不到答案;
5. 升级RN版本或需要大动干戈,向下兼容不好;
6. 增加IPA和APK包大小。
PS:缺点写的比较狠,别被吓住了哈。
四、选用新技术我们是这样思考的:
1. 怎么实现的跨平台?
简而言之,用JS封装两个平台的控件,开发者只需要编写JS代码,基本不用考虑平台特性。是用JS把两个风马牛不相及的平台统一了起来了。
2. 性能如何?
既然是封装了原生控件,那性能应该不会差,无非就是多了一个JS解释器和几个线程,对于手机设备来说几乎可以忽略不计。(但低端安卓手机上动画表现不佳) (项目性质。对我们的项目无影响)
3. 是否可持续?
a. 他爸是Facebook
b. 社区很活跃
c. 有很多企业在用
4. 适合我们吗?
a. 跨平台需求的紧迫性
b. 技术成本和人力成本
c. 热更新需求
d. 项目复杂度
五、话题延展
1. 是否可以和原生混合开发?
可以,现有原生里嵌套RN页面。JS和原生可以通过桥接相互调用。
2. 和flutter比如何?
没有深入研究过flutter,道听途说得知:
1)有团队专门做过性能测试,各有利弊,基本不相上下;
2)flutter用Dart语言,有一定学习成本,开源时间不长,成熟度不如RN;
3)可以作为兴趣研究一下
3. 为什么没有选择用Flutter?
a. flutter 当时处于初级阶段,我们应该避免成为早期吃螃蟹的人;
b. 有经验的开发者少,Dart 语言较为陌生。RN开发者相对较多。JavaScript 语言已经被广泛使用;
c. 性能方面和 RN 不分伯仲,没有明显优势。
六、总结
以上从 React Native 的诞生背景、实现原理、使用体验、优缺点分析和技术选型的策略进行了阐述,中间还植入了 ES6 的一些新特性。希望能从宏观上带你了解 React Native, 为你在技术选型上提供一些参考。
技术选型是项非常需要谨慎的事情,选好了会给团队和项目带来很大的便捷,选错了有可能会造成灾难。这其中有很多因素的考虑,以及技术调研和验证。
我是2017年在项目中使用过一年 React Native,那个时候后的版本是0.41。那个时候遇见了很多坑,填了很多坑。时隔两年之后,在新公司又开始使用 React Native,目前的版本是0.62,比起两年前的情况好了很多。再加上 expo 助力,现在的开发体验还是不错的。
这里有一个 Starter Kit,可以帮你快速体验:https://github.com/gang544043963/react-native-starter-kit-expo