用CocoaPods管理代碼組件化遇到的問(wèn)題

最近項(xiàng)目按照很久之前寫的CocoaPods遠(yuǎn)程私有庫(kù)做代碼組件化,介紹我遇到的問(wèn)題。新版的Specs和之前的一樣,就是目錄名稱改了一下,之前用s,現(xiàn)在用spec,其實(shí)是一樣的,也可以更改其他的。之前介紹的CocoaPods遠(yuǎn)程私有庫(kù)只是單獨(dú)的一個(gè).a文件和頭文件,比較簡(jiǎn)單,現(xiàn)在要弄的是一個(gè)功能模塊的組件化。這里主要是講解.podspec文件,了解更多的.podspec文件內(nèi)容,請(qǐng)看官網(wǎng)介紹:Specs and the Specs Repo。

一、添加pch文件

這個(gè)相對(duì)比較容易,添加一行 spec.prefix_header_file,如果pch文件位置改了,這里一定要更改才行,組件化里面的pch文件和項(xiàng)目中用到的pch文件是不沖突的,是區(qū)分開(kāi)來(lái)的。

spec.prefix_header_file ='pch文件的絕對(duì)路徑' 

二、依賴第三方庫(kù)

這個(gè)也比較簡(jiǎn)單,例如依賴SDWebImage,直接上代碼:

spec.dependency "SDWebImage", "~> 4.4.6" 。

三、資源文件的存放

這個(gè)是最重要的,也是本文要講解出現(xiàn)的問(wèn)題,首先介紹文件的存放路徑

①、spec.source_files = "" 和 spec.resources = ""。

    1. 如果Podfile文件用到use_frameworks!的話(到底項(xiàng)目需不需要用到的話,自行網(wǎng)上搜索答案,這里不詳細(xì)說(shuō)),
所存放的文件是在庫(kù)主目錄下,如果庫(kù)名為L(zhǎng)ibtest,那么就在Libtest.framework下,所以和平時(shí)的mainBundle不一樣;

    2. 如果沒(méi)有用到use_frameworks!的話,所存放的文件是在主目錄下,
我們平時(shí)開(kāi)發(fā)的項(xiàng)目代碼文件、資源文件(圖片、plist、音視頻)一般都是在mainBundle下的,代碼可以直接引用。

②、spec.resource_bundles = {'Image' => ['Resources/*/.{png,jpg}']}

    1. 如果Podfile文件用到use_frameworks!的話,則是存放在庫(kù)主目錄下(mainBundle)的Image.bundle下,
Image是隨意填寫的名稱,如IQKeyboardManager庫(kù)一樣,如圖所示:
image
    2. 如果沒(méi)有用到use_frameworks!的話,所存放的文件是在主目錄下(mainBundle)的Image.bundle下 

所以存放的路徑不一樣,獲取就不一樣,要對(duì)應(yīng)獲取相應(yīng)的資源文件,套用網(wǎng)上的方法如下所示:

/**
獲取文件所在name,默認(rèn)情況下podName和bundlename相同,傳一個(gè)即可
@param bundleName bundle名字,就是在resource_bundles里面的名字
@param podName pod的名字
@return bundle
*/
+ (NSBundle *)bundleWithBundleName:(NSString *)bundleName podName:(NSString *)podName{
    if (bundleName == nil && podName == nil) {
        @throw @"bundleName和podName不能同時(shí)為空";
    }else if (bundleName == nil ) {
        bundleName = podName;
    }else if (podName == nil) {
        podName = bundleName;
    }

    if ([bundleName containsString:@".bundle"]) {
        bundleName = [bundleName componentsSeparatedByString:@".bundle"].firstObject;
    }

    //沒(méi)使用framwork的情況下
    NSURL *associateBundleURL = [[NSBundle mainBundle] URLForResource:bundleName withExtension:@"bundle"];

    //使用framework形式
    if (!associateBundleURL) {
        associateBundleURL = [[NSBundle mainBundle] URLForResource:@"Frameworks" withExtension:nil];
        associateBundleURL = [associateBundleURL URLByAppendingPathComponent:podName];
        associateBundleURL = [associateBundleURL URLByAppendingPathExtension:@"framework"];
        NSBundle *associateBunle = [NSBundle bundleWithURL:associateBundleURL];
        associateBundleURL = [associateBunle URLForResource:bundleName withExtension:@"bundle"];
    }
    NSAssert(associateBundleURL, @"取不到關(guān)聯(lián)bundle");
    //生產(chǎn)環(huán)境直接返回空
    return associateBundleURL?[NSBundle bundleWithURL:associateBundleURL]:nil;
}

