將 Flutter module 整合到 iOS 專案
Flutter UI 元件可以漸進式地內嵌到你現有的 iOS 應用中,下面是幾種方法:
-
使用 CocoaPods 依賴管理器安裝 Flutter SDK 使用這種方法,每次建立應用的時候都會從原始碼中編譯
flutter_module
。(推薦) -
建立一個框架,把 Flutter 引擎、已編譯的 Dart 程式碼和所有 Flutter 外掛都放進去 這種方式你可以手動嵌入這個框架,並在 Xcode 中更改現有的應用的建立設定。如果不想要求開發團隊的每一位成員都在本地安裝 Flutter SDK 和 Cocoapods,這種方式比較適用。
-
為已編譯的 Dart 程式碼和所有 Flutter 外掛建立一個框架,對 Flutter 引擎使用 CocoaPods 來管理 這種方式是將應用內容和外掛作為內嵌的框架,但將 Flutter 引擎作為 CocoaPods podspec 分發。這有點類似第二種方式,但是它為分發大型的 Flutter.xcframework 檔案提供了替代方案。
例如使用 UIKit 建立的應用,請參閱 add_to_app 程式碼範例 中 iOS 這個目錄。有關使用 SwiftUI 的範例,請參閱 News Feed App 中的 iOS 目錄。
系統要求
你的開發環境必須滿足 Flutter 對 macOS 系統的版本要求 並 已經安裝 Xcode,Flutter 支援 iOS 12 及以上。此外,你還需要 1.10 或以上版本的 CocoaPods
建立 Flutter module
為了將 Flutter 整合到你的既有應用裡,參考上面的任意方法先建立一個 Flutter module。
在指令行中執行:
cd some/path/
flutter create --template module my_flutter
Flutter module 會建立在 some/path/my_flutter/
目錄。如果你使用上述第一種方法,則應在與現有 iOS 應用工程的父目錄中建立這個 Flutter module。
在這個目錄中,你可以像在其它 Flutter 專案中一樣,執行 flutter
指令。比如 flutter run --debug
或者 flutter build ios
。同樣,你也可以透過 Android Studio/IntelliJ 或者 VS Code
中的 Flutter 和 Dart 外掛執行這個 module,在整合到現有應用前,這個專案在 Flutter module 中包含了一個單檢視的範例程式碼,對 Flutter 側程式碼的測試會有幫助。
Module 的目錄結構
在 my_flutter
module 裡,目錄結構和普通 Flutter 應用類似:
my_flutter/
├── .ios/
│ ├── Runner.xcworkspace
│ └── Flutter/podhelper.rb
├── lib/
│ └── main.dart
├── test/
└── pubspec.yaml
新增你的 Dart 程式碼到 lib/
目錄。
新增 Flutter 依賴到 my_flutter/pubspec.yaml
,包括 Flutter packages 和 plugins。
.ios/
隱藏檔案夾包含了一個 Xcode workspace,用於單獨執行你的 Flutter module。它是一個獨立啟動 Flutter 程式碼的殼工程,並且包含了一個幫助指令碼,用於編譯 framewroks 或者使用 CocoaPods 將 Flutter module 整合到你的既有應用。
在你的既有應用中整合 Flutter module
在你的 module 開發完成後,你就能使用頁面頂部描述的方法將其嵌入到應用中去了。
使用 Flutter 會 增加應用體積 。
選項 A - 使用 CocoaPods 和 Flutter SDK 整合
這個方法需要你的專案的所有開發者,都在本地安裝 Flutter SDK。你的工程在每次建立的的時候,都將會從原始碼裡編譯 Flutter 模組。只需要在 Xcode 中編譯應用,就可以自動執行指令碼來整合 Dart 程式碼和外掛。這個方法允許你使用 Flutter module 中的最新程式碼快速迭代開發,而無需在 Xcode 以外執行額外的指令。
下面的範例假設你的既有應用和 Flutter module 在相鄰目錄。如果你有不同的目錄結構,需要適配到對應的路徑。
some/path/
├── my_flutter/
│ └── .ios/
│ └── Flutter/
│ └── podhelper.rb
└── MyApp/
└── Podfile
如果你的應用下(MyApp
)還沒有 Podfile,請執行 pod init
來建立一個。你可以在 CocoaPods 起步指南
中瞭解更多。
-
在
Podfile
中新增下面程式碼:MyApp/Podfileflutter_application_path = '../my_flutter' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
-
每個需要整合 Flutter 的 Podfile target,執行
install_all_flutter_pods(flutter_application_path)
:MyApp/Podfiletarget 'MyApp' do install_all_flutter_pods(flutter_application_path) end
-
在
Podfile
的post_install
部分,呼叫flutter_post_install(installer)
。MyApp/Podfilepost_install do |installer| flutter_post_install(installer) if defined?(flutter_post_install) end
-
執行
pod install
。
podhelper.rb
指令碼會把你的 plugins,
Flutter.framework
,和 App.framework
整合到你的專案中。
你應用的 Debug 和 Release 編譯設定,將會整合相對應的 Debug 或 Release 的 編譯產物。可以增加一個 Profile 編譯設定用於在 profile 模式下測試應用。
在 Xcode 中開啟 MyApp.xcworkspace
,你現在可以使用 ⌘B
編譯專案了。
選項 B - 在 Xcode 中整合 frameworks
除了上面的方法,你也可以建立必備的 frameworks,手動修改既有 Xcode 專案,將他們整合進去。當你組內其它成員們不能在本地安裝 Flutter SDK 和 CocoaPods,或者你不想使用 CocoaPods 作為既有應用的依賴管理時,這種方法會比較合適。但是每當你在 Flutter module 中改變了程式碼,都必須執行 flutter build ios-framework
。
下面的範例假設你想在 some/path/MyApp/Flutter/
目錄下建立 frameworks:
flutter build ios-framework --output=some/path/MyApp/Flutter/
some/path/MyApp/
└── Flutter/
├── Debug/
│ ├── Flutter.xcframework
│ ├── App.xcframework
│ ├── FlutterPluginRegistrant.xcframework (only if you have plugins with iOS platform code)
│ └── example_plugin.xcframework (each plugin is a separate framework)
├── Profile/
│ ├── Flutter.xcframework
│ ├── App.xcframework
│ ├── FlutterPluginRegistrant.xcframework
│ └── example_plugin.xcframework
└── Release/
├── Flutter.xcframework
├── App.xcframework
├── FlutterPluginRegistrant.xcframework
└── example_plugin.xcframework
在 Xcode 中將生成的 frameworks 整合到你的既有應用中。例如,你可以在 some/path/MyApp/Flutter/Release/
目錄拖拽 frameworks 到你的應用 target 編譯設定的
General > Frameworks, Libraries, and Embedded Content 下,然後在 Embed 下拉清單中選擇 “Embed & Sign”。
連結到框架
例如,你可以將框架從 Finder 的 some/path/MyApp/Flutter/Release/
拖到你的目標專案中,然後點選以下步驟
build settings > Build Phases > Link Binary With Libraries。
在 target 的編譯設定中的
Framework Search Paths (FRAMEWORK_SEARCH_PATHS
)
增加 $(PROJECT_DIR)/Flutter/Release/
。

