Flutter: iOS Android 原生項(xiàng)目集成 Flutter

附帶參考網(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)用中。

  1. 使用 CocoaPods 依賴(lài)管理和已安裝的 Flutter SDK 。(推薦)

  2. 把 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

  1. <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')
    
    
  2. <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

```
  1. 運(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.frameworkApp.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/

Update Framework Search Paths in Xcode

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”。

Embed frameworks in Xcode

你現(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.

  1. 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
  2. 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
  3. In your target’s build settings, change the Info.plist File (INFOPLIST_FILE) setting path from path/to/Info.plist to path/to/Info-$(CONFIGURATION).plist.

    Set INFOPLIST_FILE build setting

    This will resolve to the path Info-Debug.plist in Debug and Info-Release.plist in Release.

    Resolved INFOPLIST_FILE build setting

    Alternatively, you can explicitly set the Debug path to Info-Debug.plist and the Release path to Info-Release.plist.

  4. 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 phase

    The 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

Set conditional EXCLUDED_ARCHS build setting

當(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)用中。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,637評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,555評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,900評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,629評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,976評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評(píng)論 3 448
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,139評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,686評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,411評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,641評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,820評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,233評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,567評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,362評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,604評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容