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

附帶參考網(wǎng)址:

官方將 Flutter module 集成到 iOS 項(xiàng)目
官方Flutter: iOS Android 原生項(xiàng)目集成 Flutter
看視頻更直接在 iOS 應(yīng)用中添加 Flutter 頁面

Flutter 可以以 framework 框架的形式添加到你的既有 iOS 應(yīng)用中讥脐。

請參閱 add_to_app代碼示例 的 iOS 目錄径缅。

系統(tǒng)要求

你的開發(fā)環(huán)境必須滿足 Flutter 對 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。同樣箭启,你也可以通過 Android Studio/IntelliJ 或者 VS Code 中的 Flutter 和 Dart 插件運(yùn)行這個(gè)模塊壕翩,在集成到現(xiàn)有應(yīng)用前,這個(gè)項(xiàng)目在 Flutter module 中包含了一個(gè)單視圖的示例代碼傅寡,對 Flutter 側(cè)代碼的測試會(huì)有幫助放妈。

模塊組織

my_flutter 模塊北救,目錄結(jié)構(gòu)和普通 Flutter 應(yīng)用類似:

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/ 隱藏文件夾包含了一個(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 重寫铺韧。

由于 .ios/ 目錄是自動(dòng)生成的,因此請勿對其進(jìn)行版本控制灶搜。在新機(jī)器上構(gòu)建 module 時(shí)祟蚀,請?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 依賴管理和已安裝的 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)用,請按照本節(jié)底部的 嵌入框架說明進(jìn)行操作凳怨。

使用 Flutter 會(huì) 增加應(yīng)用體積 瑰艘。

選項(xiàng) A - 使用 CocoaPods 和 Flutter SDK 集成

這個(gè)方法需要你的項(xiàng)目的所有開發(fā)者,都在本地安裝 Flutter SDK肤舞。只需要在 Xcode 中編譯應(yīng)用紫新,就可以自動(dòng)運(yùn)行腳本來集成 dart 代碼和 plugin。這個(gè)方法允許你使用 Flutter module 中的最新代碼快速迭代開發(fā)李剖,而無需在 Xcode 以外執(zhí)行額外的命令芒率。

下面的示例假設(shè)你的既有應(yīng)用和 Flutter module 在相鄰目錄。如果你有不同的目錄結(jié)構(gòu)篙顺,需要適配到對應(yīng)的路徑偶芍。

some/path/
├── my_flutter/
│   └── .ios/
│       └── Flutter/
│         └── podhelper.rb
└── MyApp/
    └── Podfile

如果你的應(yīng)用(MyApp)還沒有 Podfile充择,根據(jù) CocoaPods getting started guide 來在項(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 依賴,需要在 Flutter module 目錄運(yùn)行 flutter pub get萄窜,來更新會(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ì)集成相對應(yīng)的 Debug 或 Release 的 編譯產(chǎn)物穗泵∑掌可以增加一個(gè) Profile 編譯配置用于在 profile 模式下測試應(yīng)用。

小提示

Flutter.framework 是 Flutter engine 的框架佃延, App.framework 是你的 Dart 代碼的編譯產(chǎn)物现诀。

在 Xcode 中打開 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)用的依賴管理時(shí)膘螟,這種方法會(huì)比較合適成福。但是每當(dāng)你在 Flutter module 中改變了代碼,都必須運(yùn)行 flutter build ios-framework荆残。

如果你使用前面的 使用 CocoaPods 和 Flutter SDK 集成奴艾,你可以跳過本步驟。

下面的示例假設(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

請注意

始終使用相同目錄下的 Flutter.frameworkApp.framework内斯∥詹啵混合使用不同目錄(例如 Profile/Flutter.framework 以及 Debug/App.framework)將會(huì)導(dǎo)致運(yùn)行失敗。

小提示

在 Xcode 11 中嘿期,你可以添加 --xcframework --no-universal 參數(shù)來生成 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; (注意添加引號 ")。

你也必須在 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ā)給其他開發(fā)者荷腊、機(jī)器或者持續(xù)集成 (CI) 系統(tǒng)之外,你可以加入一個(gè)參數(shù) --cocoapods 將 Flutter 框架作為一個(gè) CocoaPods 的 podspec 文件分發(fā)踩萎。這將會(huì)生成一個(gè) Flutter.podspec 文件而不再生成 Flutter.framework 引擎文件停局。如選項(xiàng) B 中所說的那樣,它將會(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.

請注意 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)用,請從模擬器支持架構(gòu)中移除 arm64企孩。

在宿主應(yīng)用的 Target 中锭碳,找到名為 Excluded Architectures (EXCLUDED_ARCHS) 的構(gòu)建設(shè)置。單擊右側(cè)的箭頭指示器圖標(biāo)以展開可用的構(gòu)建配置勿璃。將鼠標(biāo)懸停在 Debug 處并單擊加號圖標(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;

然后對全部 iOS 目標(biāo)再次執(zhí)行單元測試莲组。

開發(fā)

你現(xiàn)在可以 添加一個(gè) Flutter 頁面 到你的既有應(yīng)用中诊胞。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锹杈,隨后出現(xiàn)的幾起案子撵孤,更是在濱河造成了極大的恐慌迈着,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邪码,死亡現(xiàn)場離奇詭異裕菠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)闭专,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門奴潘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人喻圃,你說我怎么就攤上這事萤彩。” “怎么了斧拍?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵雀扶,是天一觀的道長。 經(jīng)常有香客問我肆汹,道長愚墓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任昂勉,我火速辦了婚禮浪册,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘岗照。我一直安慰自己村象,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布攒至。 她就那樣靜靜地躺著厚者,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迫吐。 梳的紋絲不亂的頭發(fā)上库菲,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音志膀,去河邊找鬼熙宇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛溉浙,可吹牛的內(nèi)容都是我干的烫止。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼戳稽,長吁一口氣:“原來是場噩夢啊……” “哼馆蠕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤荆几,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后赊时,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吨铸,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年祖秒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诞吱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡竭缝,死狀恐怖房维,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抬纸,我是刑警寧澤咙俩,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站湿故,受9級特大地震影響阿趁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坛猪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一脖阵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧墅茉,春花似錦命黔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至战转,卻和暖如春搜立,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背槐秧。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工啄踊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刁标。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓颠通,卻偏偏與公主長得像,于是被迫代替她去往敵國和親膀懈。 傳聞我的和親對象是個(gè)殘疾皇子顿锰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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