附帶參考網(wǎng)址:
官方將 Flutter module 集成到 iOS 項(xiàng)目
官方Flutter: iOS Android 原生項(xiàng)目集成 Flutter
看視頻更直接在 iOS 應(yīng)用中添加 Flutter 頁(yè)面
Flutter 可以以 framework 框架的形式添加到你的既有 iOS 應(yīng)用中。
請(qǐng)參閱 add_to_app代碼示例 的 iOS 目錄。
系統(tǒng)要求
你的開(kāi)發(fā)環(huán)境必須滿(mǎn)足 Flutter 對(duì) macOS 系統(tǒng)的版本要求 并 已經(jīng)安裝 Xcode,F(xiàn)lutter 支持 iOS 8.0 及以上。此外,你還需要 1.10 或以上版本的 CocoaPods
創(chuàng)建 Flutter module
為了將 Flutter 集成到你的既有應(yīng)用里,第一步要?jiǎng)?chuàng)建一個(gè) Flutter module。
在命令行中執(zhí)行:
cd some/path/
flutter create --template module my_flutter
Flutter module 會(huì)創(chuàng)建在 some/path/my_flutter/
目錄。在這個(gè)目錄中,你可以像在其它 Flutter 項(xiàng)目中一樣,執(zhí)行 flutter
命令。比如 flutter run --debug
或者 flutter build ios
。同樣,你也可以通過(guò) Android Studio/IntelliJ 或者 VS Code 中的 Flutter 和 Dart 插件運(yùn)行這個(gè)模塊,在集成到現(xiàn)有應(yīng)用前,這個(gè)項(xiàng)目在 Flutter module 中包含了一個(gè)單視圖的示例代碼,對(duì) Flutter 側(cè)代碼的測(cè)試會(huì)有幫助。
模塊組織
在 my_flutter
模塊,目錄結(jié)構(gòu)和普通 Flutter 應(yīng)用類(lèi)似:
my_flutter/
├── .ios/
│ ├── Runner.xcworkspace
│ └── Flutter/podhelper.rb
├── lib/
│ └── main.dart
├── test/
└── pubspec.yaml
添加你的 Dart 代碼到 lib/
目錄。
添加 Flutter 依賴(lài)到 my_flutter/pubspec.yaml
,包括 Flutter packages 和 plugins。
.ios/
隱藏文件夾包含了一個(gè) Xcode workspace,用于單獨(dú)運(yùn)行你的 Flutter module。它是一個(gè)獨(dú)立啟動(dòng) Flutter 代碼的殼工程,并且包含了一個(gè)幫助腳本,用于編譯 framewroks 或者使用 CocoaPods 將 Flutter module 集成到你的既有應(yīng)用。
提示
iOS 代碼要添加到你的既有應(yīng)用或者 Flutter plugin中,而不是 Flutter module 的 .ios/
目錄下。 .ios/
下的改變不會(huì)集成到你的既有應(yīng)用,并且這有可能被 Flutter 重寫(xiě)。
由于 .ios/
目錄是自動(dòng)生成的,因此請(qǐng)勿對(duì)其進(jìn)行版本控制。在新機(jī)器上構(gòu)建 module 時(shí),請(qǐng)?jiān)谑褂?Flutter module 構(gòu)建 iOS 項(xiàng)目之前,先于 my_flutter
目錄運(yùn)行 flutter pub get
以生成 .ios/
目錄。
在你的既有應(yīng)用中集成 Flutter module
這里有兩種方式可以將 Flutter 集成到你的既有應(yīng)用中。
使用 CocoaPods 依賴(lài)管理和已安裝的 Flutter SDK 。(推薦)
把 Flutter engine 、你的 dart 代碼和所有 Flutter plugin 編譯成 framework 。用 Xcode 手動(dòng)集成到你的應(yīng)用中,并更新編譯設(shè)置。
提示 Your app does not run on a simulator in Release mode because Flutter does not yet support outputting x86/x86_64 ahead-of-time (AOT) binaries for your Dart code. You can run in Debug mode on a simulator or a real device, and Release on a real device.
你的應(yīng)用將不能在模擬器上運(yùn)行 Release 模式,因?yàn)?Flutter 還不支持將 Dart 代碼編譯成 x86/x86_64 ahead-of-time (AOT) 模式的二進(jìn)制文件。你可以在模擬機(jī)和真機(jī)上運(yùn)行 Debug 模式,在真機(jī)上運(yùn)行 Release 模式。
要在模擬器上運(yùn)行您的應(yīng)用,請(qǐng)按照本節(jié)底部的 嵌入框架說(shuō)明進(jìn)行操作。
使用 Flutter 會(huì) 增加應(yīng)用體積 。
選項(xiàng) A - 使用 CocoaPods 和 Flutter SDK 集成
這個(gè)方法需要你的項(xiàng)目的所有開(kāi)發(fā)者,都在本地安裝 Flutter SDK。只需要在 Xcode 中編譯應(yīng)用,就可以自動(dòng)運(yùn)行腳本來(lái)集成 dart 代碼和 plugin。這個(gè)方法允許你使用 Flutter module 中的最新代碼快速迭代開(kāi)發(fā),而無(wú)需在 Xcode 以外執(zhí)行額外的命令。
下面的示例假設(shè)你的既有應(yīng)用和 Flutter module 在相鄰目錄。如果你有不同的目錄結(jié)構(gòu),需要適配到對(duì)應(yīng)的路徑。
some/path/
├── my_flutter/
│ └── .ios/
│ └── Flutter/
│ └── podhelper.rb
└── MyApp/
└── Podfile
如果你的應(yīng)用(MyApp
)還沒(méi)有 Podfile,根據(jù) CocoaPods getting started guide 來(lái)在項(xiàng)目中添加 Podfile
。
-
<t translation-result="on" style="box-sizing: border-box; margin-bottom: 0.6rem;">在
Podfile
中添加下面代碼:</t>Add the following lines to your
Podfile
:content_copy
flutter_application_path = '../my_flutter' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
<t translation-result="on" style="box-sizing: border-box; margin-bottom: 0.6rem;">每個(gè)需要集成 Flutter 的 [Podfile target][],執(zhí)行
install_all_flutter_pods(flutter_application_path)
:</t>
```
target 'MyApp' do
install_all_flutter_pods(flutter_application_path)
end
```
-
運(yùn)行
pod install
。提示
當(dāng)你在
my_flutter/pubspec.yaml
改變了 Flutter plugin 依賴(lài),需要在 Flutter module 目錄運(yùn)行flutter pub get
,來(lái)更新會(huì)被podhelper.rb
腳本用到的 plugin 列表,然后再次在你的應(yīng)用目錄some/path/MyApp
運(yùn)行pod install
.
podhelper.rb
腳本會(huì)把你的 plugins, Flutter.framework
,和 App.framework
集成到你的項(xiàng)目中。
你應(yīng)用的 Debug 和 Release 編譯配置,將會(huì)集成相對(duì)應(yīng)的 Debug 或 Release 的 編譯產(chǎn)物。可以增加一個(gè) Profile 編譯配置用于在 profile 模式下測(cè)試應(yīng)用。
小提示
Flutter.framework
是 Flutter engine 的框架, App.framework
是你的 Dart 代碼的編譯產(chǎn)物。
在 Xcode 中打開(kāi) MyApp.xcworkspace
,你現(xiàn)在可以使用 ?B
編譯項(xiàng)目了。
選項(xiàng) B - 在 Xcode 中集成 frameworks
除了上面的方法,你也可以創(chuàng)建必備的 frameworks,手動(dòng)修改既有 Xcode 項(xiàng)目,將他們集成進(jìn)去。當(dāng)你組內(nèi)其它成員們不能在本地安裝 Flutter SDK 和 CocoaPods,或者你不想使用 CocoaPods 作為既有應(yīng)用的依賴(lài)管理時(shí),這種方法會(huì)比較合適。但是每當(dāng)你在 Flutter module 中改變了代碼,都必須運(yùn)行 flutter build ios-framework
。
如果你使用前面的 使用 CocoaPods 和 Flutter SDK 集成,你可以跳過(guò)本步驟。
下面的示例假設(shè)你想在 some/path/MyApp/Flutter/
目錄下創(chuàng)建 frameworks:
flutter build ios-framework --xcframework --no-universal --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
請(qǐng)注意
始終使用相同目錄下的 Flutter.framework
和 App.framework
。混合使用不同目錄(例如 Profile/Flutter.framework
以及 Debug/App.framework
)將會(huì)導(dǎo)致運(yùn)行失敗。
小提示
在 Xcode 11 中,你可以添加 --xcframework --no-universal
參數(shù)來(lái)生成 XCFrameworks,而不是使用通用的 framework。
在 Xcode 中將生成的 frameworks 集成到你的既有應(yīng)用中。例如,你可以在 some/path/MyApp/Flutter/Release/
目錄拖拽 frameworks 到你的應(yīng)用 target 編譯設(shè)置的 General > Frameworks, Libraries, and Embedded Content 下,然后在 Embed 下拉列表中選擇 “Embed & Sign”。
鏈接到框架
例如,你可以將框架從 Finder 的 some/path/MyApp/Flutter/Release/
拖到你的目標(biāo)項(xiàng)目中,然后點(diǎn)擊以下步驟 build settings > Build Phases > Link Binary With Libraries。
在 target 的編譯設(shè)置中的 Framework Search Paths (FRAMEWORK_SEARCH_PATHS
) 增加 $(PROJECT_DIR)/Flutter/Release/
。
Embed the frameworks
內(nèi)嵌框架
生成的動(dòng)態(tài)框架必須嵌入你的應(yīng)用并且在運(yùn)行時(shí)被加載。
重點(diǎn)提醒
插件會(huì)幫助你生成 靜態(tài)或動(dòng)態(tài)框架。靜態(tài)框架應(yīng)該直接鏈接而不是嵌入。如果你在應(yīng)用中嵌入了靜態(tài)框架,你的應(yīng)用將不能發(fā)布到 App Store 并且會(huì)得到一個(gè) Found an unexpected Mach-O header code 的 archive error。
例如,你可以從應(yīng)用框架組中拖拽框架(除了 FlutterPluginRegistrant 以及其他的靜態(tài)框架)到你的目標(biāo) ‘ build settings > Build Phases > Embed Frameworks。然后從下拉菜單中選擇 “Embed & Sign”。
你現(xiàn)在可以在 Xcode中使用 ?B
編譯項(xiàng)目。
小提示
如果你想在 Debug 編譯配置下使用 Debug 版本的 Flutter frameworks,在 Release 編譯配置下使用 Release 版本的 Flutter frameworks,在 MyApp.xcodeproj/project.pbxproj
文件中,嘗試在所有 Flutter 相關(guān) frameworks 上使用 path = "Flutter/$(CONFIGURATION)/example.framework";
替換 path = Flutter/Release/example.framework;
(注意添加引號(hào) "
)。
你也必須在 Framework Search Paths (FRAMEWORK_SEARCH_PATHS
) 編譯設(shè)置中使用 $(PROJECT_DIR)/Flutter/$(CONFIGURATION)
。
選項(xiàng) C - 使用 CocoaPods 在 Xcode 和 Flutter 框架中內(nèi)嵌應(yīng)用和插件框架
除了將一個(gè)很大的 Flutter.framework 分發(fā)給其他開(kāi)發(fā)者、機(jī)器或者持續(xù)集成 (CI) 系統(tǒng)之外,你可以加入一個(gè)參數(shù) --cocoapods
將 Flutter 框架作為一個(gè) CocoaPods 的 podspec 文件分發(fā)。這將會(huì)生成一個(gè) Flutter.podspec
文件而不再生成 Flutter.framework 引擎文件。如選項(xiàng) B 中所說(shuō)的那樣,它將會(huì)生成 App.framework 和插件框架。
flutter build ios-framework --cocoapods --xcframework --no-universal --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
Host apps using CocoaPods can add Flutter to their Podfile:
pod 'Flutter', :podspec => 'some/path/MyApp/Flutter/[build mode]/Flutter.podspec'
Embed and link the generated App.xcframework, FlutterPluginRegistrant.xcframework, and any plugin frameworks into your existing application as described in Option B.
Local Network Privacy Permissions
On iOS 14 and higher, enable the Dart multicast DNS service in the Debug version of your app to add debugging functionalities such as hot-reload and DevTools via flutter attach
.
請(qǐng)注意 This service must not be enabled in the Release version of your app, or you may experience App Store rejections.
One way to do this is to maintain a separate copy of your app’s Info.plist per build configuration. The following instructions assume the default Debug and Release. Adjust the names as needed depending on your app’s build configurations.
-
Rename your app’s Info.plist to Info-Debug.plist. Make a copy of it called Info-Release.plist and add it to your Xcode project.
Info-Debug.plist and Info-Release.plist in Xcode -
In Info-Debug.plist only add the key
NSBonjourServices
and set the value to an array with the string_dartobservatory._tcp
. Note Xcode will display this as “Bonjour services”.Optionally, add the key
NSLocalNetworkUsageDescription
set to your desired customized permission dialog text.Info-Debug.plist with additional keys -
In your target’s build settings, change the Info.plist File (
INFOPLIST_FILE
) setting path frompath/to/Info.plist
topath/to/Info-$(CONFIGURATION).plist
.Set INFOPLIST_FILE build settingThis will resolve to the path Info-Debug.plist in Debug and Info-Release.plist in Release.
Resolved INFOPLIST_FILE build settingAlternatively, you can explicitly set the Debug path to Info-Debug.plist and the Release path to Info-Release.plist.
-
If the Info-Release.plist copy is in your target’s Build Settings > Build Phases > Copy Bundle Resources build phase, remove it.
Copy Bundle build phaseThe first Flutter screen loaded by your Debug app will now prompt for local network permission. The permission can also be allowed by enabling Settings > Privacy > Local Network > Your App.
Local network permission dialog
Apple Silicon (arm64
Macs)
Flutter 目前暫未支持 arm64
的 iOS 模擬器。要在 Apple Silicon Mac 設(shè)備上運(yùn)行你的宿主應(yīng)用,請(qǐng)從模擬器支持架構(gòu)中移除 arm64
。
在宿主應(yīng)用的 Target 中,找到名為 Excluded Architectures (EXCLUDED_ARCHS
) 的構(gòu)建設(shè)置。單擊右側(cè)的箭頭指示器圖標(biāo)以展開(kāi)可用的構(gòu)建配置。將鼠標(biāo)懸停在 Debug 處并單擊加號(hào)圖標(biāo)。將 Any SDK 更改為 Any iOS Simulator SDK。然后向構(gòu)建設(shè)置值中添加 arm64
。
當(dāng)全部都正確設(shè)置后,Xcode 將會(huì)向你的 project.pbxproj 文件中添加 "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
。
然后對(duì)全部 iOS 目標(biāo)再次執(zhí)行單元測(cè)試。
開(kāi)發(fā)
你現(xiàn)在可以 添加一個(gè) Flutter 頁(yè)面 到你的既有應(yīng)用中。