我一開(kāi)始不太明白資源的存放路徑,走了很多彎路,折騰了兩三天。我的項(xiàng)目用到use_frameworks!,通過(guò)綜合考慮,要用到資源文件,我把所有文件都放在Classes目錄下,我的第一版是這樣寫的,如下:

spec.source_files  = "ConnectionLib/Classes", "ConnectionLib/Classes/**/*.{h,m,xib,storyboard,plist,png}"
spec.resource_bundles = {
'SAJConnectVoice' => ['ConnectionLib/Classes/**/*.wav'],
'SAJConnectHtml' => ['ConnectionLib/Classes/**/*.{html,js,css}'],
}

加載xib、storyboard和plist文件用[NSBundle bundleForClass:[self class]],不能用[NSBundle mainBundle],
加載.wav和.html用到上面的方法+ (NSBundle *)bundleWithBundleName:(NSString *)bundleName podName:(NSString *)podName;
在xib上的圖片不需要更改,會(huì)自動(dòng)識(shí)別在當(dāng)前bundle里面的圖片,代碼回去的image就要更改了,要用到
+ (nullable UIImage *)imageNamed:(NSString *)name inBundle:(nullable NSBundle *)bundle compatibleWithTraitCollection:(nullable UITraitCollection *)traitCollection方法

很高興的在本地庫(kù)完全沒(méi)有問(wèn)題,本地驗(yàn)證也通過(guò)了,但是遠(yuǎn)程驗(yàn)證沒(méi)有通過(guò)(xib不能放在source_files里面 ),提交不了到pod私有庫(kù),所以有點(diǎn)失望。
接著我又更改了方法(把xib文件放在resource_bundles),那就是的第二版:

spec.source_files  = "ConnectionLib/Classes", "ConnectionLib/Classes/**/*.{h,m,storyboard,plist,png}"
spec.resource_bundles = {
    'SAJConnectXib' => ['ConnectionLib/Classes/**/*.xib'],
    'SAJConnectVoice' => ['ConnectionLib/Classes/**/*.wav'],
    'SAJConnectHtml' => ['ConnectionLib/Classes/**/*.{html,js,css}'],
}
此時(shí)加載xib就需要用到上面的方法
+ (NSBundle *)bundleWithBundleName:(NSString *)bundleName podName:(NSString *)podName;

這版遠(yuǎn)程驗(yàn)證通過(guò),終于提交了第一版的pod私有庫(kù),但有個(gè)問(wèn)題xib文件和圖片不在同一個(gè)Bundle里面,所以在xib放的圖片都是不能顯示,看著那么多xib文件和加載圖片很多,不想拉控件用代碼賦值。于是就有了第三版:然后把圖片放在xib同一個(gè)Bundle里面。

這時(shí)感覺(jué)沒(méi)問(wèn)題了,遇到的那么問(wèn)題,終于可以了,心里有點(diǎn)小高興,然后等到我想打包的時(shí)候,打包出錯(cuò),無(wú)法打包,
這時(shí)看到的報(bào)錯(cuò)信息,是存放的資源文件獲取不到,于是又更改存放文件。

通過(guò)多次嘗試,除了.h和.m文件之外的文件都不能放在spec.source_files里面,所以只能抽出來(lái)了,
接著為了方便加載xib、storyboard、plist、png等,于是我把它們放在spec.resources里面。
這跟放在spec.source_files里面是一樣的,存放的目錄都一樣的。
spec.source_files = 'ConnectionLib/Classes/**/*.{h,m}'
spec.resources = 'ConnectionLib/**/*.{storyboard,plist,xib,png,wav,html,js,css}'

這次沒(méi)有多大的問(wèn)題,加載文件都是正常的,打包什么都正常,但有個(gè)問(wèn)題就是遠(yuǎn)程庫(kù)沒(méi)有分目錄,全部文件雜亂存放在一起,沒(méi)眼看,但本地的有分目錄很清楚,這就很無(wú)助了,然后又想著分目錄。

