自從android和iOS兩大移動平臺的確立以來,人們就一直在不懈地探索各類跨平臺技術,但願於能用一個團隊,一套代碼高效地橫跨兩大平臺,節省人力成本的同時,快速地完成產品的開發迭代,在快速發展和激烈競爭的移動互聯網環境中佔得優點。html
全部的跨平臺技術方案歸納起來無外乎是就是兩個方面:前端
UI跨平臺react
包括控件、佈局、動畫、手勢等的渲染和交互。
複製代碼
非UI平臺API調用android
橋接調用平臺系統能力。如傳感器、攝像頭、設備信息、網絡狀態等。
複製代碼
跨平臺技術的核心在於UI跨平臺。根據實現UI跨平臺方式的不一樣,目前的跨平臺技術能夠分爲下面三類:git
原理:基於H5技術,經過WebView渲染UI,經過JS橋接和原生交互github
優點:開發效率、動態性、包大小apache
劣勢:性能和用戶體驗json
使用狀況:很是普遍,個別深度使用(優化性能)redux
原理:基於類HTML+CSS+JS開發界面和業務邏輯,並轉換爲原生視圖進行渲染。
框架:React Native、Weex
優點:前端技術棧、開發效率、動態性
劣勢:長列表滑動性能、跨端一致性
使用狀況:比較普遍,國內國外,大廠小廠均有
原理:基於跨平臺高性能2D渲染引擎Skia繪製界面。DART在Debug模式下JIT編譯,支持熱重載;在Release模式下AOT編譯成ARM彙編代碼,執行效率高,調用原生API效率高;支持isolate多線程執行
優點:精美、接近原生的性能(閒魚:平均52幀/秒,300毫秒頁面加載時間)、跨端一致性
劣勢:成熟度(框架自己,社區生態),包大小
使用狀況:大廠都在研究和嘗試
閒魚、騰訊、京東、美團
React Native主要包括如下要點:
JavaScript
let var const
數字、布爾、字符串、undefined、null、對象
Array、Date、Error
閉包
箭頭函數
複製代碼
React
JSX語法
JavaScript裏嵌XML,用於描述UI。JSX中的JS表達式要{}包起來。
組件(React.Component)
state狀態
props屬性
生命週期方法
constructor
componentWillMount
render
componentDidMount
componentWillUnmount
經常使用UI組件
View
Image
Text
FlatList
聲明式UI
樣式分離
Flexbox佈局
複製代碼
狀態管理 redux
網絡請求 Fetch API (Promise或async、await)
依賴管理
NPM install Pod install
複製代碼
第三方組件
https://github.com/react-native-community
https://react.parts/?collection=React+Native
https://github.com/ant-design/ant-design-mobile-rn/
https://github.com/Meituan-Dianping/beeshell
複製代碼
調試\熱重載
IDE CLI Chrome Shake
複製代碼
性能優化
https://reactnative.cn/docs/performance/
https://blog.csdn.net/sinat_17775997/article/details/80852485
https://mp.weixin.qq.com/s/Z1GUJW3qBqDGH1jnGt5qAg
複製代碼
下面咱們結合一個簡單的RN實例代碼學習和了解RN的一些基本概念和知識。
例子代碼:RNDemo
這個例子很是簡單,只有一個頁面,它從網絡請求數據,而後在列表裏顯示數據。
// 應用入口
AppRegistry.registerComponent(appName, () => App);
export default class App extends React.Component {
// 構造函數:初始化屬性和變量
constructor(props) {
super(props);
this.state = {
data: [],
loaded: false
};
// 在ES6中,若是在自定義的函數裏使用了this關鍵字,則須要對其進行「綁定」操做,不然this的指向會變爲空
this.fetchData = this.fetchData.bind(this);
this.renderMovie = this.renderMovie.bind(this);
}
// 組件已掛載:請求數據
componentDidMount() {
this.fetchData();
}
// 繪製方法:返回JSX視圖結構
render() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<FlatList
data={this.state.data}
renderItem={this.renderMovie}
style={{ backgroundColor: "#F5FCFF" }}
keyExtractor={item => item.id}
/>
</SafeAreaView>
</>
);
}
// 異步網絡請求
async fetchData() {
try {
let response = await fetch(REQUEST_URL);
let responseData = await response.json();
this.setState({
data: this.state.data.concat(responseData.movies),
loaded: true
});
} catch (error) {
console.error(error);
}
}
}
//樣式
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF",
paddingHorizontal: 15,
paddingVertical: 10
},
});
複製代碼
調用this.setState方法會觸發render()方法重繪。
Flutter主要包括如下要點:
Dart
var final const static
可選位置參數[]、可選命名參數{}
箭頭函數
Class 命名構造函數 工廠構造函數factory 重定向構造方法:
Map List Set
級連 ..
Future async await
複製代碼
Widget
無狀態StatelessWidget 有狀態StatefullWidget & State
生命週期方法
initState
build
dispose
複製代碼
萬物皆Widget
Widget很是輕量,僅包含不可變的配置信息。
基礎Widget Button Text Image TextField
佈局Widget Row Column Center Padding Container Expanded
滾動Widget ListView GridView PageView
裝飾Widget BoxDecoration Opacity
https://flutter.cn/docs/development/ui/widgets
https://flutter.cn/docs/reference/widgets
https://github.com/alibaba/flutter-go
複製代碼
兩套UI風格 Material Cupertino
對應android默認的物化風格和iOS系統的原生風格。
聲明式UI
網絡請求 dio
依賴管理
包含原生調用的package稱爲plugin。
package plugin
flutter pub get
複製代碼
第三方包
調試\熱重載
IDE CLI DevTool
複製代碼
性能優化
Flutter自己已具有較好的性能,性能方面須要關注的點很少。
下面咱們結合一個簡單的Flutter實例代碼學習和了解Flutter的一些基本概念和知識。
例子代碼:FlutterDemo
這個例子很是簡單,只有一個頁面,它從網絡請求數據,而後在列表裏顯示數據。
// 應用入口
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// 構建方法:這裏返回應用根Widget
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: FutureBuilderPage(),
);
}
}
class FutureBuilderPage extends StatefulWidget {
// 建立狀態對象
@override
_FutureBuilderPageState createState() => _FutureBuilderPageState();
}
class _FutureBuilderPageState extends State<FutureBuilderPage> {
Future future;
// 初始化方法
@override
void initState() {
super.initState();
future = getListData(); // 請求網絡數據
}
// 構建方法:返回Widget樹
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('知識體系')),
body: buildFutureBuilder(),
);
}
// 使用FutureBuilder處理異步網絡請求
FutureBuilder<List<Data>> buildFutureBuilder() {
return FutureBuilder<List<Data>>(
future: future,
builder: (context, snapshot) {
//在這裏根據快照的狀態,返回相應的widget
if (snapshot.connectionState == ConnectionState.done) {// 請求完成
if (snapshot.hasError) {// 請求失敗
return Center(
child: Text("ERROR"),
);
} else if (snapshot.hasData) {// 請求成功,數據用列表顯示
List<Data> list = snapshot.data;
return RefreshIndicator(
child: buildListView(context, list), onRefresh: refresh);
}
}
// 正在加載
return Center(
child: CircularProgressIndicator(),
);
});
}
buildListView(BuildContext context, List<Data> list) {
return ListView.builder(// 構建長列表
itemCount: list.length,
itemBuilder: (context, index) {
Data item = list[index];
StringBuffer str = new StringBuffer();
for (Children children in item.children) {
str.write(children.name + " ");
}
return Column(
children: [
ListTile(
title: Text(item.name),
subtitle: Text(str.toString()),
trailing: IconButton(
icon: Icon(
Icons.navigate_next,
color: Colors.grey,
),
onPressed: () {})
),
Divider()
]
);
});
}
//獲取網絡數據,利用dio庫進行網絡請求,拿到數據後利用json_serializable解析
//並將列表的數據包裝在一個future中
Future<List<Data>> getListData() async {
var dio = new Dio();
Response response = await dio.get("http://www.wanandroid.com/tree/json");
Map<String, dynamic> map = response.data;
Entity entity = Entity.fromJson(map);
return entity.data;
}
//刷新數據,從新設置future就好了
Future refresh() async {
setState(() {
future = getListData();
});
}
}
複製代碼
React Native對於前端人員來講學習成本是比較低的。Flutter我的感受學習成本比RN略高一點,自帶的Widget比較多。 接入成本我以爲二者差很少。
目前來講,二者都是比較穩定的。但從GitHub上issues的數量上看React Native要更穩定,畢竟RN出現的較早。不過Flutter的迭代速度明顯更快,畢竟Google的實力更強,相信Flutter會很快反超。
這方面也是React Native更有優點一些,一樣得益於它時間上出現的更早。兩三年前做爲惟一靠譜的跨平臺方案,它獲得了不少大廠的承認和採用,這些大廠也在RN生態的建設上投入了比較多的精力。有人統計中國市場上排名前100的應用有十幾個使用了RN或Weex。而Flutter雖然時間較晚,但發展很快,目前,開發中經常使用的一些模塊都已有成熟的第三方packages。大小公司也都投入了很大的熱情去研究和嘗試。
開發體驗上我的以爲二者差很少。都支持熱重載。提供的IDE插件,命令行工具,可視化DevTool也很類似。
React Native因爲採用原生視圖渲染,咱們經常須要去適配和橋接兩個平臺的差別性。且RN不一樣平臺JS引擎的不一致,也埋下了一些隱患。而Flutter則是在更底層抹平了平臺差別,使用統一的Skia引擎渲染,因此從原理上來講Flutter的跨端一致性會更好。而實際體驗中Flutter也確實更有優點。
動態性是React Native最大的優點,這也是不少電商、外賣大廠深度使用RN的主要緣由。而Flutter僅在Android上支持動態化。
這裏有一個對比數據。咱們能夠看到,同等條件下:
RN的包iOS比Android小不少。由於iOS內置了JavaScriptCore。
Flutter包Android比iOS小不少。由於Android內置了Skia引擎。
Flutter在數據和實際體驗方面都優於RN。詳情能夠查看下面的連接: www.yuque.com/xytech/flut…
二者直接的對比比較少,但從二者與原生的對比文章來看,Flutter這方面的性能更優。實際體驗也是如此。
詳細的對比信息能夠參考下面的連接:
https://juejin.im/post/5c88bea55188257dfa07e397#heading-22
https://juejin.im/post/5d0bac156fb9a07ec56e7f15#heading-10
https://www.yuque.com/xytech/flutter/blquhk
複製代碼
本文結合簡單的實例代碼對React Native和Flutter進行了學習和對比,讓你們對目前兩個主流的跨平臺方案有一個初步的認識。其目的是但願給你們的技術選型提供一點幫助。具體到各自的項目,你們仍是須要結合根據業務場景、人力狀況、需求來決定是否使用跨平臺方案,使用哪一個跨平臺方案。
Flutter無疑站在了更高的起點上,但它也未必一統江湖。合適的纔是最好的。