Flutter 與 iOS 混合專案初探

Inlight發表於2019-12-18

背景

大廠小廠都在搞Flutter,就問你慌不慌!

國內一些混合整合方案的文章大部分都太老了,參考價值不高,並且很容易讓初學者頭大。

前言

本文非闡述Flutter相關的原理,優勢,發展現狀等問題,只介紹在與現有的iOS專案做混合開發的實踐,以及混合過程中的一些坑。目前混合開發已有2個頁面開發完成,等待使用者檢驗。

開發工具

  1. Xcode版本 10.2
  2. Visual Studio Code 1.41.0

環境依賴

Flutter開發環境配置過程就不細說了,官網文件已經寫的很詳細了。

目前使用Flutter SDK版本為 v1.9.1+hotfix.6

環境配置完成後執行 flutter doctor 做下檢查

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel unknown, v1.9.1+hotfix.6, on Mac OS X 10.14.4 18E226,
    locale zh-Hans-CN)
 
[!] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    ! Some Android licenses not accepted.  To resolve this, run: flutter doctor
      --android-licenses
[!] Xcode - develop for iOS and macOS (Xcode 10.2)
    ! CocoaPods out of date (1.6.0 is recommended).
        CocoaPods is used to retrieve the iOS and macOS platform sides plugin
        code that responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To upgrade:
        sudo gem install cocoapods
[✓] Android Studio (version 3.5)
[✓] VS Code (version 1.41.0)
[✓] Connected device (1 available)

! Doctor found issues in 2 categories.

複製程式碼

可以看到要求CocoaPods版本為1.6.0及以上,目前我們在使用1.5.3版本,不過這只是個警告,影響不大,後續升級CocoaPods自然會解決這個問題。

混合方案

混合方案這一塊官方也是經歷了好幾個版本的變更,最初混合的方案比較麻煩,官方文件寫的也不是很詳細,不過在Flutter1.12 釋出後,混合方案文件做了更新,2種混合方案寫的也很簡單易懂。 這裡我們也是採用了官方推薦的方案(使用CocoaPods依賴管理)。

  • 建立Flutter模組(Flutter相關頁面的程式碼都在這裡)。
cd some/path/
flutter create --template module my_flutter
複製程式碼

這裡推薦將Flutter模組跟iOS工程模組放在同級目錄下

some/path/
├── my_flutter/
└── MyApp/
複製程式碼
  • 修改Podfile
  1. CocoaPods依賴本地Flutter模組
flutter_application_path = '../my_flutter'
 load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
複製程式碼
  1. 每個target嵌入Flutter
target 'MyApp' do
   install_all_flutter_pods(flutter_application_path)
 end
複製程式碼
  1. 執行pod install這裡是通過podhelper.rb指令碼將Flutter工程裡面.ios目錄下相關的產物嵌入到iOS工程。
  • Flutter.framework(Flutter engine bundle)
  • App.framework(Dart code)
  • Flutter plugins

相關產物的生成記得在Flutter模組下執行flutter build ios操作。

按照上面3步操作完成後我們可以看到Flutter產物已經整合到iOS工程了

Analyzing dependencies
Fetching podspec for `Flutter` from `../../finance-flutter-module/.ios/Flutter/engine`
Fetching podspec for `FlutterPluginRegistrant` from `../../finance-flutter-module/.ios/Flutter/FlutterPluginRegistrant`
Fetching podspec for `connectivity` from `../../finance-flutter-module/.ios/Flutter/.symlinks/connectivity/ios`
Fetching podspec for `flutter_boost` from `../../finance-flutter-module/.ios/Flutter/.symlinks/flutter_boost/ios`
Fetching podspec for `rrd_flutter` from `../../finance-flutter-module/.ios/Flutter`
Fetching podspec for `url_launcher` from `../../finance-flutter-module/.ios/Flutter/.symlinks/url_launcher/ios`
Downloading dependencies
Installing Flutter (1.0.0)
Installing FlutterPluginRegistrant (0.0.1)
Installing Reachability (3.2)
Installing connectivity (0.0.1)
Installing flutter_boost (0.0.2)
Installing rrd_flutter (0.0.1)
Installing url_launcher (0.0.1)
Generating Pods project
Integrating client project
複製程式碼

解決報錯

完成混合後run工程出現如下error

/Build/Products/Debug-iphonesimulator/investment.app/Frameworks/Flutter.framework: Permission denied
複製程式碼

這裡應該是Flutter1.9的簽名衝突Bug,官方在1.10.2已經修復這個問題。

解決方案有兩種:

  1. 執行 channel master 或者 channel dev 先換個channel用。
  2. 修改Flutter SDK檔案,開啟flutter/packages/flutter_tools/bin/xcode_backend.sh檔案,將
RunCommand find "${derived_dir}/engine/Flutter.framework" -type f -exec chmod a-w "{}" \;
複製程式碼

替換為

RunCommand find "${derived_dir}/engine/Flutter.framework" -type f -iname '.h' -exec chmod a-w "{}" \;
複製程式碼

我們採用了第二種方案,修改後再次run發現工程已經可以執行了,到這裡Flutter和iOS的初步混合已經完成了。

除錯和Hot Reload

flutter attach之後使用終端或者VSCode做Flutter頁面除錯非常方便,這裡還是推薦使用VSCode,畢竟在程式碼和終端之間來回切換不停的按r很煩。

bogon:my_flutter yin$ flutter attach
Checking for advertised Dart observatories...
Waiting for a connection from Flutter on iPhone X...
Done.
Syncing files to device iPhone X...                              1,328ms

?  To hot reload changes while running, press "r". To hot restart (and rebuild
state), press "R".
An Observatory debugger and profiler on iPhone X is available at:
http://127.0.0.1:63823/uO5BqqTmOrE=/
For a more detailed help message, press "h". To detach, press "d"; to quit,
press "q".
複製程式碼

Flutter 與 iOS 混合專案初探
不過Android Studio對Flutter開發除錯支援的要更好,畢竟是同廠出品,會有一些新的除錯功能和特性可以使用,感興趣的同學可以研究下。作為一個用慣了Xcode的人,目前來說VSCode已經可以滿足我的開發需求了,就不去折騰Android Studio,畢竟開發React Native也還是要用VSCode,搞太多IDE怕自己凌亂~

這裡有一點需要注意下就是 flutter attach 之後可能會一直為等待狀態

Checking for advertised Dart observatories...
Waiting for a connection from Flutter on iPhone X...
複製程式碼

這時我們殺掉APP程式重新啟動就可以連線了。這裡猜測是每次Native工程做Flutter相關初始化時候才會做一次attach

總結

我們目前使用的方案是Flutter官方推薦的混合方案,優點缺點並存:

  • 優點:混合整合簡單,混合過程很多事情Flutter官方已經幫我們做好了
  • 缺點:雖然iOS工程倉庫和Flutter Module工程倉庫是分離的,但緊緊做到了程式碼分離,實際執行兩個工程是相互依賴的,也就是iOS和Android端的開發者本地都要安裝一套Flutter環境。

目前這套混合方案還比較適合我們(iOS和Android都為3人)這種較小的團隊,如果團隊人員比較多或者還有Flutter單獨的專案組的話,這種混合方案可能就比較笨重了,當然網上還有一些Flutter混合開發工程化的方案,這裡我們暫時不做討論,後續如果去研究了在做補充吧~

相關連結

Flutter環境配置

官方混合文件

相關文章