作了2個多月的設計和編碼,我梳理了Flutter動態化的方案對比及最佳實現

背景

在端上爲了提高App的靈活性, 快速解決萬變的業務需求,開發者們探索了多種解決方案,如PhoneGap ,React Native ,Weex等,但在Flutter生態尚未好的解決方案。將來閒魚都會基於Flutter 來跨端開發,若是突破發版週期,在不發版的狀況下,完成業務需求,同時能兼容性能體驗,無疑是更快的響應了業務需求。所以咱們須要探索在Flutter生態下的動態化。css

方案選擇

借鑑Android 和Ios上的動態性方案,咱們也思考了多種Flutter動態性方案。前端

1.下載替換Flutter編譯產物java

下載新的Flutter編譯產物,替換 App 安裝目錄下的編譯產物,來實現動態化,這在Android 端是可行的,但在Ios 端不可行。咱們須要雙端一體的解決方案,因此這不是最好選擇。node

2.相似React Native 框架android

咱們先來看看React Native 的架構ios

MacDown image

React Native 要轉爲android(ios) 的原生組件,再進行渲染。
用React Native的設計思路,把XML DSL轉爲Flutter 的原子widget組件,讓Flutter 來渲染。技術上說是可行的,但這個成本很大,這會是一個龐大的工程,從投入產出比看,不是很好的選擇json

3.頁面動態組件框架後端

由粗粒度的Widget組件動態拼裝出頁面,Native端已經有不少成熟的框架,如天貓的Tangram,淘寶的DinamicX,它在性能、動態性,開發週期上取得較好平衡。關鍵它能知足大部分的動態性需求,能解決問題。weex

三種方案的比較圖表如:
MacDown image網絡

根據實際動態性需求,從兩端一致性,和性能,成本,動態性考慮,咱們選擇一個折中方案,頁面動態組件的設計思路是一個不錯的選擇。

頁面動態組件框架

在Flutter上使用粗力度的組件動態拼裝來構建頁面,須要一整套的先後端服務和工具。本文咱們重點介紹前端界面渲染引擎過程。

語法樹的選擇

Native端的Tangram ,DinamicX等框架他們有個共同點,都是Xml或者Html 作爲DSL。可是Flutter 是React Style語法。他本身的語法已經能很好的表達頁面。無須要自定義的Xml 語法,自定義的邏輯表達式。用Flutter 源碼作爲DSL 能大大減輕開發,測試過程,不須要額外的工具支持。
因此選擇了Flutter 源碼做爲DSL,來實現動態化。

如何解析DSL

Flutter源碼作爲DSL,那咱們須要對源碼進行很好的解析和分析。Flutter analyzer給了咱們一些思路,Flutter analyzer是一個代碼風格檢測工具。它使用package:analyzer來解析dart 源碼,拿到ASTNode。

看下Flutter analyze 源碼結構,它使用了dart sdk 裏面的 package:analyzer

dart-sdk: analysis_server: analysis_server.dart handleRequest(Request request) analyzer: parseCompilationUnit() parseDartFile parseDirectives 

Flutter analyze 解析源碼獲得ASTNode過程。

MacDown image

插件或者命令對analysis server發起請求,請求中帶須要分析的文件path,和分析的類型,analysis_server通過使用 package:analyzer 獲取 commilationUnit (ASTNode),再對astNode,通過computer分析,返回一個分析結果list。

一樣咱們也能夠把使用 package:analyzer 把源文件轉換爲commilationUnit (ASTNode),ASTNode是一個抽象語法樹,抽象語法樹(abstract syntax tree或者縮寫爲AST)是源代碼的抽象語法結構的樹狀表現形式.

全部利用抽象語法樹能很好的解析dart 源碼。

解析渲染引擎

下面重點介紹渲染模塊

架構圖:

MacDown image

1.源碼解析過程

1.AST樹的結構

以下面這段Flutter組件源碼:

import 'package:flutter/material.dart'; class FollowedTopicCard extends StatelessWidget { @override Widget build(BuildContext context) { return new Container( padding: const EdgeInsets.fromLTRB(12.0, 8.0, 12.0, 0.0), child: new InkWell( child: new Center( child: const Text('Plugin example app'), ), onTap: () {}, ), ); } }

它的AST結構:

MacDown image

從AST結構看,他是有規律的.

