【Flutter】iOS混搭Flutter

【Flutter】iOS混搭Flutter

打從 Swift 出來之前(等等,明明是個 Android 工程師,怎麼跑來弄 Swift 呢?),就有許多的跨平台方案被提了出來,PhoneGap、Xamarin,等等的(完全暴露年紀),原先對這些方案都抱持著嗤之以鼻的態度,畢竟效能低落、開發成本也沒有比較低,對於雙平台還需各別處理一些東西,能省下的工其實也沒多少。直到最近碰上了 Flutter...

雖然說 Flutter 也不能解決所有跨平台的問題,但至少對於畫出雙平台一致的畫面,產生一樣的使用者經驗還是可以的,並且擁有豐富的套件庫,很多效果基本上不用自己硬寫,找一下套件修改一下就可以直接使用了。

這篇主要講的是如何把寫好的 Flutter 專案整合進 iOS 專案裡面,讓兩者可以交互使用,所以會先假設大家的環境都已配置完成,並有一個以可以執行的 Flutter 專案。那麼,就開始吧!

#方案選擇

根據 Flutter 官網,要將 Flutter 整合進 iOS 專案裡面有三種選擇

  1. 利用 CocoPods 跟 Flutter SDK
  2. 將 Flutter 專案打包成 Framework 供 iOS 專案叫用
  3. 利用 CocoPods 在 iOS 專案和 Flutter 中內嵌應用和外掛

這邊我們用看似比較簡單的 Framework 方式。

#產出 Framework

首先,打開 cmd 切換到你的 Flutter 專案目錄底下,並輸入以下指定讓 Flutter 來產出專案的 Framework 檔案,其中 output 為你希望產出的檔案放在哪裡,這邊我設定在桌面的 flutter_framework 資料夾下:

flutter build ios-framework --output=/Users/jeremy/Desktop/flutter_framework
產出 Framework 指令

而當你看到下面畫面,表示 Framework 已經順利產生完成,接著就可以把產出的檔案直接複製進 iOS 的專案底下,然後就可以打開 Xcode 來進行整合的部分。

💪 Building with sound null safety 💪

Building frameworks for com.jeremyhuang.flutter in debug mode...
 ├─Copying Flutter.xcframework...                                  343ms
 ├─Building App.xcframework...                                     20.3s
 ├─Building plugins...                                             15.4s
 └─Moving to ../../flutter_framework/Debug                   105ms
Building frameworks for com.jeremyhuang.flutter in profile mode...
 ├─Copying Flutter.xcframework...                                  243ms
 ├─Building App.xcframework...                                     65.0s
 ├─Building plugins...                                             16.5s
 └─Moving to ../../flutter_framework/Profile                 115ms
Building frameworks for com.jeremyhuang.flutter in release mode...
 ├─Copying Flutter.xcframework...                                1,171ms
 ├─Building App.xcframework...                                     62.0s
 ├─Building plugins...                                             16.6s
 └─Moving to ../../flutter_framework/Release                 175ms
Frameworks written to /Users/jeremy/Desktop/flutter_framework.
產出過程

#整合 iOS 專案及 Flutter Framework

接著打開 Xcode,並切換到目標 target 的 Build Settings > Build Phases > Link Binary With Libraries 部分,這時候可以直接將剛剛產出的 flutter_framework 裡面 Release (如果要 build 在模擬器上則是要用 Debug 的)底下的 Frameworks,以拖拉的方式拖進 Xcode 裡的 Link Binary With Libraries,如下圖所示。

Link Binary With Libraries

而下方的 Embed Frameworks 也一樣要加入這些 Frameworks ,直接點選下方的加號把 Frameworks 都選起來就可以了。

Embed Frameworks

如果找不到 Embed Frameworks 的話,可能要先切到 General 頁籤,並把 Frameworks, Libraries, and Embedded Content 底下的 Embed 類別改成 Embed & Sign,設定完再切回 Build Phases 頁籤,應該就會看到了。

Frameworks, Libraries, and Embedded Content

下一步我們將頁籤切換到 Build Settings,找到 Search Paths 並將 Frameworks 的路徑加入到 Framework Search Paths 裡,我這邊填入的是 $(PROJECT_DIR)/Flutter/Release/

Framework Search Paths

#添加 Flutter 畫面

準備就緒後就可以讓 iOS 專案呼叫 Flutter 的畫面起來了,這邊希望一開 App 的時候就可以跳出 Flutter 的畫面為目標。首先打開 AppDelegate.swift 檔案,先將 Flutter import 進來,創建 FlutterEngine ,並在 application() 裡把他 run 起來。

AppDelegate.swift

再來,打開 ViewController.swift 檔案,一樣先 import flutter,接著要利用 FlutterViewController 來將畫面呈現,如下所示:

ViewController.swift

至此,可以先把程式跑起來看看有沒有問題。

#GeneratedPluginRegistrant

如果你有使用一些插件的話,在 build 的時候可能會噴 MissingPluginException 的錯誤,這時候需要回到剛剛 Flutter 產出的那包 Frameworks 資料夾下,找到 GeneratedPluginRegistrant.h 及 GeneratedPluginRegistrant.m 兩個檔案,一樣用拖拉的方式,拖拉進 Xcode 左側的目錄結構裡,這時候 Xcode 應該會自動產生一個 ${Project_Name}-bridging-Header.h 的檔案,沒有的話就自己建立一個,並在裡面寫上:

#import "GeneratedPluginRegistrant.h"
${Project_Name}-bridging-Header.h

接著回到 AppDelegate.swift 檔案,在剛剛的 flutterEngine.run(); 下面多加一行:

GeneratedPluginRegistrant.register(with: self.flutterEngine);
AppDelegate.swift

如此一來,再重新 build 一次應該就可以了。至此,大功告成 🎉

參考