頭條 Flutter iOS 混合工程實(shí)踐

體驗(yàn) Flutter

從 App Store 下載或更新頭條(6.9.2 或以上版本),找到 懂車帝 -> 熱門車型,點(diǎn)擊打開(kāi)后即可體驗(yàn) Flutter 的頁(yè)面效果延旧。

由于前期業(yè)務(wù)改造順利埋酬,線上 Crash 少,性能良好碘勉,目前我們正在進(jìn)行小視頻模塊的 Flutter 重構(gòu)巷挥,即將上線。

本文主要介紹頭條 iOS 端在接入 Flutter 的過(guò)程中验靡,選擇的技術(shù)方案倍宾,遇到的問(wèn)題和未來(lái)的計(jì)劃雏节。雖然是以 iOS 為例,但很多內(nèi)容都是雙端通用的高职。

Flutter 基礎(chǔ)

為了方便對(duì) Flutter 零基礎(chǔ)讀者閱讀本文钩乍,首先介紹一些 Flutter 的基礎(chǔ)知識(shí)。

當(dāng)我們寫(xiě)完 Dart 代碼后怔锌,需要編譯后才能給客戶端使用寥粹。Flutter 的產(chǎn)物分為兩種模式,一個(gè)是 Debug 模式埃元,采用 JIT(Just In Time)的方式涝涤,類似于解釋型語(yǔ)言,好處是可以支持熱更新岛杀,方便調(diào)試阔拳。另一種是 AOT(Ahead Of Time)模式,類似于編譯型語(yǔ)言类嗤,好處是性能比較好糊肠。

因此在開(kāi)發(fā)中,我們一般使用 Debug 模式的產(chǎn)物來(lái)提升調(diào)試效率遗锣,正式上線后再換成 Release 模式獲得極致的性能货裹。不管是哪種模式,在 iOS 下的產(chǎn)物都是三個(gè)(安卓類似):

  1. App.framework:和 flutter 的業(yè)務(wù)邏輯相關(guān)精偿,在 Debug 模式下就是一個(gè)很小的空殼弧圆,在 Release 模式下包含全部業(yè)務(wù)邏輯
  2. flutter_assets:也和 flutter 的業(yè)務(wù)邏輯相關(guān),在 Debug 模式下包含全部業(yè)務(wù)邏輯还最,在 Release 模式下很小墓阀。
  3. Flutter.framework:實(shí)現(xiàn) Flutter 框架自己的邏輯

iOS 工程接入 Flutter 的已有方案

目前主流的方案中主要有兩種,一種在 Google 的官方文檔里 拓轻,它最大的問(wèn)題在于斯撮, 需要?jiǎng)?chuàng)建一步 BUILD PHASE 調(diào)用 shell 腳本去編譯 Flutter。編譯 Flutter 的過(guò)程需要本機(jī)有 Flutter 環(huán)境才行扶叉。

這顯然是不能接受的勿锅。其實(shí)我們先不考慮 Flutter 這件事,不管是搭建什么類型的混合工程枣氧,都一定要保證以下兩點(diǎn):

  1. 對(duì)原生工程無(wú)侵入:原生工程可以增加組件的依賴溢十,但不能修改主工程的配置,更不能讓原生工程對(duì)環(huán)境產(chǎn)生新的依賴达吞。
  2. 方便調(diào)試:不管是原生工程開(kāi)發(fā)张弛,調(diào)試新接入的模塊(比如 Flutter),還是模塊開(kāi)發(fā)調(diào)試原生工程,都應(yīng)該支持?jǐn)帱c(diǎn)調(diào)試吞鸭。

很明顯寺董,官網(wǎng)的方案不滿足第一點(diǎn)要求,我們不能讓每個(gè)參與原生工程開(kāi)發(fā)的同學(xué)刻剥,本機(jī)都安裝 Flutter 環(huán)境遮咖。

Flutter 的官網(wǎng)教程 中可以看到,它支持 flutter run 命令或者從 IDE 啟動(dòng) iOS 工程造虏。其實(shí)只要觀察一下 ios 目錄下的 Runner.xcworkspace 工程就會(huì)發(fā)現(xiàn)御吞,F(xiàn)lutter 項(xiàng)目運(yùn)行的就是這個(gè)工程。當(dāng)然如果直接把我們的 iOS 工程拷貝過(guò)來(lái)是無(wú)法運(yùn)行的漓藕。

至少在目前最新的 dev 分支(Tag:v0.10.0)上是不行的陶珠,因?yàn)?flutter 的代碼中寫(xiě)死了工程的名字就是 Runner,可以驗(yàn)證一下:

這也就催生了目前主流的撵术,也是閑魚(yú)最先介紹的方案背率,魔改 Flutter 源碼,讓它能運(yùn)行自己的工程嫩与。然而個(gè)人覺(jué)得這種方式還是太 trick,主要有兩個(gè)問(wèn)題:

  1. 后續(xù)如果 Flutter 升級(jí)了交排,還得把修改的部分應(yīng)用到新的分支上去划滋,并且修復(fù)沖突。
  2. 如果公司或者業(yè)內(nèi)有別的團(tuán)隊(duì)要用埃篓,接入成本比較高处坪。

頭條的混合工程方案

觀察一下 Runner 的工程結(jié)構(gòu):

再看一眼 Flutter 編譯腳本就會(huì)發(fā)現(xiàn),這一步并不是必須放在主工程的 BUILD 階段進(jìn)行架专。只要擁有 Flutter 的編譯產(chǎn)物同窘,項(xiàng)目就可以接入 Flutter 的功能了。因此頭條選擇的方案是:

  1. 利用 flutter build iosflutter build ios --debug 命令部脚,先后構(gòu)建兩種模式下的產(chǎn)物并上傳到 CDN
  2. 構(gòu)建一個(gè) Pod想邦,并且讓 Pod 依賴上述產(chǎn)物

