More Related Content Similar to Flutter 踩雷心得 (20) More from Weizhong Yang (20) Flutter 踩雷心得3. 簡介
• 在 KKBOX 的⼯工程師,之前都在做 KKBOX 在各種蘋果平台
上的版本,包括 iOS、macOS、tvOS 以及 watchOS
• 今年年五⽉月在 KKBOX 成⽴立新部⾨門,部⾨門名稱叫做
eXperimental Design and Development Division - XDDD,
只有兩個⼈人,開發新的實驗性產品
• 因為只有兩個⼈人,因此就會想要研究⼀一些跨平台的 App 開
發框架,並且在今年年七⽉月起在 KKBOX 導⼊入 Flutter
7. Flutter 是什什麼?🤔
• 設計給 Google ⼀一套尚未正式推出的作業系統 Fuchsia 使⽤用
的應⽤用程式框架
• ⽬目前可以被嵌⼊入在 iOS 與 Android app 中執⾏行行,因此也就
成為⼀一套跨平台的應⽤用程式框架
• 架構上,很像是精簡過的瀏覽器器,⽽而在現在的硬體上,有
不不輸給 Native App Framework 的流暢程度
8. 瀏覽器器的組成
• HTML loader:發送 HTTP 連線,抓取 HTML、CSS 檔案
• HTML Parser:將 HTML 解析成 DOM 物件樹
• DOM:⾴頁⾯面元件的 model 物件
• Renderer:將 DOM 繪製到畫⾯面中
• JavaScript Engine:使⽤用 JS 撰寫額外的邏輯,以及操作
DOM,像是加⼊入/刪除節點
9. Flutter 的組成
• Widget:組成畫⾯面的樹狀狀結構
• Stateless Widget:建⽴立之後不不會改動的 Widget
• Stateful Widget:建⽴立之後可以改變內部狀狀態的 Widget
• Renderer:將 Widget 畫出來來
• Dart VM:⽤用來來組成 Widget 的程式語⾔言 runtime
直接使⽤用 code 組出 Widget,不不需要像 HTML tag 這種還要額外解
析的語法
10. 寫起 Flutter 的感覺
• 基本上,就是⾃自⼰己組出 Widget 樹給 Renderer 繪製。沒有
MVC 之分,全都是 view model
• ⾮非常接近 Web 開發中的 SPA,寫過 React、Vue 的⼈人,應
該會對 Flutter 覺得有點親切
11. 拿 Flutter 做產品?
• 越接近 Web app 的 Mobile app,越適合使⽤用 Flutter 開發
• Flutter 專⻑⾧長處理理複雜的 UI 排版,像是⼀一些複雜的表格、圖
⽂文整合的故事⾴頁⾯面,不不同螢幕尺⼨寸要⽤用不不同的版⾯面…⽤用
Native Framework 反⽽而很難做
• 適合像是新聞、電商、聊天室等軟體
12. Flutter 不不適合
• 遊戲:Flutter 基本上不不⿎鼓勵勵⼀一直做畫⾯面的重繪
• 需要⽤用到平台或硬體功能的 app:拍照、錄錄影、錄錄⾳音、媒
體串串流
• 在 iOS 上,你會捨棄 3D Touch、與 watchOS 或其他 iOS
widget 共⽤用 framework
• 需要⼤大量量運算的功能
13. ⽬目前的 Flutter 某些地⽅方還有問題
• 多國語⾔言⽀支援:Dart 的 Localization Engine 只去抓
Language code 與 Country code,所以 iOS 上使⽤用 zh-
Hant,只能抓到 zh,最近才改 (Flutter PR #23583)
• 在 iOS 12 ,中⽂文預設使⽤用很奇怪的明體字…
14. 導⼊入 Flutter 之後 🤔
• 我們還要懂 Native 開發嗎?
• 我們還需要 iOS/Android ⼯工程師嗎?
…我常常被問
16. 導⼊入 Flutter
• 開發
• Dart 程式語⾔言
• 認識 Flutter Widget
• 習慣 Flutter Pattern(如⼤大量量使⽤用 Decorator)
• …知道 Flutter 原廠還有哪些 Bug
• Flutter Plug-in 開發
• Build System
• 測試
18. 發⾏行行版本號碼管理理
• Flutter 預設 iOS/Android App 共⽤用同⼀一個寫在
pubspec.yml 檔案中的版號
• iOS 會寫⼊入到 Info.plist 中
• Anrdrod 會寫⼊入到 gradle 設定中
• 在呼叫 flutter build 指令時,可以指定 —build-name 與 —
build-number
• iOS 正常,Android 就莫名其妙不不⾏行行
19. 編譯流程
• 兩段式的編譯
• 先將 Dart code 編譯成 native code
• 然後
• iOS:拉 Cocoa Pods、在 app bundle 中嵌⼊入 Flutter
framework、編譯 ObjC/Swift code、打包、code sign
• Android:啟動 gradle、安裝 Dependencies 、編譯
Java/Kotlin、proguard、sign APK
20. 混淆 Dart code
• 官⽅方提供⼀一套 Dart Obfuscator
• 但是⽂文件說,還沒有完整測試過
• 在我們⾃自⼰己的專案中,⼀一混淆了了 Dart code,整個 app 跑起
來來就當掉了了…🤣
22. Dependency 管理理
• Flutter 使⽤用 dart pub 管理理套件,但是如果⼀一個 plugin ⽤用到
了了 device channel,iOS ⽤用 CocoaPods 管理理,Android 使⽤用
gradle
• iOS:可能每個 plugin 的 deployment target 不不⼀一樣,需要
⾃自⼰己調整 pod 設定
• Android:可能每個 plugin 使⽤用的 Android API、Kotlin、
Google Service 版本不不同⽽而發⽣生衝突
• 所以你還是要有⼈人懂這些
23. Android 的 32/64 問題
• Flutter 還不不⽀支援 Android App Bundle
• ⼀一次只會編譯 32 或 64 的 libflutter.so
• 開發版本中,可以⽤用 CLI 編出兩種版本
• flutter build apk --debug --target-platform android-arm
• flutter build apk --debug --target-platform android-arm64
• Release 版本⽬目前先只保留留 armv7a 的 NDK…
25. X86 Android
• Flutter 沒有 X86 的 Release Binary
• 但是外⾯面有
• 以卵卵擊⽯石的 x86 Android ⼿手機
• Chromebook
• …去 Google Play 後台禁⽌止這些裝置下載你的 app
26. 環境的版本
• Flutter/Dart 的版本:Dart Pub 上現在很多 package 不不知
元 Dart 2…
• Xcode/iOS SDK 版本:Flutter 還不不⽀支援 Xcode 10 的 New
Build System…
• Android 版本問題:要使⽤用那種 Android SDK?每個 plugin
使⽤用的是哪種 gradle/Kotlin 版本?
• 其中⼀一者發⽣生改動,就整個團隊要更更新開發環境
27. CI
• MS App Center 還不不⽀支援 Flutter app 的設定
• Travis CI 應該要可以,但我搞不不起來來
• 常常遇到無法偵測抓下來來的 flutter runtime 的版本,導致
無法更更新 dependency(pub get 失敗)
• …我們還是在⽤用 Jenkins
28. Testing
• 使⽤用 Flutter 開發,就等於是跟 XCTest、XCUITest 等框架
說再⾒見見了了
• Flutter 有兩種測試框架:
• Dart 的單元測試
• Flutter Widget 測試
29. Dart 單元測試
• 如果是可以獨⽴立運作的 code,建議改寫成獨⽴立的 Dart
package(可以⽤用 stagehand 建⽴立)
• 使⽤用 Flutter 或是直接⽤用獨⽴立的 Dart VM 跑測試都可以,但
是 Flutter 裡頭的⼯工具⽐比較好
• 有 Mockito 做 Mock
• …我直接⽤用 Dart VM 跑測試,怎樣都搞不不出覆蓋率報告出
來來
30. Widget 測試
• 可以把整個 app 的根 widget 跑起來來,或是單獨將⼀一個
widget 包進⼀一個 app 容器器裡頭測試。檢查⼀一些⾏行行為之後,
畫⾯面中是否有出現對應的 widget
• 不不好寫:Flutter 基本上禁⽌止在結束測試的時候,widget 當
中還有⾮非同步的 code 在執⾏行行,會丟出 exception
• ⼀一個可以跑 Widget Test 的 Widget,基本上要把所有⾮非同
步的操作都 mock 掉
32. 線上問題的處理理
• 如果在 Dart VM 裡頭發⽣生邏輯錯誤,不不會產⽣生 crash log 回
報,只會直接在 app 裡頭畫出紅畫⾯面,在發⽣生問題時,增
加解決問題的難度
• Flutter 的 exception 往往也不不會直接告訴你在 code 的哪
段,⽽而是 renderer 當中丟出的 exception
• 有些事情你想不不到:在 ListView 裡頭使⽤用 StatefulWidget
會跳出 Exception…
34. 建議在新專案導⼊入 Flutter
• 在原本的 iOS/Android app 上導⼊入 Flutter,技術上可⾏行行,
iOS/Android app 可以嵌⼊入 Flutter view。
• 但是軟體⼯工程上很麻煩
• Flutter app 要求將跨平台的 code/平台專屬的 code 區隔
開來來,在軟體架構上相當具有挑戰
• 平台專屬的 code 也要維持同⼀一個介⾯面,讓 Dart code 可
以呼叫,也就是,iOS/Android app 基本上要使⽤用同⼀一套
架構設計
35. 團隊的組成
• 基本上要有夠資深的 iOS/Android ⼯工程師
• 搞定 codesign、發⾏行行上架等問題
• 要每個⼯工程師同時懂兩個平台很難
• 下⼀一步,就是這兩個⼯工程師應該還要有各⾃自的代理理,之後可以加⼊入
只寫 Dart 的⼈人
• 先以⼤大量量的單元測試加上 QA ⼿手動測試為主
• 因為 Flutter 的 Widget Test 實在很難寫,⽽而且有地⽅方還測不不到…
36. 改變思維
• Flutter 的 Controller 不不是 iOS 的 Controller
• iOS 的 Controller 是畫⾯面的基本單位
• Flutter 的 Widget ⾃自成天地,當外部想操作某個 Widget 時,才提供
⼀一個 Controller 當做接⼝口
• Flutter 的 delegate 不不是 iOS 的 delegate
• iOS 的 delegate 是集中處理理 callback 的物件,在 Flutter 中則使⽤用
builder function 或是
• Flutter 的 delegate 像是 Widget 的設定
37. 改變思維
• 在 iOS 上,如果有個連線,我們可能會在 ViewController
中呼叫 NSURLSession 以及 NSURLSessionTask
• 在 Flutter 中,我們的作法可能是把⽤用到這個連線的畫⾯面⽤用
FutureBuilder 包起來來
• <Furture><Widget>….</Future>