相關進展:
更多 MXFlutter 資訊,請關注掘金 MXFlutter Team賬號的相關文章 MXFlutter
MXFlutter 自去年釋出預覽版之後,經過不斷優化和重構 v0.2.1 已在iOS 線上APP使用,同時支援 Android 平臺。由於整個框架的複雜性,業務接入步驟繁多,近期經過一系列的改造和重構,現已重構為標準的 Flutter Package,並在昨天上線官方 pub 庫 mxflutter v0.2.1,進一步簡化接入流程,可以簡單三步接入現有專案,開啟由JS編寫的MXFlutter頁面。歡迎小夥伴接入嚐鮮。可以安裝編譯好的 Android 的包來體驗 MXFlutter_v0-1-2.apk
MXFlutter 是一套基於 JavaScript 的 Flutter 動態化框架,是目前開源的最完整可用的動態化方案,它用極類似Dart的開發方式,通過編寫JavaScript 程式碼,來開發 Flutter 應用。程式碼開源在 MXFlutter Github ,更多細節在 基於JavaScript的Flutter框架詳細介紹。
v0.2.1版本新特性
- 升級適配 Flutter 1.17.0 ,對應Channel stable tag:v1.17.0
- 支援Packages
- dio
- pull_to_refresh
- cached_network_image
- shared_preferences
- 支援MessageChannel
- 效能和穩定性優化,Bug Fix
MXFlutter Roadmap
總體目標和方向
- 使用JS開發,擴充套件 Flutter 的開發陣營,實現 Flutter 動態化,
- 支援業務由 Dart 開發,使用mxjsbuilder編譯為JS直接執行,實現同一套 Dart 程式碼同時支援 AOT 編譯為 Native APP,也可以編譯為JS支援動態化。
MXFlutter 當前因為工程量龐大,人力有限,還有很多需要逐步修改優化的地方,更新計劃參照 MXFlutter Roadmap
MXFlutter 接入指南
mxflutter 是一個標準的 Dart package,可以按照 Dart 引入 package 的方式接入,步驟非常簡單。在開始接入之前,執行體驗 mxfltuter 的兩個例子,對接入會有幫助,一個是示例豐富但比較複雜的例子,在 github.com/mxflutter/m… 主庫根目錄,一個是最簡化接入示例,在主庫 mxflutter/example/ 目錄下 ,推薦第一次接入按照第二個例子來。
mxflutter v0.2.1 對應Flutter 1.17.0 (Channel stable tag:v1.17.0)
三步接入MXFlutter
1. 新增依賴
dependencies:
mxflutter: ^0.2.1
複製程式碼
因為mxflutter在快速迭代,推薦 fork 在 github 的主庫 github.com/mxflutter/m… 來接入,方面自己修改和定期從主庫的更新。
dependencies:
mxflutter:
git:
url: https://github.com/mxflutter/mxflutter.git
path: mxflutter/
複製程式碼
2. 拷貝示例JS程式碼檔案,配置JS程式碼資源引入
第一步拷貝JS程式碼檔案:mxflutter 主庫提供了JS程式碼模版,拷貝主庫 mxflutter/example/mxflutter_js_src (github.com/mxflutter/m…) 資料夾到你的工程目錄,和pubspec.yaml檔案同級。
第二步在 pubspec.yaml 檔案中引入 mxflutter_js_src 程式碼資原始檔夾
flutter:
assets:
- mxflutter_js_src/
複製程式碼
特別注意:第一步拷貝的資料夾和第二步匯入的資源是配套的,因為 pubspec.yaml 匯入資源時,不會自動匯入子資料夾, 如果你是拷貝的主庫根目錄 github.com/mxflutter/m… 資料夾,要配套按照主庫 pubspec.yaml 的資源配置來引入,學習接入建議使用 mxflutter/example/mxflutter_js_src 的示例
完成後目錄結構應該是這樣的
my_flutter/
├── lib/
│ └── main.dart
└── pubspec.yaml
└── mxflutter_js_src/
│ └── main.js
│ └── home_page.js
│ └── js_dev_demo.js
│ └── mxjsbuilder_demo.js
複製程式碼
3. 在Flutter程式碼中,執行MXFlutter,開啟由JS編寫的頁面
在 main.dart 檔案中,呼叫 runJSApp 啟動JSApp,runJSApp 函式如果不傳任何引數,預設會執行 mxflutter_js_src/mian.js 檔案
//mxflutter
import 'package:mxflutter/mxflutter.dart';
void main() {
//-------1. MXFlutter 啟動---------
MXJSFlutter.getInstance().runJSApp();
runApp(MyApp());
}
複製程式碼
在合適時機,比如使用者點選介面時,開啟JS頁面。
onTap: () {
//-------2. MXFlutter push 一個使用MXFlutter框架編寫的頁面
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MXJSPageWidget(
jsWidgetName: "MXJSWidgetHomePage")));
}
複製程式碼
上面程式碼 MXJSPageWidget 的引數 jsWidgetName: "MXJSWidgetHomePage",在mxflutter_js_src/main.js MyApp::createJSWidgetWithName 函式中使用,用來標示開啟哪個JS頁面。
bingo 如果順利的話,基本得接入工作已經完成,你應該可以開啟一個經典的 Flutter 示例頁面了。接下來可以嘗試修改下 mxflutter_js_src/ 資料夾下的JS檔案,可以看到 UI 變化。
更多易用的配置
iOS模擬器熱過載支援
在 github.com/mxflutter/m… 主庫iOS工程或者主庫 mxflutter/example/ 目錄的例子中,AppDelegate.m 檔案詳細註釋瞭如果開啟模擬器熱過載。拷貝setupMXFlutterJSPath 函式,在 Flutter 外掛註冊 [GeneratedPluginRegistrant registerWithRegistry:self]; 之前呼叫即可
- (void)setupMXFlutterJSPath{
///mxflutter js程式碼模擬器熱過載支援
///把JS檔案重定向到本地地址,簡單支援模擬器JS檔案熱過載,
///僅支援模擬器環境使用
///*釋出版本的熱更新,也使用同樣API設定為你的JS程式碼下載目錄
#if TARGET_IPHONE_SIMULATOR
//業務JS程式碼的熱過載
NSString *jsAppPath = nil;
NSArray *jsAppSearchPathList = nil;
///mxflutter framework的開發者用來加快除錯,如不需要修改mxflutter jsframework,無需設定jsFramewrokPath
NSString *jsFramewrokPath = nil;
///1. 可以直接修改定位到絕對路徑,但多人協作開發時,每個人路徑不同需要,需要都配置,推薦第二種方法,配置PROJECT_DIR
///jsFramewrokPath = @“/Volumes/Data/Work/mxflutter2/mxflutter/js_lib”;
///jsAppPath = @"/Volumes/Data/Work/mxflutter2/mxflutter_js_src/"
///2. 可以配置PROJECT_DIR,把JS程式碼路徑地址重定向到開發機iMac地址,用來支援模擬器熱過載,支援多人協同,配置PROJECT_DIR方法如下。
///XCode -> Build Settings -> Preprocessor Macros : Debug下增加 PROJECT_DIR=@\""$PROJECT_DIR\/"\"
///這是github https://github.com/TGIF-iMatrix/mxflutter.git 下的 flutter/example/ios 工程為例子,js_lib的
///物理路徑配置如下
#ifdef PROJECT_DIR
//可以根據自己的工程部署調整相對路徑
jsAppPath = [PROJECT_DIR stringByAppendingPathComponent:@"../mxflutter_js_src/"];
//
jsAppSearchPathList = @[
[jsAppPath stringByAppendingPathComponent:@"app_demo/"],
[jsAppPath stringByAppendingPathComponent:@"mxjsbuilder_demo/"]
];
jsFramewrokPath = [PROJECT_DIR stringByAppendingPathComponent:@"../../js_lib/"];
#endif
//可以呼叫[MXFlutterPlugin setJSFramewrokPath:jsFramewrokPath]; 設定jsframework到Documents你的下載目錄,支援framework的熱更新
if (jsFramewrokPath.length > 0) {
[MXFlutterPlugin setJSFramewrokPath:jsFramewrokPath];
}
if (jsAppPath.length > 0) {
[MXFlutterPlugin setJSAppPath:jsAppPath jsAppSearchPathList:jsAppSearchPathList];
}
#endif
}
複製程式碼
APP Demo示例截圖:
先看看使用效果,以下截圖是在MXFlutter框架下用JS開發,可以把上面的原始碼下載下來,裡面有完整的JS程式碼示例:
單頁面演示
下面是UI截圖對應的JS程式碼,沒錯,你沒有眼花,這個是 JavaScript 程式碼,可以在 MXFlutter 的執行時庫上渲染出 Flutter 的UI,(是不是很像Flutter裡面的元件程式碼)!
class JSPestoPage extends MXJSWidget {
constructor() {
super("JSPestoPage");
this.recipes = recipeList;
}
build(context) {
let statusBarHeight = 24;
let mq = MediaQuery.of(context);
if (mq) {
statusBarHeight = mq.padding.top
}
let w = new Scaffold({
appBar: new AppBar({
title: new Text("Pesto Demo")
}),
floatingActionButton: new FloatingActionButton({
child: new Icon(new IconData(0xe3c9)),
onPressed: function () {
},
}),
body: new CustomScrollView({
semanticChildCount: this.recipes.length,
slivers: [
//this.buildAppBar(context, statusBarHeight),
this.buildBody(context, statusBarHeight),
],
}),
//body:this.buildItems()[0]
});
return w;
}
buildAppBar(context, statusBarHeight) {
return SliverAppBar({
pinned: true,
expandedHeight: _kAppBarHeight,
actions: [
IconButton({
icon: new Icon(new IconData(1)),
tooltip: 'Search',
onPressed: function () {
},
}),
],
flexibleSpace: LayoutBuilder({
builder: function (context, constraints) {
size = constraints.biggest;
appBarHeight = size.height - statusBarHeight;
t = (appBarHeight - kToolbarHeight) / (_kAppBarHeight - kToolbarHeight);
extraPadding = new Tween({ begin: 10.0, end: 24.0 }).transform(t);
logoHeight = appBarHeight - 1.5 * extraPadding;
return Padding({
padding: EdgeInsets.only({
top: statusBarHeight + 0.5 * extraPadding,
bottom: extraPadding,
}),
child: Center({
child: new Icon(new IconData(1))
}),
});
},
}),
});
}
buildBody(context, statusBarHeight) {
let mediaPadding = EdgeInsets.all(0);
let mq = MediaQuery.of(context);
if (mq) {
mediaPadding = MediaQuery.of(context).padding;
}
let padding = EdgeInsets.only({
top: 8.0,
left: 8.0 + mediaPadding.left,
right: 8.0 + mediaPadding.right,
bottom: 8.0
});
return new SliverPadding({
padding: padding,
sliver: new SliverGrid({
gridDelegate: new SliverGridDelegateWithMaxCrossAxisExtent({
maxCrossAxisExtent: _kRecipePageMaxWidth,
crossAxisSpacing: 8.0,
mainAxisSpacing: 8.0,
}),
delegate: new SliverChildBuilderDelegate(
function (context, index) {
let recipe = this.recipes[index];
let w = new RecipeCard({
recipe: recipe,
onTap: function () { showRecipePage(context, recipe); },
});
return w;
},
{
childCount: this.recipes.length,
}),
}),
});
}
複製程式碼
專案演示
原始碼中還有更豐滿的示例,高仿知乎頁面JSFlutter版,可以點此進入檢視程式碼:
下圖是對應的UI,已經接近線上上版直接使用了:
聯絡我們
當前 MXFlutter 處於 Beta版本,因為工程量龐大,人力有限,還有很多需要逐步修改優化的地方,目前在高速迭代中,使用 MXFlutter 過程中有任何問題,可以加群交流 QQ群:747535761