MXFlutter上線Flutter pub.dev 三步接入現有工程

SoapY 發表於 2020-05-09

MXFlutter上線Flutter pub.dev 三步接入現有工程


相關進展:

更多 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
    1. dio
    2. pull_to_refresh
    3. cached_network_image
    4. 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 變化。

MXFlutter上線Flutter pub.dev 三步接入現有工程

更多易用的配置

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下增加 [email protected]\""$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程式碼示例:

單頁面演示

MXFlutter上線Flutter pub.dev 三步接入現有工程

下面是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版,可以點此進入檢視程式碼:

zhihu/home/home_page.js

下圖是對應的UI,已經接近線上上版直接使用了:

MXFlutter上線Flutter pub.dev 三步接入現有工程

聯絡我們

當前 MXFlutter 處於 Beta版本,因為工程量龐大,人力有限,還有很多需要逐步修改優化的地方,目前在高速迭代中,使用 MXFlutter 過程中有任何問題,可以加群交流 QQ群:747535761

qrcode