移動端跨平臺技術方案研究

自從android和iOS兩大移動平臺的確立以來,人們就一直在不懈地探索各類跨平臺技術,但願於能用一個團隊,一套代碼高效地橫跨兩大平臺,節省人力成本的同時,快速地完成產品的開發迭代,在快速發展和激烈競爭的移動互聯網環境中佔得優點。html

如何跨平臺

全部的跨平臺技術方案歸納起來無外乎是就是兩個方面:前端

  • UI跨平臺react

    包括控件、佈局、動畫、手勢等的渲染和交互。
    複製代碼
  • 非UI平臺API調用android

    橋接調用平臺系統能力。如傳感器、攝像頭、設備信息、網絡狀態等。
    複製代碼

技術劃分

跨平臺技術的核心在於UI跨平臺。根據實現UI跨平臺方式的不一樣,目前的跨平臺技術能夠分爲下面三類:git

H5應用或Hybrid應用

  • 原理:基於H5技術,經過WebView渲染UI,經過JS橋接和原生交互github

  • 框架:CordovaIonicshell

  • 優點:開發效率、動態性、包大小apache

  • 劣勢:性能和用戶體驗json

  • 使用狀況:很是普遍,個別深度使用(優化性能)redux

    12306,銀行類App,支付寶手機QQ百度App

用Web技術開發原生應用

  • 原理:基於類HTML+CSS+JS開發界面和業務邏輯,並轉換爲原生視圖進行渲染。

  • 框架:React NativeWeex

  • 優點:前端技術棧、開發效率、動態性

  • 劣勢:長列表滑動性能、跨端一致性

  • 使用狀況:比較普遍,國內國外,大廠小廠均有

    攜程美團京東、餓了麼、騰訊課堂

Flutter

  • 原理:基於跨平臺高性能2D渲染引擎Skia繪製界面。DART在Debug模式下JIT編譯,支持熱重載;在Release模式下AOT編譯成ARM彙編代碼,執行效率高,調用原生API效率高;支持isolate多線程執行

  • 優點:精美、接近原生的性能(閒魚:平均52幀/秒,300毫秒頁面加載時間)、跨端一致性

  • 劣勢:成熟度(框架自己,社區生態),包大小

  • 使用狀況:大廠都在研究和嘗試

    閒魚、騰訊、京東、美團

React Native實例

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實例

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 
    複製代碼
  • 第三方包

    pub.flutter-io.cn/flutter

  • 調試\熱重載

    IDE CLI DevTool
    複製代碼
  • 性能優化

    Flutter自己已具有較好的性能,性能方面須要關注的點很少。

    flutter.cn/docs/testin…

下面咱們結合一個簡單的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引擎。

  • 內存/CPU/FPS

    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進行了學習和對比,讓你們對目前兩個主流的跨平臺方案有一個初步的認識。其目的是但願給你們的技術選型提供一點幫助。具體到各自的項目,你們仍是須要結合根據業務場景、人力狀況、需求來決定是否使用跨平臺方案,使用哪一個跨平臺方案。

  • 對於UI和交互簡單,性能要求不高,但動態性很重要的應用能夠用H5或Hybrid的方式。
  • 對於UI和交互較複雜,有必定的性能要求,動態性很重要的應用能夠用React Native(或Weex)。
  • 對於複雜的UI和交互,性能要求高,但動態性要求不是首要的應用能夠用Flutter。

Flutter無疑站在了更高的起點上,但它也未必一統江湖。合適的纔是最好的。

相關文章
相關標籤/搜索