摘要:

目前流行的两个智能手机操作系统 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

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