摘要:
目前流行的兩個智能手機操作系統 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 新特性中的一部分,也是最常用的幾條。篇幅原因,寫的比較簡單。更詳細的內容可以參考 https://babeljs.io/docs/en/learn
三、開發體驗,優缺點總結
優點:
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 助力,現在的開發體驗還是不錯的。