2個多月前,我開始探索flutter的使用方法,並用flutter對已有app進行集成,遇到了一些困惑,也摸索出一些解決問題的方法,希望可以幫助到大家。

注意

作為Google推出的移動跨平台框架,flutter跟隨開發者的腳步不斷迭代更新,這篇文章具有時效性,我從flutter穩定版本v1.2.1開始接觸,目前最新的版本是v1.5.4-hotfix.2。


flutter module更新時間線

2018年2月22日

issue 14821中出現了關於「如何在已有app上進行混合開發並減少摩擦」的討論,因為有很多開發者並不想直接把現有app直接替換成flutter,而是想在現有應用程序上添加一個或多個flutter屏幕進行使用。

https://github.com/flutter/flutter/issues/14821

2018年4月6日

flutter wiki上出現了第一篇關於《如何在已有app添加flutter並持續更新》的文章。

https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps

2018年6月22日

發起了第一個關於flutter module的pull request,只能用於Android上,並在flutter v0.5.6加入stable。

https://github.com/flutter/flutter/pull/18697

更多

flutter團隊一直在對已有app集成做持續跟進,你可以在 github.com/flutter/flut 看到最新進展。


flutter和native混合開發解決方案

現在flutter可以用module的方式對現有app進行集成,你可以參照上面的wiki,這非常容易做到。github.com/flutter/flut

如果你是獨立開發者,那麼直接用官方wiki上的接入方式不會有太大問題。但如果在一個團隊協作中,這樣的做法有可能就不那麼友好了,因為這不僅會侵入native工程,還有可能產生一些問題。我們該怎麼解決呢?

iOS以cocoapods通過ruby的eval binding方式接入,並需要加入run script,因為podhelper.rb中存在post_install,如果原工程也有post_install,就會出現如下錯誤

[!] Invalid `Podfile` file: [!] Specifying multiple `post_install` hooks is unsupported..

需要如何解決,詳見

https://github.com/flutter/flutter/issues/26212#issuecomment-477487234

Android的處理方法和iOS有所不同。它以子module方式接入,需要settings.gradle和build.gradle添加依賴,在以子module接入時,會產生一些問題。如果原工程有添加自定義buildTypes和flavor等功能選項,就需要在相應的module中補上自定義buildTypes和flavor。以module方式創建的flutter項目,.android是被gitignore的,每次通過flutter packages get自動生成,就不太好做版本控制,當然你可以選擇使用「git add -f.」,flutter module中每引入一個plugin就會在原生Android項目中產生一個module,如果依賴多個那就會產生多個module,這需要補上非常多的buildType和falavor,管理起來也不是特別方便。

一個好的flutter混合項目的需要具備哪些

  • flutter可以不依賴native獨立開發,debug快速便捷
  • native可以非常簡單的集成並不破壞原項目,也不需要添加flutter環境,當然能以其他SDK,framework的通用接入方式是最好
  • flutter開發完成能release bundle供native端進行使用,也就是第二點需要達到的目的

改造flutter module

我們需要對flutter module進行改造來滿足更多工作上的需求,flutter module本身可以不依賴native進行獨立開發,並且能快速便捷的debug。所以第一點目的達到了。

這裡推薦使用Android Studio進行flutter開發,因為Android Studio的Flutter插件功能更強大(雖然我更喜歡VSCode),比如flutter inspector, flutter outline等等。

iOS目前集成外部framework的方式有Cocoapods, Carthage等,Android使用Maven是最方便的。很多開發者都關心這個問題:能不能把flutter module在iOS中導出.framework .a,在Android中導出.aar 然後使用cococapods和meaven進行接入?答案是肯定的,後面會有詳細的說明。

寫到這裡上述兩點都能得到解決,但還遺留了一些問題。因為flutter目前還不支持單個flutter engine進行多個窗口繪製,參考wiki,如果需要接入多個窗口(iOS:FlutterViewController, Android: FltterActivity, FlutterFragment),就需要初始化多個flutter engine,隨之帶來的就是內存消耗不斷增加。

該如何實現單個flutter engine支持多窗口繪製呢?阿里開源了解決上述問題的flutter plugin:flutter_boost (github.com/alibaba/flut)

這裡我們需要給module添加flutter_boost依賴。引入flutter_boost也隨之帶來了一些需要優化問題:比如在flutter側進行獨立開發不是特別友好,破壞了原本入口結構。要如何解決會在後面細說。

