1.0 iOS模塊化中的問(wèn)題
前文已經(jīng)介紹了模塊化的流程及一些常見(jiàn)的問(wèn)題,我們?cè)谶@里再次總結(jié)一下。
在工作中,當(dāng)我們開(kāi)始一個(gè)新項(xiàng)目的時(shí)候,最先考慮的就是模塊化工作。
模塊化工作的想法是很美好的,可是執(zhí)行過(guò)程中會(huì)遇到很多的問(wèn)題,而這些問(wèn)題可能會(huì)讓我們?cè)诠ぷ髦信e步維艱。
工具使用問(wèn)題。iOS的模塊化一般會(huì)使用cocoapods工具,這個(gè)工具很強(qiáng)大,內(nèi)容也很豐富,我們想要完成模塊化工作,需要建立私有庫(kù),編寫podspec文件,處理資源,編寫Podfile文件,建立本地依賴等等。讓團(tuán)隊(duì)成員每個(gè)人都精通這個(gè)工具是不必要的。因此經(jīng)常會(huì)在使用工具中遇到不易解決的問(wèn)題,從而浪費(fèi)大量的時(shí)間。
xcode設(shè)置問(wèn)題。xcode設(shè)置項(xiàng)多如牛毛,很多內(nèi)容看起來(lái)并不直觀,需要我們?nèi)ゲ殚喒俜轿臋n來(lái)解決。而且這些設(shè)置數(shù)量多,使用的頻率又少,所以難免會(huì)出現(xiàn)這樣的情況:每個(gè)人都遇到的問(wèn)題,然后各自去花時(shí)間解決,然后過(guò)段時(shí)間遇到相同的問(wèn)題常常就忘記了,還要花時(shí)間去查閱解決,造成資源的重復(fù)浪費(fèi)。
模塊間依賴的問(wèn)題,當(dāng)你依賴的也是
私有庫(kù)的其他模塊(下文中稱為自有模塊)
時(shí),開(kāi)發(fā)中可能要同時(shí)修改多個(gè)模塊,這樣就會(huì)出現(xiàn)在多個(gè)工程中切換的問(wèn)題。規(guī)范問(wèn)題,每個(gè)人建立模塊的方式可能都不同,包括工程結(jié)構(gòu),工程設(shè)置等等。這樣一來(lái),不同的模塊可能差異特別大,當(dāng)跨模塊開(kāi)發(fā)或者代碼交接的時(shí)候,可能就會(huì)出現(xiàn)難以解決的問(wèn)題。
設(shè)置的變更修改都是手動(dòng)修改,有時(shí)候難免會(huì)因?yàn)槭韬?,而?dǎo)致難以發(fā)現(xiàn)的錯(cuò)誤,當(dāng)需要處理的模塊和依賴較多時(shí),發(fā)生錯(cuò)誤的概率也會(huì)增加。
2.0 編寫自動(dòng)化工具
為了解決這些問(wèn)題,讓團(tuán)隊(duì)能夠?qū)⒕θ考械綐I(yè)務(wù)開(kāi)發(fā)中,特使用bash shell開(kāi)發(fā)一個(gè)構(gòu)建工具,用于自動(dòng)化處理模塊化的過(guò)程中遇到的設(shè)置及工具使用問(wèn)題。
工具的地址如下:https://github.com/hardman/AWModularization
使用這個(gè)自動(dòng)化工具你將會(huì)獲得如下能力:
- 一條命令即可創(chuàng)建模塊工程,創(chuàng)建.podspec及Podfile文件,自動(dòng)安裝依賴,工程默認(rèn)使用靜態(tài)庫(kù),支持Swift和OC
- 一條命令即可拉取之前開(kāi)發(fā)的模塊,并且安裝好所有依賴
- 一條命令即可自動(dòng)打tag,自動(dòng)更新.podspec文件,將工程推送到pod服務(wù)器
- 自有模塊的列表,將會(huì)保存在單獨(dú)git庫(kù)中,便于有依賴模塊時(shí),可動(dòng)態(tài)加載
- 自有模塊的依賴都通過(guò).podspec文件使用local path的方式安裝,這樣當(dāng)被依賴的模塊也需要修改時(shí),不需要打開(kāi)多個(gè)工程
因此,使用這個(gè)自動(dòng)化工具,你不需要了解cocoapods工具,也不需要處理任何工程和工具設(shè)置,可以將注意力都集中到業(yè)務(wù)開(kāi)發(fā)中。
【注】工具使用靜態(tài)庫(kù)作為模塊的輸出文件。
3.0 工具的使用
3.1 基本使用步驟
- 將工程clone到本地目錄
- 打開(kāi)
tools/config
修改配置文件- modulelistgitaddress.txt:新建一個(gè)git庫(kù),并將地址保存在這個(gè)文件中,地址最好是以
git@
開(kāi)頭。這個(gè)git庫(kù)用于保存所有自有模塊名稱及地址。 - podspecsaddr.txt:再新建一個(gè)git庫(kù),將地址保存在這個(gè)文件中,地址最好是
git@
開(kāi)頭。這個(gè)git庫(kù)就是你的私有庫(kù)地址。 - podspecsname.txt:為你的git庫(kù)取一個(gè)名字,保存在這個(gè)文件中
- 上述3個(gè)文件都只有一行
- dependencypodrepos.txt:這個(gè)文件保存你的app依賴的其他
pod repos
,一般情況下保持默認(rèn)即可,支持多行,每行保存一個(gè)地址 - 由于這些配置幾乎不會(huì)修改,考慮將這些文件提交到你自己的git庫(kù)中
- modulelistgitaddress.txt:新建一個(gè)git庫(kù),并將地址保存在這個(gè)文件中,地址最好是以
- 執(zhí)行
./create.sh -n=[模塊名] -b=[bundle id] -t=[s|f|r]
即可創(chuàng)建工程- 腳本執(zhí)行過(guò)程中會(huì)要求輸入一些工程基本信息及所依賴的模塊,請(qǐng)認(rèn)真輸入,不要遺漏
- 創(chuàng)建的工程會(huì)自動(dòng)打開(kāi),并且可以直接執(zhí)行
- 創(chuàng)建好的模塊文件在:
工程根目錄/modules
。 - 例:
./create.sh -n=HelloWorld -b=com.helloworld -t=s
- 模塊開(kāi)發(fā)完畢,需要將代碼提交到develop分支,然后執(zhí)行
./push.sh [模塊名] [tag]
- 執(zhí)行push.sh時(shí),模塊必須在develop分支上
- 執(zhí)行成功后,你的模塊就已經(jīng)提交成功,可以通過(guò)Podfile文件引用了
- 例:
./push.sh HelloWorld 0.0.1
- 使用
./pull.sh [模塊名]
即可下載其他未同步到本地的自有模塊- 執(zhí)行成功后,會(huì)自動(dòng)下載所有依賴的模塊,并通過(guò)local path添加到模塊依賴中
- 例:
./pull.sh HelloWorld
3.2 如何提升模塊所依賴其他模塊的版本號(hào)
有的時(shí)候,當(dāng)前模塊所依賴的模塊版本升級(jí)了,需要修改當(dāng)前模塊的依賴文件。
有2種方法:
- 直接修改文件
- 需要修改的文件有2個(gè),一個(gè)是文件根目錄的
dependency.txt
文件,文件內(nèi)記錄了當(dāng)前模塊依賴的自有模塊
。 -
dependency.txt
文件記錄模塊版本的格式是:每行一個(gè)模塊;格式為:模塊名@@版本號(hào)
,版本號(hào)支持~>
前綴,不可帶空格 - 另一個(gè)文件是
模塊名.podspec
文件 - 按照
podspec
文件要求的格式去修改版本號(hào)
- 需要修改的文件有2個(gè),一個(gè)是文件根目錄的
- 使用腳本修改
- 執(zhí)行命令:
./utils.sh [模塊名] upgradedependency [依賴的模塊名] [版本號(hào)]
- 其中版本號(hào)可以為空
- 例子:
./utils.sh LoginModule upgradedependency AFNetworking 3.5.0
- 例子:
./utils.sh LoginModule upgradedependency AFNetworking
- 執(zhí)行命令:
- 版本號(hào)可支持英文字符:a.b.c
3.3 如何在模塊工程內(nèi)使用Swift&OC混編
- 在module工程內(nèi)創(chuàng)建OC的類文件及swift文件,假設(shè)OC類名為 TestOC,swift類名為TestSwift
- 讓OC能夠訪問(wèn)Swift類
- 只需要在TestOC.m中添加import。例:
#import "模塊名/模塊名-Swift.h"
。 - 另外需注意的是,TestSwift類必須是public并繼承自NSObject。
- 只需要在TestOC.m中添加import。例:
- 讓Swift能夠訪問(wèn)OC類
- 在 [模塊名].h 這個(gè)文件中引入你的頭文件。例:
#import "TestOC.h"
。 - 在
xcode - build phases - [模塊名].h
文件必須在public區(qū)域
- 在 [模塊名].h 這個(gè)文件中引入你的頭文件。例:
3.4 關(guān)于模塊資源文件的獲取
- 由于模塊都是靜態(tài)庫(kù),所以最終運(yùn)行到app中后,每個(gè)模塊的資源文件
(.xcassets, .xib, .png, .jpg, .jpeg, .gif, .txt, .plist, .bundle, .zip, .car)
都是放到:"模塊名.bundle"
文件中的,而這個(gè)bundle在main bundle
的根目錄(這也是要求模塊名防止重名的原因之一) - 所以獲取圖片可以使用
UIImage.init(named: name, in: bundle, compatibleWith: nil)
方法 - 獲取其他文件也需要指定bundle才可以
- 開(kāi)發(fā)過(guò)程中,獲取任何資源都需要帶bundle,不能直接使用類似
UIImage.init(named:String)
這種方法,即使是在模塊工程內(nèi)部的代碼也不行 - 需要注意的是,靜態(tài)庫(kù)的單元測(cè)試target是無(wú)法獲取資源的
3.5 注意事項(xiàng)
- 模塊名要防止重復(fù),不但要防止同一個(gè)私有庫(kù)重復(fù),也要防止與其他pod repo內(nèi)的模塊重復(fù)
- 依賴庫(kù)不可產(chǎn)生循環(huán)依賴,比如 A依賴B,B依賴C,C依賴A
- 每個(gè)模塊都有一個(gè)develop分支,develop分支的代碼總是與最新的tag保持一致。執(zhí)行push命令時(shí),代碼總是在develop分支上
- 開(kāi)發(fā)期間(集成測(cè)試前)總是依賴本地模塊,每次總是在集成測(cè)試前,才會(huì)執(zhí)行push.sh腳本
- 如果當(dāng)前的開(kāi)發(fā)模塊有修改,同時(shí)依賴的模塊也有修改,則需要先push當(dāng)前模塊所依賴的模塊,最后push當(dāng)前模塊。這時(shí)候可能需要使用
./utils.sh [模塊名] upgradedependency [依賴的模塊名] [版本號(hào)]
命令修改模塊所依賴的模塊的版本號(hào)
--完--