Embed the frameworks
內嵌框架
生成的動態框架必須嵌入你的應用並且在執行時被載入。
例如,你可以從應用框架組中拖拽框架(除了 FlutterPluginRegistrant 以及其他的靜態框架)到你的目標 ‘ build settings > Build Phases > Embed Frameworks。然後從下拉選單中選擇『Embed & Sign』。
之後它們將出現在 Build Phases 中的 Embed Frameworks 內,如下所示:

你現在可以在 Xcode中使用 ⌘B
編譯專案。
選項 C - 使用 CocoaPods 在 Xcode 和 Flutter 框架中內嵌應用和外掛框架
除了將一個很大的 Flutter.framework 分發給其他開發者、機器或者持續整合 (CI) 系統之外,你可以加入一個引數 --cocoapods
將 Flutter 框架作為一個
CocoaPods 的 podspec 檔案分發。這將會生成一個 Flutter.podspec
檔案而不再生成 Flutter.framework 引擎檔案。如選項 B 中所說的那樣,它將會生成 App.framework 和外掛框架。
要生成 Flutter.podspec
和框架,指令行切換到 Flutter module 根目錄,然後執行以下指令:
flutter build ios-framework --cocoapods --output=some/path/MyApp/Flutter/
some/path/MyApp/
└── Flutter/
├── Debug/
│ ├── Flutter.podspec
│ ├── App.xcframework
│ ├── FlutterPluginRegistrant.xcframework
│ └── example_plugin.xcframework (each plugin with iOS platform code is a separate framework)
├── Profile/
│ ├── Flutter.podspec
│ ├── App.xcframework
│ ├── FlutterPluginRegistrant.xcframework
│ └── example_plugin.xcframework
└── Release/
├── Flutter.podspec
├── App.xcframework
├── FlutterPluginRegistrant.xcframework
└── example_plugin.xcframework
使用 CocoaPods 的宿主應用程式可以將 Flutter 新增到 Podfile 中:
pod 'Flutter', :podspec => 'some/path/MyApp/Flutter/[build mode]/Flutter.podspec'
如選項 B 所述,將生成的 App.xcframework、 FlutterPluginRegistrant.xcframework 以及任何外掛框架,連結並嵌入到你現有的應用程式中。
本地網路隱私權限
在 iOS 14 及更高的版本中,可以在應用程式的 Debug 版本中啟用 Dart 的多播 DNS 服務 (multicast DNS service),透過 flutter attach
新增
除錯功能,如熱過載和 DevTools。
還有一種方式是將每種不同的建立設定,單獨建立對應設定的 Info.plist。下面的說明假定預設為 除錯版本 (Debug) 和 發布版本 (Release)。根據應用程式建立設定的需要調整名稱。
-
將應用程式中的 Info.plist 重新命名為 Info-Debug.plist,再複製一個相同的檔案並重命名為 Info-Release.plist,最後將 Info-Debug.plist、Info-Release.plist 新增到 Xcode 專案中。
-
在 Info-Debug.plist 中 只 新增 key
NSBonjourServices
,並將它的值設定為陣列 (Array),然後在該陣列中新增_dartVmService._tcp
字串 (String)。可以選擇新增 key
NSLocalNetworkUsageDescription
,並設定為你自定義的許可權提示對話框文字。 -
在 target 建立設定中,將 Info.plist File (
INFOPLIST_FILE
) 設定路徑從path/to/Info.plist
改為path/to/Info-$(CONFIGURATION).plist
。這個設定將會在 Debug 時,使用 Info-Debug.plist 的設定,在 Release 時,使用 Info-Release.plist 的設定。
又或者,你可以明確地將 Debug 的路徑設定為 Info-Debug.plist,將 Release 的路徑設定為 Info-Release.plist。
-
如果 Info-Release.plist 在 target 中 Build Settings > Build Phases > Copy Bundle Resources 的時候,請刪除它。
現在 Debug 應用程式會在 Flutter 啟動時提示本地網路許可權。也可以透過開啟 設定 > 隱私與安全性 > 本地網路 > 你的應用程式 來允許該許可權。
arm64
Macs)
Apple Silicon (在使用 Apple Silicon 晶片的 Mac 上 (M1),宿主應用將針對 arm64
架構的模擬器編譯。儘管 Flutter 支援 arm64
的 iOS 模擬器,但一些外掛仍有可能未進行支援。當你在使用這些外掛時,你會遇到 Undefined symbols for architecture arm64 的錯誤,此時你必須從模擬器支援架構中移除 arm64
。
在宿主應用的 Target 中,找到名為 Excluded Architectures (EXCLUDED_ARCHS
) 的建立設定。單擊右側的箭頭指示器圖示以展開可用的建立設定。將滑鼠懸停在 Debug 處並單擊加號圖示。將 Any SDK 更改為 Any iOS Simulator SDK。然後向建立設定值中新增 arm64
。

當全部都正確設定後,Xcode 將會向你的 project.pbxproj 檔案中新增 "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
。
然後對全部 iOS 目標再次執行單元測試。
開發
你現在可以 新增一個 Flutter 頁面 到你的既有應用中。