在第一步中,運(yùn)行 flutter build ios 實(shí)際上會(huì)依賴 Runner 工程委刘,相當(dāng)于是我們借助這個(gè)空殼去得到產(chǎn)物丧没。不過(guò)要想編譯通過(guò),還需要做如下兩個(gè)微小的改動(dòng):

  1. 修改項(xiàng)目的 Bundle ID锡移,使用自己的證書(shū)呕童。否則無(wú)法通過(guò)簽名
  2. 打開(kāi) Xcode -> File -> Workspace -> Setting,把 BUILD_SYSTEM 切換為 Legacy淆珊,否則會(huì)產(chǎn)生編譯錯(cuò)誤

第二步中夺饲,重點(diǎn)在于如何讓 Pod 動(dòng)態(tài)的下載資源,因?yàn)樾枰付ㄊ褂媚膫€(gè)版本,哪種模式的 Flutter 產(chǎn)物往声。我們目前的策略是在打包機(jī)器上使用 Release 模式產(chǎn)物擂找,在開(kāi)發(fā)機(jī)器上使用 Debug 模式產(chǎn)物。

至于動(dòng)態(tài)指定版本號(hào)烁挟,可以這樣寫(xiě):

s.prepare_command = "bash ./BDFlutterDownload.sh"
s.vendored_frameworks = 'Framework/*.framework'
s.resources = 'Framework/flutter_assets'

通過(guò) prepare_command 語(yǔ)法婴洼,可以在 Pod Install 的過(guò)程中執(zhí)行 shell 腳本,把產(chǎn)物下載到 Framework 文件夾中撼嗓,只要把版本號(hào)寫(xiě)到腳本中柬采,并且及時(shí)更新就可以了。

調(diào)試 Flutter

上述方案解決了 Flutter 工程接入的問(wèn)題且警,因?yàn)槭蔷幾g后的資源接入粉捻,我們還需要保證 Flutter 開(kāi)發(fā)的同學(xué)可以正常調(diào)試。這里以最新的 dev 分支舉例(Tag:v0.10.0)斑芜。

如果是 Flutter 開(kāi)發(fā)的同學(xué)肩刃,不關(guān)心 iOS 開(kāi)發(fā)的細(xì)節(jié),可以找到打包后的 app 文件杏头,然后使用 ? flutter run --use-application-binary? 指定被調(diào)試應(yīng)用的路徑:

如果是 iOS 開(kāi)發(fā)的同學(xué)盈包,使用 Xcode 運(yùn)行項(xiàng)目即可。這兩種方式下醇王,都可以看到本地調(diào)試的端口(圖中的 57674)呢燥。

如果是使用編譯好的 app 來(lái)運(yùn)行,可以直接使用 r/R 來(lái)實(shí)現(xiàn)熱刷新/熱重啟寓娩。如果使用 Xcode 運(yùn)行項(xiàng)目叛氨,需要先使用命令: ?flutter attach --debug-port=57674 ?。

如果需要在 iOS 側(cè)打斷點(diǎn)棘伴,必須用 Xcode 運(yùn)行項(xiàng)目寞埠。如果需要在 Dart 側(cè)打斷點(diǎn),可以利用 IDE 的 Debug 功能焊夸。這里以 VSCode 為例仁连,首先安裝 Dart 插件。


Flutter.png
想學(xué)習(xí)更多Android知識(shí)淳地,或者獲取相關(guān)資料請(qǐng)加入Android技術(shù)開(kāi)發(fā)交流2群:935654177怖糊。本群可免費(fèi)獲取Gradle,RxJava颇象,小程序伍伤,Hybrid,移動(dòng)架構(gòu)遣钳,NDK扰魂,React Native,性能優(yōu)化等技術(shù)教程!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末劝评,一起剝皮案震驚了整個(gè)濱河市姐直,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蒋畜,老刑警劉巖声畏,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異姻成,居然都是意外死亡插龄,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門科展,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)均牢,“玉大人,你說(shuō)我怎么就攤上這事才睹∨枪颍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵琅攘,是天一觀的道長(zhǎng)垮庐。 經(jīng)常有香客問(wèn)我,道長(zhǎng)坞琴,這世上最難降的妖魔是什么突硝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮置济,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锋八。我一直安慰自己浙于,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布挟纱。 她就那樣靜靜地躺著羞酗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪紊服。 梳的紋絲不亂的頭發(fā)上檀轨,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音欺嗤,去河邊找鬼参萄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛煎饼,可吹牛的內(nèi)容都是我干的讹挎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼筒溃!你這毒婦竟也來(lái)了马篮?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤怜奖,失蹤者是張志新(化名)和其女友劉穎浑测,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體歪玲,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡迁央,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了读慎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漱贱。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖夭委,靈堂內(nèi)的尸體忽然破棺而出幅狮,到底是詐尸還是另有隱情,我是刑警寧澤株灸,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布崇摄,位于F島的核電站,受9級(jí)特大地震影響慌烧,放射性物質(zhì)發(fā)生泄漏逐抑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一屹蚊、第九天 我趴在偏房一處隱蔽的房頂上張望厕氨。 院中可真熱鬧,春花似錦汹粤、人聲如沸命斧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)国葬。三九已至,卻和暖如春芹壕,著一層夾襖步出監(jiān)牢的瞬間汇四,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工踢涌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留通孽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓斯嚎,卻偏偏與公主長(zhǎng)得像利虫,于是被迫代替她去往敵國(guó)和親挨厚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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