乾貨 | 把Flutter擴充套件到微信小程式端的探索
Google Flutter是一個非常優秀的跨端框架,不僅可以執行在Android、 iOS平臺,而且可以支援Web和桌面應用。在國內小程式是非常重要的技術平臺,我們也一直思考能否把Flutter擴充套件到小程式端?我們團隊之前已經開源了Alita專案(),Alita可以把React Native的程式碼轉換並執行在微信小程式平臺。受此啟發,我們認為同樣是宣告式UI框架的Flutter同樣可以執行在小程式平臺。
所以,我們發起了flutter_mp()開源專案。以微信小程式為例,不過現階段,flutter_mp專案還處於早期的實驗階段,很多功能還在探索規劃中,歡迎大家在Github上隨時關注我們的最新進展,或者參與專案共同探索。
原理簡介
雖然還有諸多功能未完成,我們先來談談整個flutter_mp的實現原理。篇幅原因,下面我們將只對flutter_mp幾個重要的部分進行簡單說明。
先看下flutter_mp的實際效果:
Flutter版官方layout樣例:
透過flutter_mp轉換並執行在小程式端效果
宣告式UI的處理
Flutter是宣告式UI框架,宣告式UI只需要向框架描述UI長什麼樣子而不用關心框架具體的實現細節,具體到Flutter,上層的UI描述使用底層的skia圖形引擎處理就是原生Flutter,而把底層處理換成html/css/canvas就是flutter_web,flutter_mp則是探索在類小程式上對這些UI描述的處理。
我們看一個最簡單例子
var x = 'Hello World'
Center(
child: Text(x)
);
對於上面的UI結構,我們只需要在小程式的wxml檔案裡,用如下的結構對應就OK了。
// wxml部分
<Center>
<Text>{{x}}</Text>
</Center>
// js 部分
Component({
data: {
x: 'Hello World'
}
})
雖然實際的結構要比上面的情況複雜的多,不過透過上面簡單的例子,我們知道起碼要做兩個事情:
我們需要根據Flutter程式碼生成相關小程式wxml模版檔案 收集wxml渲染需要的資料,放置到小程式元件的data欄位。
wxml結構生成
我們知道小程式是無法動態操作節點的,wxml結構需要預先生成,所以Flutter執行在小程式之前,會存在一個編譯打包階段,這個階段會遍歷Dart程式碼, 根據一定規則生成wxml檔案(編譯階段還會做下文將要提到的另外一個重要事情 --- 把Dart編譯為js)。
具體的,我們首先會將Dart原始碼處理為可分析的AST結構,AST是原始碼的樹型表示結構。然後我們深度遍歷這份AST語法樹結構,生成目標wxml,整個過程如下:
構建wxml結構的難點在於:Flutter不僅是宣告式UI還是“值UI”,什麼叫“值UI”?簡單來說,Flutter把UI看成是一個普通的值,類似於字串,數字一樣的值,既然是一個普通的值,就可以參與所有的控制流程,可以是函式的返回值也可以是函式引數等等。而小程式的wxml雖然也是宣告式UI,卻不是“值UI”,wxml更加像模版,更加的靜態。怎麼用靜態的wxml表達動態的“值UI”是構建wxml結構的關鍵所在。
看個例子
Widget getX() {
if (condition1) {
return Text('Hello');
} else if (condition2) {
return Container(
child: ...
);
} else if (condition3) {
return Center(
child: ...
);
}
...
}
Widget x = getX();
Center(
child: x // < --- 如何處理這裡的 x??
);
這裡的child: x x是一個動態值,它的具體值需要在執行階段才能確定,它可能是任意的Widget,如何在靜態的wxml上處理這裡動態的x?受Alita框架的啟發,這裡主要是藉助於小程式template的動態性(template的is屬性可以接受變數值)。有如下幾步:
1、首先在遍歷Dart原始碼AST結構的時候,會把每一個獨立完整的“UI值”片段,對應到wxml的template, 比如上文 getX 裡面的UI
<template name="template001">
<text>Hello</text>
</template>
<template name="template002">
<Container>...</Container>
</template>
<template name="template003">
<Center>...</Center>
</template>
2、在遇到 類似x 這種動態值的時候,固定的會生成一個template佔位
<template name="template004">
<Center>
<template is="{{templateName}}" data="{{...templateData}}"/>
</Center>
<template name="template003">
3、在執行階段,會根據getX
函式的執行結果來決定x對映的“UI值”,如果getX裡面condition1為true,那麼這裡的templateName的值就是template001。具體的資料計算收集工作,參考下面要的 “渲染資料收集”過程。可以看出flutter_mp處理“值UI”方式,完全參考了Alita。
渲染資料收集
wxml結構的生成是在編譯階段就完成了,與它不同渲染資料是執行時的資訊,隨時會根據setState而改變。那麼我們怎麼收集出我們需要的渲染資料呢?
如果我們還是順著Flutter的架構圖,很難插入我們收集的鉤子函式,另外Flutter的這個架構對於小程式來說太重了,下圖紅框裡的這些過程對於小程式的渲染來說並不必要。最後由於最終的程式碼會被轉化為js,而Flutter本身依賴的庫裡面很多是不支援轉化js的,比如dart:ui等等。
所以我們實現了一個極簡極簡的Flutter小程式版本mini_flutter,在編譯期我們會把所有對Flutter庫的引用替換為mini_flutter, mini_flutter只存在到上圖的Rendering階段,這個Rendering的實現也是為小程式定製的, 在執行時期Rendering不斷收集Widgets的資訊。最終生成一個UI描述的JSON結構,這個結構就包含了上文所說的templateName, templateData,UI描述將會被下層小程式獲得,用來渲染小程式UI,架構圖如下:
Dart/JS:轉化與互操作
Flutter的開發語言是Dart,而小程式的執行環境是瀏覽器,所以我們還需要把Dart編譯為JavaScript程式碼。
在上文的編譯打包階段也提到這一點,這個過程主要是使用了Dart提供的dart2js工具,不過,針對小程式環境,生成的js程式碼仍需要做一些適配,另外雖然都是JS程式碼,dart2js生成的js和小程式原生js的執行環境卻是隔離的,也就是說它們是不能共享變數,方法等等,它們各自在本身的"域"裡執行。
這帶來兩個問題:
1、Widget 初始化 或者setState更新,生成的UI描述JSON,如何傳遞給小程式"域"呢?
2、相關渲染回撥,事件的都發生在小程式"域",這些資訊如何傳遞給Dart?
總結一下:Dart(最終會編譯為JS)與小程式原生JS如何互操作?
解決這個問題主要是藉助dart:js, package:js這兩個庫:
Dart操作JS
<template name="template004">
<Center>
<template is="{{templateName}}" data="{{...templateData}}"/>
</Center>
<template name="template003">
這樣當Dart程式碼呼叫stringify方法的時候,實際上會執行window.JSON.stringify方法
JS操作Dart
// dart註冊
void main() {
context['dartHi'] = () {
print('dart hi!');
};
}
// js 呼叫
window.dartHi()
這裡只是簡單說明Dart與JS的互操作,另外由於小程式的執行環境是閹割以後的瀏覽器環境,flutter_mp的實現還稍有不同。
總之,Dart與JS是可以互操作的,這樣就打通了上層Flutter環境和下層小程式環境。
佈局系統
Flutter的佈局系統不同與css,但是和css頗相似。
在上文提到的Rendering階段,會根據Widget的佈局屬性,類別,約束條件生成一個等效的css樣式。注意這裡邊界約束是上下文相關的。比如一個沒有寬高的Container實際大小,不僅和子元素相關,還和父元素傳遞過來的邊界約束條件相關,這個其實是比較麻煩的,能不能把Flutter的Widget屬性,邊界約束完全用css表達,我們還在尋求有效的方案。
總結
和flutter_web一樣,完全把Flutter所有特性渲染到小程式上是不可能的,一般我們覺得應該是部分頁面,部分功能需要執行在小程式上,這樣使用flutter_mp才是有意義的。
正如前文所說,flutter_mp還在很早期的階段,如果你需要在生產環境實現小程式跨端開發,推薦使用我們成熟的RN轉小程式專案Alita。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69912185/viewspace-2660224/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 把Flutter擴充套件到微信小程式端的探索Flutter套件微信小程式
- 乾貨丨如何水平擴充套件和垂直擴充套件DolphinDB叢集?套件
- (乾貨)微信小程式元件封裝微信小程式元件封裝
- (乾貨)微信小程式轉發好友微信小程式
- Flutter——Dart Extension擴充套件方法的使用FlutterDart套件
- 微信公眾平臺/擴充套件套件
- 開源 | FLUI : Flutter 的元件擴充套件集UIFlutter元件套件
- PHP實現Bitmap的探索 - GMP擴充套件使用PHP套件
- Laravel 微信小程式獲取『使用者詳細資訊』及『帶引數小程式碼』擴充套件Laravel微信小程式套件
- Flutter 應用程式建立一個擴充套件皮膚列表Flutter套件
- kotlin 擴充套件(擴充套件函式和擴充套件屬性)Kotlin套件函式
- 乾貨技巧,微信小程式推廣運技巧祕籍微信小程式
- [譯] 探索 SMACSS:可擴充套件的模組化 CSS 框架MacCSS套件框架
- Docker 的足跡正擴充套件到中國Docker套件
- Laravel Admin 微信擴充套件,支援多公眾號、多小程式、多微信支付,包含後臺與介面Laravel套件
- 乾貨|Linux程式函式棧列印工具gstack原始碼解讀、運用及擴充套件程式設計Linux函式原始碼套件程式設計
- chrome擴充套件程式開發Chrome套件
- 編寫可擴充套件程式套件
- Wise Menu for MacFinder擴充套件程式Mac套件
- 設計師對可擴充套件設計工具的探索套件
- OPENWRT擴充套件系統到U盤套件
- Chrome 擴充套件程式的開發與釋出 — 手把手教你開發擴充套件程式Chrome套件
- 點選擴充套件或縮小文字框效果程式碼套件
- WCF擴充套件:行為擴充套件Behavior Extension套件
- 微信小程式測試過程中的各個要點(乾貨)微信小程式
- Chrome擴充套件程式可偷偷竊取你的加密貨幣私鑰Chrome套件加密
- ?用Chrome擴充套件管理器, 管理你的擴充套件Chrome套件
- [Flutter翻譯]如何用Flutter 2.2.3建立Chrome擴充套件外掛FlutterChrome套件
- [外掛擴充套件]微信外掛Wechat1.0套件
- 【Kotlin】擴充套件屬性、擴充套件函式Kotlin套件函式
- flutter開發的乾貨集中營客戶端Flutter客戶端
- 小程式開發實用技巧——擴充套件 Page 頁面物件套件物件
- 如何開發Chrome擴充套件程式Chrome套件
- Chrome第一個擴充套件程式Chrome套件
- CheckBoxList擴充套件方法程式碼套件
- 將單點登入擴充套件到雲套件
- Sanic 擴充套件套件
- ORACLE 擴充套件Oracle套件