深入談一談iOS模塊獨(dú)立運(yùn)行

背景

最近一直在團(tuán)隊(duì)推進(jìn)關(guān)于iOS模塊獨(dú)立運(yùn)行相關(guān)的事項(xiàng),想把最近的一些想法和實(shí)施情況通過(guò)這篇文章做一個(gè)記錄。

如果在一個(gè)項(xiàng)目中,某一塊代碼足夠獨(dú)立(功能、業(yè)務(wù)上),就會(huì)傾向于將他通過(guò)Cocoapods抽離為一個(gè)pods文件。通過(guò)一個(gè)podspec文件描述這個(gè)pod的信息。

最直接的方式就是把相關(guān)文件組織好遷移到一個(gè)目錄下,通過(guò)podspec對(duì)源碼位置,資源位置等信息的描述,完成一個(gè)最簡(jiǎn)單直白的pod創(chuàng)建。

并且在Podfile中通通過(guò)

pod 'XXX', :path => '~/dev/XXX'

這種方式,集成到主工程進(jìn)行開(kāi)發(fā)。開(kāi)發(fā)自測(cè)完成后通過(guò)私有repo發(fā)布,并且將Podfile中的指向版本

pod 'XXX', '1.0.0'

然后我們就會(huì)說(shuō),抽離了一個(gè)庫(kù),項(xiàng)目的代碼結(jié)構(gòu)變得更合理更清晰了。

但這么做,在我看來(lái)跟在項(xiàng)目里直接用group把這些代碼區(qū)別開(kāi)來(lái)沒(méi)什么區(qū)別,反而要修改的時(shí)候還要重新git pull、pod install變得更加麻煩了。

因?yàn)檫@么做被分離的代碼無(wú)法獨(dú)立運(yùn)行,而且由于依賴不清晰,沒(méi)辦法共享給其他項(xiàng)目使用,導(dǎo)致這種分離方式是一種偽解耦,該有的益處沒(méi)有展現(xiàn)出來(lái),修改的時(shí)候反倒更加麻煩,這絕對(duì)不是我們想要的效果。

由此引出對(duì)模塊獨(dú)立運(yùn)行

對(duì)iOS模塊獨(dú)立運(yùn)行的思考

Pod帶來(lái)的受益的預(yù)期

個(gè)人心目中完美的Pod應(yīng)該在這四個(gè)維度上做到最好。

  • 依賴足夠清晰
    清楚的描述自己的依賴狀況。說(shuō)到這個(gè)不得不吐槽一個(gè)iOS項(xiàng)目與Cocoapods結(jié)合之后一個(gè)奇怪的現(xiàn)象,就是Pod如果在主工程中通過(guò)path引入的,那么,在不聲明清楚自身以來(lái)的情況下,可以使用主工程內(nèi)所有類,甚至是主工程的類,并且不會(huì)得到任何提示,這種情況很普遍,并且事后想要理清依賴的成本極高,這個(gè)Pod算是廢了(沒(méi)有了抽離Pod的意義了)。

  • 方便共享給其他項(xiàng)目使用
    我的理解,抽離Pod的很大一個(gè)目的不就是為了共享嗎?如果不是為了這個(gè)目的,其實(shí)沒(méi)必要抽離Pod的,反而更加麻煩了,只跟一個(gè)項(xiàng)目綁死的Pod在我看來(lái),完全沒(méi)有必要做成Pod,項(xiàng)目里放在Group就可以了。而為了能達(dá)到這個(gè)目的需要克服很多的困難。

  • 方便快速修改驗(yàn)證
    隨著主工程越來(lái)越大,編譯速度越來(lái)越慢,開(kāi)發(fā)效率也在無(wú)形之中慢慢降低。Pod從主工程中脫離出來(lái)獨(dú)立運(yùn)行,單獨(dú)編譯,隔絕對(duì)主工程的依賴,完全自給自足,這樣代碼編譯量就會(huì)大大降低,達(dá)到開(kāi)發(fā)效能提高的目的。

  • 自身質(zhì)量保障
    在第三點(diǎn)的基礎(chǔ)上,帶上完全針對(duì)這個(gè)Pod的單元測(cè)試UI測(cè)試,完美顆?;a的同時(shí),還能很好的保障自身的質(zhì)量,并且清晰易維護(hù),這塊如果配合Xcode Server,會(huì)發(fā)揮強(qiáng)大的優(yōu)勢(shì)。

然而要做到這些維度上的最好,需要克服很多問(wèn)題,接下來(lái)慢慢道來(lái)。