但這分目錄還是比較棘手的,我這份代碼是比較多,各牽連著各,其實(shí)份目錄是每個(gè)目錄都可以獨(dú)立或者依賴的,要不是分不了的(這里不詳細(xì)說(shuō)目錄)。我這邊只是分了資源文件和.h和.m直接的

spec.subspec 'Classes' do |classes|
  classes.source_files = 'ConnectionLib/Classes/**/*.{h,m}'
end
spec.subspec 'Resources' do |resources|
  resources.subspec 'Image' do |image|
    image.resources = 'ConnectionLib/**/*.png'
  end
  resources.subspec 'Storyboard' do |storyboard|
    storyboard.resources = 'ConnectionLib/**/*.storyboard'
  end
  resources.subspec 'Xib' do |xib|
    xib.resources = 'ConnectionLib/**/*.xib'
  end
  resources.subspec 'Voice' do |voice|
    voice.resources = 'ConnectionLib/**/*.wav'
  end
  resources.subspec 'Html' do |html|
    html.resources = 'ConnectionLib/**/*.{html,js,css}'
  end
  resources.subspec 'Plist' do |plist|
    plist.resources = 'ConnectionLib/**/*.plist'
  end
  resources.subspec 'Localizable' do |localizable|
    localizable.resources = 'ConnectionLib/**/*.strings'
  end
end

就這樣勉強(qiáng)用著,后來(lái)又增加了國(guó)際化,其實(shí)和其他文件一樣存放在資源文件,最好把文件名改一下,我這里用MYLocalizable.strings講解一下

spec..resources = 'ConnectionLib/**/*.strings'

可以定義一個(gè)宏,如果strings文件名為MYLocalizable
#define MYLocalizedString(text) \
NSLocalizedStringFromTableInBundle(text, @"MYLocalizable", [NSBundle bundleForClass:[self class]], nil)

那么就是用MYLocalizedString(text)代替NSLocalizedString(text, nil)

四、本地驗(yàn)證和遠(yuǎn)程驗(yàn)證以及上傳pod庫(kù)

這里用到第三方庫(kù),還有很多文件,如果用之前的簡(jiǎn)單命令是不能通過(guò)的

pod lib lint     ---- 本地庫(kù)驗(yàn)證是否有誤
pod spec lint ---- 遠(yuǎn)程庫(kù)驗(yàn)證是否有誤
pod repo push Mymaster ConnectionLib.podspec ---- 提交遠(yuǎn)程私有庫(kù),
這里Mymaster是自己添加的repo名稱,ConnectionLib.podspec是自己制作的podspec文件

以上都是簡(jiǎn)單的命令,在我的項(xiàng)目中的不能通過(guò)的,然后又加多了--allow-warnings還是不能通過(guò),
提示:xcodebuild: Returned an unsuccessful exit code.
后來(lái)在網(wǎng)上查還要用到--verbose --no-clean --use-libraries才能通過(guò)

pod lib lint --allow-warnings --verbose --no-clean --use-libraries
pod spec lint --allow-warnings --verbose --no-clean --use-libraries
pod repo push Mymaster ConnectionLib.podspec --allow-warnings --verbose --use-libraries 

如果庫(kù)里有依賴私有庫(kù)和公有庫(kù)(CocoaPods)的時(shí)候,需要在后面添加source,如:
pod lib lint --allow-warnings --verbose --no-clean --use-libraries --sources='自己私有庫(kù)地址,https://github.com/CocoaPods/Specs'
pod repo push Mymaster ConnectionLib.podspec --allow-warnings --verbose --use-libraries --sources='自己私有庫(kù)地址,https://github.com/CocoaPods/Specs'

五、同事使用

添加私有的repo
    pod repo add Mymaster spec的存放的地址     // Mymaster名字可以隨意寫
然后執(zhí)行  pod install  就ok了,
這里可能會(huì)有問(wèn)題,地址不能用帶自己用戶名的地址,這個(gè)權(quán)限只有自己的權(quán)限,要輸入自己的git密碼,
我這邊使用的是沒(méi)有帶用戶名的地址,同事都可正常使用。(可以用https)
image.png
最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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