做者:閒魚技術-正物java
當前,閒魚客戶端已經實現了基於Flutter的商品詳情頁的全量重構,線上效果良好。從alpha一路走來,咱們遇到了不少問題,或基於原理,或透過社區,或與官方合做,都一個個解決了,是時候梳理和總結下,也但願爲其餘的開發者們,尤爲是已有工程中引入Flutter(混合場景)實現漸進式重構帶來啓發和幫助。 鑑於存在多個問題一個緣由或解法的狀況,而本系列的重點在於說明各類問題的解決方案與思路,就不一一列出問題。全部調試/熱重載相關的Flutter均爲Debug模式的Flutter,再也不特殊說明。android
本系列文章包含三篇:引入篇,運行篇,上線篇。引入篇重點介紹工程研發體系;運行篇介紹混合情景下的棧管理與能力補齊等;上線篇介紹兼容/穩定性保障及方法。ios
工程研發體系的關鍵點包括:git
a.混合工程下的Flutter研發結構github
混合工程中一個全局視角的的研發結構如何。編程
b.工程結構xcode
已有的Native工程如何引入Flutter,工程結構如何組織,如何管理Flutter環境,如何去編譯構建,集成打包等。app
c.構建優化ide
這裏主要介紹如何去針對Flutter的工具鏈(flutter_tools,Intellij插件等)進行調試與優化。模塊化
d.Native啓動下的Flutter調試
不一樣於Flutter啓動下的一體化調試,這種Native啓動(Xcode/Android Studio啓動,或點擊圖標打開應用)下的Flutter調試,我稱之爲分離式調試。分離式調試能夠簡化flutter_tools帶來的複雜度,提升調試的穩定性和靈活性。
e.Native啓動下的Flutter熱重載
同d。
f.聯合調試
即同時調試Flutter和Android/iOS。
g.持續集成
即混合環境下的Flutter構建與持續集成。
#混合工程下的Flutter研發結構
這部分的核心邏輯是如何在最小改動已有iOS/Android工程的前提下運行Flutter。咱們能夠將Flutter部分理解成爲一個單獨的模塊,經過pod庫(iOS),aar庫(Android)的方式,由CocoaPods和Gradle引入到主工程。
具體的原理與實踐請參見:
其中,咱們將整套Flutter環境做爲Git Submodule統一管理,以保證團隊內環境一致,遇到的個性化的問題/需求可以統一處理。
問題:Android在由Flutter啓動時構建緩慢。
緣由:在flutter工具鏈(flutter_tools)的邏輯中,未找到android/app/build.gradle時,會運行gradle build從而執行多個編譯配置的構建,而不是gradle assembleDebug。
解法:重構Android工程,使工程應用Module對應的build.gradle位於android/app下,從而符合flutter_tools的邏輯。
原理:flutter_tools的調試
a.修改flutter_tools.dart,使之可打印參數
b.刪除flutter/bin/cache/flutter_tools.stamp使得flutter_tools能夠被重建
c.從flutter運行構建,獲取其入口參數
d.用Intellij(或Android Studio下同)打開flutter_tools工程,新建Dart Command Line App,並基於步驟c得到的入參配置"Program arguments"
e.開始你的flutter_tools調試之旅吧‘
問題:Flutter構建報"Observatory connection never became ready.",形成構建中斷
緣由:重構前咱們的工程全量編譯時間較長(1000+文件全量編譯時長>10min😭),而Flutter Intellij插件有個超時邏輯,使得構建中斷。
解法a(下策):定製Flutter Intellij插件(修改下面代碼中的超時時間),編譯插件,並替換Android Studio中的Flutter插件。更合理的解法是提PR,但這一路基本上都是在快馬加鞭地解決各類產品化中的問題,因此...(最新版本已去除此邏輯)
原理:
事實上,咱們使用IDE開發Flutter時,有下面的一個邏輯流程:
解法b(中策):iOS工程的模塊拆分和Pod(Framework)化,主工程構建依賴編譯好的Framework,大大加快了構建時間。
原理:模塊化+預編譯Framework
解法c(上策):Native視角下的Flutter調試
原理:Native啓動下,Flutter的調試與熱重載
實際上,當Native工程配置好Flutter支持後,Flutter啓動下作的事情主要有:
a.檢查是否須要從新生成flutter_tools.snapshot。
b.基於pubspec.yaml獲取依賴(pub packages get),並生成插件描述文件.flutter-plugins和pubspec.lock。
c.基於Flutter配置(如Framework路徑,Debug/Release模式,是否開啓Dart2等),生成Generated.xcconfig(iOS)和local.properties(Android)。
d.基於gradle和xcodebuild構建應用(Flutter相關構建請參見前文中深刻理解flutter的編譯原理與優化)。
e.基於adb和lldb啓動應用。
f.等待應用中Flutter啓動,尋找Observatory端口,經過Dart Debugger鏈接以便調試。
g.尋找到端口後同步Hot Reload依賴的文件,同時透過Daemon監聽命令(如用戶點擊插件按鈕)實現Full Restart或Hot Reload。
換個角度來看,若是咱們可以解決Native啓動下的Dart調試和Hot Reload,由flutter_tools形成的編譯慢等問題將不是問題,且可解決調試環境不穩定的狀況(如咱們的場景下,應用啓動後,僅當用戶點擊進入詳情頁面的時候纔會啓動Flutter,此時flutter_tools才能去發現Observatory端口,調試和熱重載,常有很差用的狀況)。當從Xcode啓動(或點擊桌面圖標啓動,再也不重複)包含了Debug模式Flutter內容的iOS(Android Studio啓動Android相似,這裏再也不重複)應用時,咱們須要關注abcfg。而abc除非flutter_tools或pubspec.yaml或Flutter配置變化等,不然都不須要從新執行。fg則是研發依賴的調試與熱重載,必須考慮此模式下如何支持。
a.尋找iOS設備上Observatory端口
或者命令行經過idevicesyslog獲取,此處涉及到libimobiledevice庫,其包含了idevicesyslog,iproxy等命令。
能夠看到iOS設備上Observatory啓動了一個xxxx的端口(端口號隨機)。
b.透過iproxy將iOS設備上端口xxxx映射到本機端口yyyy
c.能夠看到waiting for connection,此時就能夠訪問http://127.0.0.1:yyyy/#/vm打開Observatory以下:
可使用Observatory去檢查諸多dart相關的內存,調試等,這裏不展開。
也能夠經過IDE連接去調試:
d.配置Dart Remote Debug
這裏須要注意的是端口要使用剛轉發到電腦的端口yyyy,搜索源碼路徑是Flutter工程的根目錄。
e.配置好以後點擊Debug按鈕,鏈接到調試端口
f.成功後能夠看到Debugger顯示Connected(若是沒有顯示,再點擊一次綠色的調試按鈕🤦♀️)
g.以後即可以正常地使用IDE設置斷點和調試dart(Flutter)代碼
#Native視角下的Flutter熱重載
a.啓動App,進入Flutter頁面,查找Observatory端口xxxx,並轉發到電腦yyyy(同上面ab)
b.在Flutter工程目錄下,執行flutter attach --debug-port=yyyy
c.修改dart源代碼,而後在b中Terminal中輸入r(這一輸入位於上圖中'To quit,press"q"'以後)
這裏咱們將超讚文案換成了贊。
d.能夠看到Terminal顯示"Initializing hot reload...Reloaded...",結束後,設備上變動生效(左下角文案變成了贊)
Android下,Native啓動的的Flutter調試/熱重載相似iOS,不一樣的是獲取端口時可經過IDE logcat或者adb logcat | grep Observatory,端口轉發使用adb forward。 #Native與Flutter聯調 上文中已經介紹瞭如何在任意時刻(Flutter啓動後)調試Flutter。此外咱們還可使用Android Studio的Attach Debugger to Android Process來調試Android,這就實現了Android與Flutter聯調。一樣,結合Xcode的Attach to Process,能夠實現iOS與Flutter聯調。
目前團隊包括Native同窗和Flutter同窗,所以咱們區分了Flutter模式和Native模式。有一臺公共設備(Mac Mini)安裝了Flutter環境並負責Flutter相關的構建,構建好的產物以aar(Android)或pod庫(iOS)的形式集成到Native工程下(能夠認爲Flutter相關的代碼就是一個模塊),用於構建最終產物apk(Android)或ipa(iOS)的CI平臺最終也經過產物方式集成Flutter並打包。
更多細節請參見:
本文着重介紹了混合場景下的工程研發體系。解決這一問題後,接下來就要解決實際業務開發中遇到的問題。好比Native與Flutter互相跳轉場景下的棧如何管理,Flutter不能實現的功能(平臺特性等)如何去補全,Flutter Plugin/Dart Package包管理的方式有哪些等,這些敬請關注本系列的運行篇。
若是對文本的內容有疑問或指正,歡迎告知咱們。
閒魚技術團隊是一隻短小精悍的工程技術團隊。咱們不只關注於業務問題的有效解決,同時咱們在推進打破技術棧分工限制(android/iOS/Html5/Server 編程模型和語言的統一)、計算機視覺技術在移動終端上的前沿實踐工做。做爲閒魚技術團隊的軟件工程師,您有機會去展現您全部的才能和勇氣,在整個產品的演進和用戶問題解決中證實技術發展是改變生活方式的動力。
簡歷投遞:guicai.gxy@alibaba-inc.com