項(xiàng)目背景
項(xiàng)目需求:
在已有項(xiàng)目A的前提下,抽離出一個(gè)和項(xiàng)目A有公共業(yè)務(wù)甚至模塊的項(xiàng)目B勘伺,對(duì)于公共業(yè)務(wù)和模塊當(dāng)然是想維護(hù)一份代碼實(shí)現(xiàn)兩個(gè)項(xiàng)目同步跪腹;差異性在于兩個(gè)項(xiàng)目的主題風(fēng)格、項(xiàng)目模塊架構(gòu)不一致飞醉,有各自獨(dú)立的業(yè)務(wù)和功能冲茸。
開發(fā)思路:
1、copy出另一個(gè)target實(shí)現(xiàn)項(xiàng)目B的業(yè)務(wù)模塊缅帘;否定原因:兩個(gè)項(xiàng)目的UI轴术、架構(gòu)不一致,在didFinishlaunch時(shí)就有差異钦无,這種需要通過判斷當(dāng)前target的方式進(jìn)行差異性開發(fā)逗栽,代碼會(huì)比較雜亂和難以維護(hù),圖片等資源文件的分離使用也很難做到失暂,另外還會(huì)增大開發(fā)包的體積
2祭陷、組件化開發(fā);將公共基礎(chǔ)模塊和業(yè)務(wù)模塊完全獨(dú)立趣席,使用pod管理不同組件,兩個(gè)獨(dú)立項(xiàng)目中進(jìn)行各自的引用醇蝴;否定原因:1)開發(fā)時(shí)間緊迫宣肚,人手不足,完全抽離組件不太理想 悠栓,2)對(duì)于公共業(yè)務(wù)模塊霉涨,兩個(gè)項(xiàng)目的風(fēng)格也不盡相同,某種程度上不能完全獨(dú)立惭适,3)現(xiàn)狀是公共的業(yè)務(wù)模塊也需要開發(fā)升級(jí)笙瑟,抽離出去就需要不停維護(hù),這種不穩(wěn)定狀態(tài)實(shí)際上不適合封裝成組件
3癞志、workspace工作區(qū)開發(fā)往枷;采納原因:1)不同于組件抽離,workspace內(nèi)的靜態(tài)庫可以靈活抽取,不用像組件那樣需要完全和外部解耦错洁,可以把工具秉宿,三方庫,category等自定義的和項(xiàng)目AB公共的業(yè)務(wù)模塊都放在靜態(tài)庫屯碴, 2)由于靜態(tài)庫被項(xiàng)目引用后描睦,圖片資源通過bundle管理并且內(nèi)置于項(xiàng)目,所以圖片資源可以獨(dú)立兩份于兩個(gè)項(xiàng)目中导而,3)公共業(yè)務(wù)只需在靜態(tài)庫中進(jìn)行開發(fā)忱叭,兩個(gè)項(xiàng)目引用靜態(tài)庫就好,靜態(tài)庫把外部使用的類的頭文件設(shè)置好就可以了今艺;
4韵丑、具體開發(fā)過程和遇到的問題,就往下看吧
項(xiàng)目配置
實(shí)際開發(fā)項(xiàng)目:一個(gè)workspace中一個(gè)靜態(tài)庫和兩個(gè)項(xiàng)目
一洼滚、創(chuàng)建workspace工作區(qū)埂息,cocoaTouch static library,projectA 和 projectB
1.1 workspace文件遥巴,不多說千康,直接上圖,創(chuàng)建好后只會(huì)生成一個(gè).xcworkspace文件铲掐,無其他文件生成1.2 創(chuàng)建靜態(tài)庫拾弃,由于蘋果不支持開發(fā)者使用動(dòng)態(tài)庫,所以我們使用靜態(tài)庫(當(dāng)然也可以選擇動(dòng)態(tài)庫CocoaTouch Framework再改成靜態(tài)庫摆霉,還是有不同的)
1.3 兩個(gè)項(xiàng)目的創(chuàng)建和日常創(chuàng)建項(xiàng)目無異,只是要和靜態(tài)庫一樣携栋,選擇addTo和group到剛剛創(chuàng)建的workspace 最終的文件目錄, 如圖搭盾,兩個(gè)項(xiàng)目一個(gè)靜態(tài)庫在一個(gè)workspace下
二、靜態(tài)庫的配置和項(xiàng)目中的使用
1婉支、由于我們是在workspace中創(chuàng)建靜態(tài)庫鸯隅,和獨(dú)立的靜態(tài)庫使用不同(將.a文件拖拽入項(xiàng)目即可),而是在同一個(gè)workspace里向挖,一起編譯蝌以,具體往下看
1.1 前往靜態(tài)庫的target的Build phases,添加copy Files何之,以便項(xiàng)目中引用靜態(tài)庫暴露的頭文件
1.2 項(xiàng)目引用.a靜態(tài)庫跟畅,Link binary with libraries下,add
libCommonLibrary.a
1.3 訪問靜態(tài)庫的類溶推,#import<CommonLibrary/CommonLibrary.h>
至此徊件,項(xiàng)目中如何應(yīng)用靜態(tài)庫和訪問其類就結(jié)束了奸攻,心好累吧
靜態(tài)庫中xib和圖片資源的管理
先解釋一下這個(gè)過程,在項(xiàng)目A中引入.a靜態(tài)庫庇忌,對(duì)于[NSBundle mainBundle]返回的是項(xiàng)目A的bundle舞箍,那么.a中的xib和圖片資源肯定是不在項(xiàng)目A的bundle中的,所以在.a中如何加載xib和圖片呢皆疹,下面要講疏橄,如何管理靜態(tài)庫中的資源文件
- 關(guān)于Bundle
對(duì)于bundle可以理解為一個(gè)捆綁包,個(gè)人理解bundle為一個(gè)獨(dú)立的空間略就,而我們的可執(zhí)行(executable)工程捎迫,打包完之后,也是一個(gè)捆綁包表牢,我們稱之為主bundle窄绒,這個(gè)主bundle包含了可執(zhí)行代碼,如各個(gè)viewcontroller的可執(zhí)行代碼崔兴,和相關(guān)資源例如圖片資源等彰导。
使用bundle管理靜態(tài)庫中的xib和圖片資源
-
在靜態(tài)庫中創(chuàng)建bundle入口
macOS下 -
xib文件的bundle,包含xib文件和xib上所加載的圖片資源敲茄;最后我才發(fā)現(xiàn)的位谋,xib用的圖片必須和xib文件在同一個(gè)bundle中,xib才可以自動(dòng)加載圖片堰燎,如圖
xib的bundle 圖片資源的bundle掏父,和xib的bundle創(chuàng)建過程一致,圖片的bundle其實(shí)完全可以看做是一個(gè)文件夾
-
至此秆剪,我創(chuàng)建了三個(gè)bundle赊淑,一個(gè)xib bundle,兩個(gè)圖片bundle(用于兩個(gè)不同風(fēng)格的項(xiàng)目仅讽,內(nèi)部圖片名稱一樣)
還有一個(gè)XZimgBundle.bundle
bundle如何使用
-
首先陶缺,bundle其實(shí)是靜態(tài)庫中的資源,因?yàn)楫?dāng)前是在項(xiàng)目中引用靜態(tài)庫洁灵,所以bundle需要拖拽進(jìn)項(xiàng)目饱岸,供項(xiàng)目應(yīng)用,如下
bundle拖拽入項(xiàng)目 xib又和圖片資源不同处渣,不同點(diǎn)在于xib會(huì)變化,修改蛛砰,那就需要靜態(tài)庫重新編譯獲取xib的bundle罐栈,而圖片bundle上面說了其實(shí)就是個(gè)文件夾用于管理圖片,所以在image的bundle創(chuàng)建好之后泥畅,就可以從靜態(tài)庫的target中刪除了荠诬,它的管理就在項(xiàng)目中刪加圖片就是了
最后一點(diǎn),現(xiàn)在bundle都在項(xiàng)目中了,靜態(tài)庫中訪問Bundle其實(shí)就是在訪問項(xiàng)目中的bundle柑贞,那怎么訪問呢方椎?我在靜態(tài)庫中定義了一個(gè)BundleTool
//其中一個(gè)項(xiàng)目的名稱是qmp_ios,這樣可以判斷靜態(tài)庫當(dāng)前是哪個(gè)項(xiàng)目加載的
+ (BOOL)isQMP{
return [[[NSBundle mainBundle]bundlePath]containsString:@"qmp_ios"];
}
//xib資源所在的bundle
+ (NSBundle *)commonBundle{
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"CommonBundle.bundle"];
NSBundle *bundle1 = [NSBundle bundleWithPath: path];
return bundle1;
}
//qmp_ios引入的圖片資源QMPimgBundle.bundle
+ (NSBundle *)qmpImgBundle{
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"QMPimgBundle.bundle"];
NSBundle *bundle1 = [NSBundle bundleWithPath: path];
return bundle1;
}
//xinzhi_ios引入的圖片資源XZimgBundle.bundle
+ (NSBundle *)xzImgBundle{
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"XZimgBundle.bundle"];
NSBundle *bundle1 = [NSBundle bundleWithPath: path];
return bundle1;
}
+ (NSString *)getBundlePath: (NSString *) assetName{
NSBundle *myBundle = [BundleTool commonBundle];
if (myBundle && assetName) {
return [[myBundle resourcePath] stringByAppendingPathComponent: assetName];
}
return nil;
}
//用此類替代[UIImage imageNamed] 訪問正確路徑下的圖片,bundle下的圖片可以直接[UIImage imageNamed: bundle+圖片名]
+ (UIImage*)imageNamed:(NSString*)imageName{
if ([BundleTool isQMP]) {
if ([imageName containsString:@"activity_user"]) {
NSLog(@"----");
}
return [UIImage imageNamed:[NSString stringWithFormat:@"QMPimgBundle.bundle/%@",imageName]];
}else{
return [UIImage imageNamed:[NSString stringWithFormat:@"XZimgBundle.bundle/%@",imageName]];
}
}
至此钧嘶,bundle的創(chuàng)建和使用就此結(jié)束棠众,而在項(xiàng)目內(nèi)部(不牽扯靜態(tài)庫)用到的圖片及xib和平時(shí)普通的用法還是一樣的,因?yàn)轫?xiàng)目內(nèi)的Bundle就是xib和圖片所在的bundle
靜態(tài)庫中的類和項(xiàng)目中的類如何相互調(diào)用
先講有决,這種workspace機(jī)構(gòu)闸拿,.a靜態(tài)庫只能被項(xiàng)目引用,不能引用項(xiàng)目(項(xiàng)目是可以引用項(xiàng)目的)书幕,那就意味著項(xiàng)目可以隨意調(diào)用.a暴露出來的靜態(tài)庫中的類新荤,那.a如何調(diào)用項(xiàng)目的類呢,以上講了背景台汇,我們的.a不是完全獨(dú)立解耦的苛骨,項(xiàng)目A和B的公共業(yè)務(wù)模塊還在.a里,所以.a 是存在需要調(diào)用項(xiàng)目業(yè)務(wù)模塊的情況的苟呐;
- 靜態(tài)庫想要訪問項(xiàng)目中的類痒芝?
如何調(diào)用? 我選擇使用protocol掠抬,.a中定義了一套跳轉(zhuǎn)協(xié)議AppPageSkipProtocol吼野,和一個(gè)跳轉(zhuǎn)工具類LibraryPageSkipTool(其中有一個(gè)代理屬性id< AppPageSkipProtocol >delegate),需要跳轉(zhuǎn)到項(xiàng)目中的地方两波,就用delegate調(diào)用跳轉(zhuǎn)協(xié)議中的api去負(fù)責(zé)跳轉(zhuǎn)瞳步,傳入對(duì)應(yīng)參數(shù)即可 - 跳轉(zhuǎn)協(xié)議根據(jù)實(shí)際情況,看是否需要傳入?yún)?shù)腰奋,定義block回調(diào)单起,根據(jù)實(shí)際情況隨時(shí)修改添加都可以
- 跳轉(zhuǎn)工具的delegate,在項(xiàng)目的didFinishLaunch里劣坊,用項(xiàng)目的跳轉(zhuǎn)工具類實(shí)例作為delegate傳給.a 的跳轉(zhuǎn)工具類嘀倒,如 [LibraryPageSkipTool shared].delegate = [AppPageSkipTool shared],項(xiàng)目的跳轉(zhuǎn)工具類AppPageSkipTool內(nèi)部局冰,遵循協(xié)議AppPageSkipProtocol测蘑,實(shí)現(xiàn)協(xié)議方法就可以了
如何使用cocoaPods
上面講過,靜態(tài)庫被引入項(xiàng)目之后康二,編譯執(zhí)行環(huán)境都是項(xiàng)目的環(huán)境碳胳,所以靜態(tài)庫需要的環(huán)境(build phases,三方庫沫勿,系統(tǒng)庫)挨约,項(xiàng)目中也需要實(shí)現(xiàn)配置味混,那么......
- Podfile如何配置, 如圖,靜態(tài)庫中用到的三方庫诫惭,項(xiàng)目中也需要引入翁锡,項(xiàng)目中另外可以添加項(xiàng)目內(nèi)部需要的庫
workspace 'WorkSpaceQMP.xcworkspace'
target 'CommonLibrary' do
platform :ios,'8.0'
project 'CommonLibrary/CommonLibrary.xcodeproj'
pod 'AFNetworking', '~> 3.1.0'
pod 'MJRefresh', '~> 3.1.0'
pod 'SDWebImage'
end
target 'qmp_ios' do
platform :ios,'8.0'
project 'qmp_ios/qmp_ios.xcodeproj'
pod 'AFNetworking', '~> 3.1.0'
pod 'MJRefresh', '~> 3.1.0'
pod 'SDWebImage'
pod 'YYText'
在對(duì)應(yīng)的.a和項(xiàng)目的build phases的Link build Library中添加各自的libPod庫
-
關(guān)閉workspace,此時(shí)文件目錄夕土,啊馆衔,多么愉快的feel
最終的目錄結(jié)構(gòu)
最后一個(gè)步驟,git管理
我的一個(gè)不知道是否錯(cuò)了的步驟: 創(chuàng)建倉庫并初始化——>clone到本地文件夾——>代碼復(fù)制到此文件夾——>add,commit,push——>發(fā)現(xiàn)兩個(gè)項(xiàng)目是空隘弊,git提示subModule的相關(guān)信息
- 正確步驟: 創(chuàng)建倉庫并初始化——>終端 cd到代碼根目錄——>git init初始化倉庫哈踱,add,commit——>重點(diǎn)[git remote add origin 你的遠(yuǎn)程庫地址] ——>獲取遠(yuǎn)程庫同步git pull --rebase origin master——>提交git push -u origin master
如果Git pull報(bào)錯(cuò): refusing to merge unrelated histories的解決辦法,執(zhí)行下面的命令:git pull origin master --allow-unrelated-histories就可以了
參考:(https://www.cnblogs.com/xiangxinhouse/p/8254120.html)
創(chuàng)建本地庫和fetch遠(yuǎn)程分支這些前面的步驟這里略過梨熙】停可以自行百度。
解決辦法:
1.cmd進(jìn)入項(xiàng)目的根目錄咽扇。
2.執(zhí)行下面的命令:git pull origin master --allow-unrelated-histories邪财。可以提交成功质欲。
參考:https://www.cnblogs.com/eedc/p/6168430.html
遇到的問題
- 實(shí)際情況下的.a 配置是很麻煩的树埠,需要引入很多第三方庫,其實(shí)整個(gè)過程和實(shí)際項(xiàng)目中使用是一樣的嘶伟,能使用pod管理的盡量使用cocoaPods管理怎憋,三方庫搞定一個(gè)再導(dǎo)入另一個(gè),不然你都不知道哪個(gè)庫出的問題
- 靜態(tài)庫配置出現(xiàn)arm64的問題九昧,按照網(wǎng)上的做法大概就可以绊袋,千萬記住,項(xiàng)目要配置靜態(tài)庫相同的環(huán)境铸鹰,所需要的系統(tǒng)庫一定全部導(dǎo)入癌别,有時(shí)候這種情況也會(huì)出現(xiàn)arm64的問題,實(shí)際是項(xiàng)目沒有導(dǎo)入需要支持的三方庫
- 先配置靜態(tài)庫蹋笼,xcode先build靜態(tài)庫展姐,.a成功了,再build項(xiàng)目
- Archive問題:報(bào)錯(cuò)XcodeDefault.xctoolchain/usr/bin/strip: can't open temporary file:剖毯。圾笨。。逊谋,解決在.a的build setting中將strip linked product置為NO
- 打包完成發(fā)現(xiàn)最終的.ipa文件特別大擂达,比原先大了二三十兆,網(wǎng)上搜索一些縮減靜態(tài)庫的方法如下:
1涣狗、在Build setting里面配置:
2谍婉、set Generate Debug Symbols to NO
3、Strip Debug Symbols During Copy flag set to Yes
4镀钓、同時(shí)Valid Architectures可以根據(jù)實(shí)際情況縮減穗熬;
目前Xcode默認(rèn)支持iOS的指令集有armv7,armv7s丁溅,arm64唤蔗;armv7只出現(xiàn)在iPhone4、iPhone4S的機(jī)器上窟赏;armv7s只出現(xiàn)在iPhone5妓柜、iPhone5C上;后面的機(jī)器一般都是arm64芯片涯穷;iPhone4棍掐、iPhone4S一般項(xiàng)目可以考慮不支持就在Valid Architectures將armv7刪掉。(經(jīng)測試拷况,只要設(shè)置Valid Architectures就可以了作煌,其他的設(shè)置效果不太明顯)