兩種類型的代碼

類似AFNetworking、SDWebImage這樣的功能型代碼,分離的一個(gè)只需要確保自己的依賴清晰,被依賴的時(shí)候使用方便就可以了。而對(duì)于偏業(yè)務(wù)型的代碼就不那么容易了,通常會(huì)有界面,還會(huì)有各種業(yè)務(wù)帶來(lái)的附加產(chǎn)物,例如打點(diǎn),例如網(wǎng)絡(luò)庫(kù)各種規(guī)則。

因?yàn)楣δ苄痛a本身對(duì)于以上四點(diǎn)門檻不高,我就不展開(kāi)討論了,主要還是展開(kāi)說(shuō)一下業(yè)務(wù)型代碼。

業(yè)務(wù)型代碼獨(dú)立運(yùn)行的看法

推進(jìn)業(yè)務(wù)型代碼獨(dú)立運(yùn)行過(guò)程中遇到的一些問(wèn)題列舉:

獨(dú)立運(yùn)行問(wèn)題
  1. 業(yè)務(wù)代碼需要用到 打點(diǎn)、網(wǎng)絡(luò)等基本能力,背后每個(gè)能力都可能牽扯出一堆間接依賴,但這些依賴跟這個(gè)Pod本身沒(méi)任何屁關(guān)系,同時(shí)還會(huì)是不是的出現(xiàn)間接依賴不明確導(dǎo)致的編譯報(bào)錯(cuò)問(wèn)題。

  2. 作為已經(jīng)是獨(dú)立可運(yùn)行的Pod了,界面什么的都自己hold了,那么它一定還需要跟其他本身之外的幾面進(jìn)行交互,舉個(gè)例子,一個(gè)Product的Pod,需要跳轉(zhuǎn)到Order中的一個(gè)界面,或者Chat中的一個(gè)界面,而這個(gè)界面在代碼層面根本不存在,要如何處置。

  3. 之前也提到了,一個(gè)依賴清晰的獨(dú)立運(yùn)行Pod如果被不小心path方式開(kāi)發(fā)了一次,那么這個(gè)Pod會(huì)慢慢變廢,下次運(yùn)行可能就不能運(yùn)行了,所以還要想辦法要怎么不被path依賴。

  4. 還有一個(gè)比較頭疼的問(wèn)題是,隨著業(yè)務(wù)迭代,某個(gè)冷門的獨(dú)立運(yùn)行Pod并沒(méi)有跟上腳步,其直接依賴的功能庫(kù)在主工程都更新了,但它卻全然不知,難道還要一個(gè)一個(gè)校對(duì)嗎?

  5. 解決了基礎(chǔ)能力的間接依賴,各種必要的直接依賴的間接依賴也會(huì)出現(xiàn)不明確而出現(xiàn)的編譯失敗問(wèn)題,需要解決,確保只有代碼api需要更新時(shí)才會(huì)編譯不過(guò),才是最爽的開(kāi)發(fā)流程。

思考實(shí)施解決之道

實(shí)施過(guò)程中開(kāi)發(fā)了兩套工具來(lái)解決。均未開(kāi)源,外網(wǎng)勿搜。下面介紹詳細(xì)思路。

腳手架工具 - gearmaker

避免被path模式開(kāi)發(fā)

好不容建了一個(gè)獨(dú)立運(yùn)行Pod,要是不小心被不明真相的同學(xué)用path開(kāi)發(fā)了就糟了。如何避免被path模式開(kāi)發(fā)呢?如果是源碼模式下,其實(shí)是做不到的。所以我們把每個(gè)獨(dú)立運(yùn)行的Pod的產(chǎn)物定位二進(jìn)制庫(kù),靜態(tài)動(dòng)態(tài)都可,podspec層面就不允許指向源碼,想要修改源碼,只能通過(guò)獨(dú)立運(yùn)行的工程進(jìn)行修改。

具體操作這里不展開(kāi)了,如果podspec指向的是靜態(tài)庫(kù),而沒(méi)有源碼指向則這個(gè)Pod理論上不可能不可被path模式開(kāi)發(fā)。

而如果通過(guò)Cocoapods 官方建議的 pod lib create 方式創(chuàng)建,則Pod代碼會(huì)存在于 Development Pods 下,而必須在podspec中指定源碼路徑,因此我修改了 pod lib create 的腳手架模板,將Pod代碼直接放入項(xiàng)目的一個(gè)Group中,而Group對(duì)應(yīng)產(chǎn)物是一個(gè)framework,podspec直接指向podspec,外加Universal打包腳本就可以啦。