2.AST 到widget Node

咱們拿到了ASTNode,但ASTNode 和widget node tree 徹底是兩個不同的概念,
須要遞歸ASTNode 轉化爲 widget node tree.

widget Node 須要的元素

用Name 來記錄是什麼類型的widget

widget的arguments放在 map裏面

widget 的literals 放在list 裏面

widget 的children 放在lsit 裏面

widget 的觸發事件 函數map裏面

widget node 加fromjson ,tojson 方法

能夠在遞歸astNode tree 時候,識別InstanceCreationExpression來建立一個widget node。

2.組件數據渲染

框架sdk 中註冊支持的組件,組件包括:

a.原子組件:Flutter sdk 中的 Flutter 的widget

b.本地組件:本地寫好到一個大顆粒的組件,卡片widget組件

c.邏輯組件:本地包裝了邏輯的widget組件

d.動態組件:經過源碼dsl動態渲染的widget

具體代碼以下:

const Map<String, CreateDynamicApi> allWidget = <String, CreateDynamicApi>{ 'Container': wrapContainer, …………. } static Widget wrapContainer(Map<String, dynamic> pars) { return new Container( padding: pars['padding'], color: pars['color'], child: pars['child'], decoration: pars['decoration'], width: pars['width'], height: pars['height'], alignment: pars['alignment'] ); }

通常咱們經過網絡請求拿到的數據是一個map。
好比源碼中寫了這麼一個 '${data.urls[1]}'
AST 解析時候,拿到這麼一個string,或者AST 表達式,經過解析它 ,確定能從map 中拿到對應的值。

3.邏輯和事件

a.支持邏輯

Flutter 概念萬物都是widget ,能夠把表達式,邏輯封裝成一個自定義widget。若是在源碼裏面寫了if else,變量等,會加劇sdk解析的過程。因此把邏輯封裝到widget中。這些邏輯widget,看成組件當成框架組件。

b.支持事件

把頁面跳轉,彈框,等服務,註冊在sdk裏面。約定使用者僅限sdk 的服務。

4.規則和檢測工具

a.檢測規則

須要對源碼的格式制定規則。好比不支持 直接寫if else ,須要使用邏輯wiget組件來代替if else 語句。若是不制定規則,那ast Node 到widget node 的解析過程會很複雜。理論上均可以解析,只要解析sdk 夠強大。制定規則,能夠減輕sdk的解析邏輯。

b.工具檢測

用工具來檢測源碼是否符合制定的規則,以保證全部的源碼都能解析出來。

性能和效果

幀率大於50fps,體驗上看比weex相同功能的頁面更加流暢,Samsung galaxy s8上,感受不出組件是經過動態渲染的.

數據結構

服務端請求到的數據,咱們能夠約定一種格式以下:

class DataModel { Map<dynamic, dynamic> data; String type; } 

每一個page 都是由組件組成的,每一個組件的數據都是 DataModel來渲染。
根據type 來找到對應的模版,模版+data,渲染出界面。

動態模版管理模塊

咱們把Widget Node Tree 轉換爲一個組件Json模版,它須要一套管理平臺,來支持版本控制,動態下載,升級,回滾,更新等。

框架的邊界

該框架是經過組件的組裝,組件佈局動態變動,頁面佈局動態變動來實現動態化。因此它適合運營變化較快的首頁,詳情,訂單,個人等頁面。一些複雜的邏輯須要封裝在組件裏面,把組件內置到框架中,看成本地組件。框架側重於動態組件的組裝,而引擎對於源碼複雜的邏輯表達式的解析是弱化的。

後續拓展

1.和UI自動化的結合

UI自動化 
,前面已經有文章介紹。UI自動化工具生成組件,再組件轉爲模版,動態下發,來快速解決運營需求。

2.國際化的支持

App在不一樣國家會有不一樣的功能,咱們能夠根據區域,來動態拼裝咱們的頁面。

3.千人千面

根據不一樣的人羣,來動態渲染不同的界面。

總結

本文介紹動態化方案的渲染部分。該方案都在初探階段,還有不少須要完善,後續會繼續擴展和修改,等達到開源標準後,會考慮開源。動態方案是一個後端前端一體的方案,須要一整套工具配合,後續會有文章繼續介紹總體的動態化方案。

 

原文連接本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索