如何構建一個混合項目

github.com/JaminZhou/fl

為了看起來更直觀,我把flutter和native項目融合到了一起,實際開發中,兩者應使用不同的倉庫來管理。

示例分為三部分1. flutter 2. native 3. release腳本+repo。

flutter里包含1. module 2. plugin 3. example(module方式接入flutter,實際可有可無,因為會產生重複)

首先繼續解決「如何對引入flutter_boost進行優化」的問題,我是這樣處理的:添加了開發環境,對flutter_boost和其他一些需要用到native的plugin進行隔離,不受native限制直接進行flutter的開發。

因此,我加入了`main_dev.dart`,用於區分隔離開發和生產環境,在Android Studio添加一個新的Flutter Configuation,Dart enrtypoint指向main_dev.dart

接下來需要解決「如何和native進行交互」的問題。

首先請把FlutterView想像成WebView,我們是如何和前端進行協作開發的?客戶端和前端將各自獨立開發互不干擾,客戶端和前端約定好JSBridge用於數據交互,然後在客戶端的WebView容器中指定url就可以展示相應內容,並可以進行Remote Debug。回到Flutter,我們已經有了flutter_boost用於展示FlutterView,還欠缺類似於JSBridge用於數據交互的橋樑,所以我們需要自定一個自己的plugin用戶數據交互。

我在plugins里創建了一個flutter_bridge,它的功能和JSBridge一樣。

想知道plugin和底層是如何交互的可以看這篇文章

flutter.dev/docs/develo

flutter.dev/docs/develo

在flutter_bridge中,我用protocol(iOS), abstract class(Android)定義好類似於JSBridge的協議,然後運用runtime調用實現方法(runtime會增加開發效率,但性能上又還是直接用if else或者switch case更好,見仁見智,諸君可以自行選擇)。

我在iOS中還添加了`FLBFlutterViewContainer`的Category,用於隱藏導航欄。當FLBFlutterViewContainer消失,就會回到之前導航欄的狀態,目的是想讓flutter自行控制導航欄的事件,UI等等。

flutter團隊也提供了很多plugin, package(純dart),如果沒有滿足你的需求,你也可以開發自己的plugin和package

github.com/flutter/plug

pub.dev/

負責flutter的同學開發完項目,如何把成果輸出給native端呢?

回想一下,當寫Web端同學開發完,他可以部署到伺服器,只需要把最後的url移動端的人接入即可;寫ReactNative的同學開發完也可以導出JSBundle讓移動端的同學接入。

那flutter可以導出哪些東西呢?

flutter提供了對iOS,Android的導出命令 `flutter build ios --release`和`flutter build android --release`,,一般都在module目錄下的build文件夾,在.ios/Flutter和.android/Flutter/build目錄下能找到以下這些:

  • iOS:lib{plugin_name}.a App.framework Flutter.framework
  • Android:flutter-release.aar {plugin_name}-release.aar

所以,iOS我們可以輸出成cocoapods,Android上傳到maven,這也是release_ios.sh和release_android.sh做的一些事情。需要注意的是執行flutter build xxx --release 輸出的.a .framework .aar不會包含x_86架構,所以模擬器不能運行(Flutter.framework是個例外,無論release還是debug導出都會有x_86),我們也可以輕鬆解決這些問題(flutter build xxx --debug .a也不會包括x_86,可以用`xcrun xcodebuild build -configuration Debug ARCHS=x86_64 xxxxx`)

如何使用自動化發布腳本詳見flutter-native-hybrid的README.md


注意事項

  • 暫時不要用macOS Catalina(10.15 beta)進行開發,在release的時候會產生一些問題。不過只要不進行release操作,正常開發還是可以的(我目前暫時沒有發現問題,有問題你們可以反饋到評論中)。Issues when using macos 10.15 & ios 13(github.com/flutter/flut
  • 目前flutter_boost還沒正式發布flutter v1.5.4-hotfix.2的適配版本 github.com/alibaba/flut 所以可以使用flutter v1.2.1 開發 或者使用flutter_boost的flutter_1.5_upgrade_opt分支github.com/alibaba/flut

參考文獻

github.com/flutter/flut

github.com/flutter/flut

github.com/flutter/flut

github.com/flutter/flut

github.com/flutter/plug

pub.dev/

推薦閱讀:

相关文章