有同學(xué)有疑問(wèn)了,那源碼調(diào)試怎么辦呢?這個(gè)不用擔(dān)心,既然Pod已經(jīng)可以獨(dú)立運(yùn)行,有什么問(wèn)題需要調(diào)試,是都可以在Pod工程中進(jìn)行數(shù)據(jù)Mock來(lái)還原問(wèn)題的,所以主工程只是用來(lái)集成,不需要考慮調(diào)試問(wèn)題。

即便是特別特殊的情況,只在主工程能還原,那臨時(shí)加一下podspec指向本地path做一下debug也是可以的。

版本仲裁 & 保鮮

Pod獨(dú)立運(yùn)行工程的一大詬病就是時(shí)間一長(zhǎng),工程就無(wú)法編譯通過(guò)運(yùn)行了,并且哪些依賴需要更新,需要詳細(xì)對(duì)比,成本非常高,很多遇到這樣情況就會(huì)放棄Pod工程。

為此gearmaker中集成了版本仲裁能力,通過(guò)hook pod命令,在pod install之前,計(jì)算出指定客戶端主工程最新的依賴全集,在pod install時(shí),在這個(gè)全集中找到仲裁版本來(lái)使用。

這樣一來(lái),pod install后的Pod工程所有依賴必然與主工程一致,只需要修改因?yàn)橐蕾嚫聨?lái)的相關(guān)api變更即可通過(guò)編譯正常運(yùn)行,確保Pod工程不會(huì)腐敗。

依賴切斷 服務(wù)提供組件 - ServiceProvider

所有Pod只需要直接依賴ServiceProvider,由ServiceProvider來(lái)統(tǒng)一提供服務(wù)能力,包括Pod工程本身需要的任何能力。比如,路由、打點(diǎn)、網(wǎng)絡(luò)、從另一個(gè)模塊獲取數(shù)據(jù),獲取一個(gè)View對(duì)象等,均不需要依賴其他庫(kù),直接從ServiceProvider中通過(guò)內(nèi)置的protocol來(lái)獲得,并使用。

提供能力的一方對(duì)預(yù)先放置在ServiceProvider中的protocol進(jìn)行功能實(shí)現(xiàn),通過(guò)以下方式將自身的能力注冊(cè)入ServiceProvider,即可為其他提供能力,而不需要依賴。

注冊(cè)服務(wù)

[ServiceProvider registService:[XMUserTrack class] withProtocol:@protocol(UserTrack)];

獲取服務(wù)

id<UserTrack> ut = [ServiceProvider serviceWithProtocol:@protocol(UserTrack)];

使用體驗(yàn)

對(duì)于新的Pod創(chuàng)建,直接使用以下命令創(chuàng)建:

gearmaker <PodName>

根據(jù)命令行提示進(jìn)行創(chuàng)建即可。創(chuàng)建完成的腳手架直接提供了ServiceProvider,開(kāi)發(fā)同學(xué)直接從ServiceProvider中獲取服務(wù)進(jìn)行Pod開(kāi)發(fā),開(kāi)發(fā)完成后通過(guò)Universal腳本生成framework上傳到私有repo中定版本即可直接使用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • iOS CocoaPods組件平滑二進(jìn)制化方案及詳細(xì)教程 感謝"fly2never_寶貝別哭"??梢允褂胏ocoa...
    曹俊_413f閱讀 12,904評(píng)論 6 83
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,733評(píng)論 25 709
  • 項(xiàng)目組件化、平臺(tái)化是技術(shù)公司的共同目標(biāo),越來(lái)越多的技術(shù)公司推崇使用pod管理第三方庫(kù)以及私有組件,一方面使項(xiàng)目架構(gòu)...
    swu_luo閱讀 22,827評(píng)論 0 39
  • 比如大名鼎鼎的ReactCocoa。切到早期版本,你根本找不到podspec,說(shuō)明它從未官方支持過(guò)CocoaPod...
    曹俊_413f閱讀 2,919評(píng)論 5 7
  • 不記得是多久沒(méi)有拿過(guò)筆寫(xiě)字,也不記得上一篇自己用心寫(xiě)的文章是在何時(shí)了。然而文字總是有一種說(shuō)不清的魅力,即使時(shí)間荒蕪...
    低吟淺唱度流年閱讀 134評(píng)論 0 0

友情鏈接更多精彩內(nèi)容