何為組件化
一種能夠解決代碼耦合的技術(shù)。項(xiàng)目經(jīng)過組件化的拆分,不僅可以解決代碼耦合的問題,還可以增強(qiáng)代碼的復(fù)用性,工程的易管理性,減少編譯時間等
1.組件化分層架構(gòu)圖

2.架構(gòu)分層詳解
1.Lib層
基礎(chǔ)模塊跟業(yè)務(wù)無關(guān),只定義接口和基本配置,子類可以重寫,便于擴(kuò)展
- LibBase
- LibBaseController
- LibBaseNavController
- ...
- LibCommon基礎(chǔ)公共組件
- LibFlexBox移動端FlexBox布局
Widget層
- 由Lib延伸而來,便于組件的擴(kuò)展和復(fù)用
2.Mediator層
- 采用Bifrost框架,創(chuàng)建調(diào)度組件并定義交互協(xié)議,處理業(yè)務(wù)模塊之間的數(shù)據(jù)傳遞及邏輯交互處理
- Module層必須依賴該庫
3.Module層
業(yè)務(wù)層,跟業(yè)務(wù)相關(guān)的一些組件,業(yè)務(wù)組件之間互不依賴,且依賴于ModuleCommon層
ModuleCommon
跟業(yè)務(wù)相關(guān)的公共組件部分,例如
- CommonBaseController
- CommonLodingController
- CommonListController
- 數(shù)據(jù)模型Models
- Tools工具類
- Macro常見宏等
- QMUI常見配置/換膚配置
- 第三方分享/登錄/支付配置
3.組件化要點(diǎn)羅列
- 多Target分模塊開發(fā),代碼解耦
- 單獨(dú)編譯項(xiàng)目
- 組件之間傳值,通過調(diào)度組件Biforst
- 組件間訪問公共圖片資源,解決命名沖突
- 文件夾分層:子組件subspec
-
pod 引入依賴方式
- 引入本地依賴
- 引入遠(yuǎn)程依賴
- 引入指定分支
- 組件命名方式
- App路由管理
- podspec使用及格式校驗(yàn)
- 組件間依賴管理
- coapods私有化倉庫搭建
**
3.1多Target分模塊開發(fā),代碼解耦
workspace 依賴多個功能文件開發(fā)
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
def commonPods()
#基礎(chǔ)宏定義,類別
pod 'HKMacros', :git => 'https://gitee.com/Steven_Hu/HKMacros.git'
# 組件化基類-引用本地依賴
pod 'HKBaseModule', :path => './PrivateRepo/HKBaseModule/HKBaseModule.podspec'
#pod 'HKBaseModule', :git => 'https://gitee.com/Steven_Hu/HKBaseModule.git'
end
def mediatorPods()
#pod 'Bifrost', :path => '../'
end
# Comment the next line if you don't want to use dynamic frameworks
#use_frameworks!
#workspace文件名
workspace 'HKiOSTools.xcworkspace'
#主工程路徑
project 'HKiOSTools/HKiOSTools.xcodeproj'
target 'HKiOSTools' do
project 'HKiOSTools/HKiOSTools.xcodeproj'
commonPods()
target "HKBaseModule_Example" do
project 'PrivateRepo/HKBaseModule/Example/HKBaseModule.xcodeproj'
commonPods()
end
end
**
3.2單獨(dú)編譯項(xiàng)目
如何區(qū)分你編譯的是主工程項(xiàng)目還是子工程項(xiàng)目
- 最簡單的方式,通過項(xiàng)目名稱:ProjectName
[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleExecutableKey]
- 判斷項(xiàng)目名稱是否和子項(xiàng)目名稱一致即可
3.3組件之間傳值Bifrost

注冊路由(ViewController)
+ (void)load {
[Bifrost bindURL:kRouteHomePage
toHandler:^id _Nullable(NSDictionary * _Nullable parameters) {
return [HKHomeViewController new];
}];
}
獲取路由(ViewController)
UIViewController * vc = [Bifrost handleURL:kRouteHomePage];
[self.navigationController pushViewController:vc animated:YES];
頁面?zhèn)髦?/h4>
- 以type為例
//1.當(dāng)前頁面聲明一個type屬性
/// 驗(yàn)證類型
@property (nonatomic, assign) HKVerifyType type ;
// 2.bindURL
[Bifrost bindURL:kRouteBindPhoneNumPage toHandler:^id _Nullable(NSDictionary * _Nullable parameters) {
HKBindPhoneNumViewController *vc = [[self alloc] init];
vc.type = [parameters[kRouteBindPhoneNumParamType] integerValue];
return vc;
}];
// 3.傳值type
NSString *routeURL = BFStr(@"%@?%@=%@", kRouteBindPhoneNumPage, kRouteBindPhoneNumParamType, @(HKVerifyTypeForgetPassword));
UIViewController * vc = [Bifrost handleURL:routeURL]
[self.navigationController pushViewController:vc animated:YES];
頁面回調(diào)處理
//1.當(dāng)前頁面聲明一個type屬性和Block
/// 驗(yàn)證類型
@property (nonatomic, assign) HKVerifyType type ;
/// 完成回調(diào)
@property (nonatomic, strong) BifrostRouteCompletion complete ;
// 2.bindURL
[Bifrost bindURL:kRouteBindPhoneNumPage toHandler:^id _Nullable(NSDictionary * _Nullable parameters) {
HKBindPhoneNumViewController *vc = [[self alloc] init];
vc.type = [parameters[kRouteBindPhoneNumParamType] integerValue];
vc.complete = parameters[kBifrostRouteCompletion];
return vc;
}];
// 3.點(diǎn)擊事件處理
/// 獲取驗(yàn)證
- (void)getVerifyCodeEvent
{
[self.view endEditing:YES];
BFComplete(@{kBifrostRouteCompletion:self.complete}, @(self.type));
}
// 4.傳值type
UIViewController *vc = [Bifrost handleURL:kRouteBindPhoneNumPage complexParams:@{kRouteBindPhoneNumParamType:@(HKVerifyTypeForgetPassword)} completion:^(id _Nullable result) {
HKVerifyType type = (YNVerifyType)result;
[HKKeyWindow hk_showWithText:HKStr(@"你點(diǎn)擊的類型是:%@",type)];
}];
[self.navigationController pushViewController:vc animated:YES];
3.4組件間訪問公共圖片資源
主工程有一個a.png的圖片,而pod庫里面也有一個a.png的圖片,此時就產(chǎn)生命名沖突了
思路:不同的組件都有自己獨(dú)立的bundle,組件內(nèi)部資源提供自身的Bundle來獲取,以避免資源重復(fù)
- 本地資源如圖片等存放位置(Assets文件夾,否則無法訪問)
image.png
- 指定Bundle名稱
# resource_bundles
s.resource_bundles = {
'HKLibCommon' => ['HKLibCommon/**/*.{xib,jpg,gif,png,xcassets}']
}
- 解決命名沖突:resource_bundles
-
resource_bundles會自動生成bundle把資源文件打包進(jìn)去
加載本地資源方法
工具類抽取
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ModuleBundle : NSObject
/*
* 根據(jù)bundle的名稱獲取bundle
*/
+ (NSBundle *)bundleWithName:(NSString *)bundleName;
//獲取bundle 每次只要重寫這個方法就可以在指定的bundle中獲取對應(yīng)資源
+ (NSBundle *)bundle;
//根據(jù)xib文件名稱獲取xib文件
+ (__kindof UIView *)viewWithXibFileName:(NSString *)fileName;
//根據(jù)圖片名稱獲取圖片
+ (UIImage *)imageNamed:(NSString *)imageName;
//根據(jù)sb文件名稱獲取對應(yīng)sb文件
+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName;
//獲取nib文件
+ (UINib *)nibWithName:(NSString *)nibName;
@end
#import "ModuleBundle.h"
@implementation ModuleBundle
+ (NSBundle *)bundleWithName:(NSString *)bundleName {
if(bundleName.length == 0) {
return nil;
}
NSString *path = [[NSBundle mainBundle] pathForResource:bundleName ofType:@"bundle"];
NSAssert([NSBundle bundleWithPath:path], @"not found bundle");
return [NSBundle bundleWithPath:path];
}
+ (NSBundle *)bundle {
// NSAssert([NSBundle mainBundle], @"not found bundle");
return [NSBundle mainBundle];
}
+ (UIView *)viewWithXibFileName:(NSString *)fileName {
NSAssert([self viewWithXibFileName:fileName inBundle:[self.class bundle]], @"not found view");
return [self viewWithXibFileName:fileName inBundle:[self.class bundle]];
}
+ (UIImage *)imageNamed:(NSString *)imageName {
NSAssert([self imageNamed:imageName inBundle:[self.class bundle]], @"not found image");
return [self imageNamed:imageName inBundle:[self.class bundle]];
}
+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName {
NSAssert([self storyboardWithName:storyboardName inBundle:[self.class bundle]], @"not found storyboard");
return [self storyboardWithName:storyboardName inBundle:[self.class bundle]];
}
+ (UINib *)nibWithName:(NSString *)nibName {
NSAssert([self nibWithNibName:nibName inBundle:[self.class bundle]], @"not found nib");
return [self nibWithNibName:nibName inBundle:[self.class bundle]];
}
#pragma mark - private
+ (UIImage *)imageNamed:(NSString *)imageName inBundle:(NSBundle *)bundle {
if(imageName.length == 0 || !bundle) {
return nil;
}
return [UIImage imageNamed:imageName inBundle:bundle compatibleWithTraitCollection:nil];
}
+ (UIImage *)imageNamed:(NSString *)imageName bundleName:(NSString *)bundleName {
return [self imageNamed:imageName inBundle:[self bundleWithName:bundleName]];
}
+ (UIView *)viewWithXibFileName:(NSString *)fileName inBundle:(NSBundle *)bundle {
if(fileName.length == 0 || !bundle) {
return nil;
}
//如果沒有國際化,則直接去相應(yīng)內(nèi)容下的文件
UIView *xibView = [[bundle loadNibNamed:fileName owner:nil options:nil] lastObject];
if(!xibView) {
//文件國際化之后,所有的bundle的文件資源都在base的目錄下
xibView = [[[NSBundle bundleWithPath:[bundle pathForResource:@"Base" ofType:@"lproj"]] loadNibNamed:fileName owner:nil options:nil] lastObject];
}
return xibView;
}
+ (UIView *)viewWithXibFileName:(NSString *)fileName bundleName:(NSString *)bundleName {
return [self viewWithXibFileName:fileName inBundle:[self bundleWithName:bundleName]];
}
+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName inBundle:(NSBundle *)bundle {
if(storyboardName.length == 0 || !bundle) {
return nil;
}
return [UIStoryboard storyboardWithName:storyboardName bundle:bundle];
}
+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName bundleName:(NSString *)bundleName {
return [self storyboardWithName:storyboardName inBundle:[self bundleWithName:bundleName]];
}
+ (UINib *)nibWithNibName:(NSString *)nibName inBundle:(NSBundle *)bundle {
if(nibName.length == 0 || !bundle ) {
return nil;
}
return [UINib nibWithNibName:nibName bundle:bundle];
}
@end
Bundle獲取
//1.當(dāng)前頁面聲明一個type屬性
/// 驗(yàn)證類型
@property (nonatomic, assign) HKVerifyType type ;
// 2.bindURL
[Bifrost bindURL:kRouteBindPhoneNumPage toHandler:^id _Nullable(NSDictionary * _Nullable parameters) {
HKBindPhoneNumViewController *vc = [[self alloc] init];
vc.type = [parameters[kRouteBindPhoneNumParamType] integerValue];
return vc;
}];
// 3.傳值type
NSString *routeURL = BFStr(@"%@?%@=%@", kRouteBindPhoneNumPage, kRouteBindPhoneNumParamType, @(HKVerifyTypeForgetPassword));
UIViewController * vc = [Bifrost handleURL:routeURL]
[self.navigationController pushViewController:vc animated:YES];
//1.當(dāng)前頁面聲明一個type屬性和Block
/// 驗(yàn)證類型
@property (nonatomic, assign) HKVerifyType type ;
/// 完成回調(diào)
@property (nonatomic, strong) BifrostRouteCompletion complete ;
// 2.bindURL
[Bifrost bindURL:kRouteBindPhoneNumPage toHandler:^id _Nullable(NSDictionary * _Nullable parameters) {
HKBindPhoneNumViewController *vc = [[self alloc] init];
vc.type = [parameters[kRouteBindPhoneNumParamType] integerValue];
vc.complete = parameters[kBifrostRouteCompletion];
return vc;
}];
// 3.點(diǎn)擊事件處理
/// 獲取驗(yàn)證
- (void)getVerifyCodeEvent
{
[self.view endEditing:YES];
BFComplete(@{kBifrostRouteCompletion:self.complete}, @(self.type));
}
// 4.傳值type
UIViewController *vc = [Bifrost handleURL:kRouteBindPhoneNumPage complexParams:@{kRouteBindPhoneNumParamType:@(HKVerifyTypeForgetPassword)} completion:^(id _Nullable result) {
HKVerifyType type = (YNVerifyType)result;
[HKKeyWindow hk_showWithText:HKStr(@"你點(diǎn)擊的類型是:%@",type)];
}];
[self.navigationController pushViewController:vc animated:YES];
主工程有一個a.png的圖片,而pod庫里面也有一個a.png的圖片,此時就產(chǎn)生命名沖突了

# resource_bundles
s.resource_bundles = {
'HKLibCommon' => ['HKLibCommon/**/*.{xib,jpg,gif,png,xcassets}']
}
resource_bundles會自動生成bundle把資源文件打包進(jìn)去#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ModuleBundle : NSObject
/*
* 根據(jù)bundle的名稱獲取bundle
*/
+ (NSBundle *)bundleWithName:(NSString *)bundleName;
//獲取bundle 每次只要重寫這個方法就可以在指定的bundle中獲取對應(yīng)資源
+ (NSBundle *)bundle;
//根據(jù)xib文件名稱獲取xib文件
+ (__kindof UIView *)viewWithXibFileName:(NSString *)fileName;
//根據(jù)圖片名稱獲取圖片
+ (UIImage *)imageNamed:(NSString *)imageName;
//根據(jù)sb文件名稱獲取對應(yīng)sb文件
+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName;
//獲取nib文件
+ (UINib *)nibWithName:(NSString *)nibName;
@end
#import "ModuleBundle.h"
@implementation ModuleBundle
+ (NSBundle *)bundleWithName:(NSString *)bundleName {
if(bundleName.length == 0) {
return nil;
}
NSString *path = [[NSBundle mainBundle] pathForResource:bundleName ofType:@"bundle"];
NSAssert([NSBundle bundleWithPath:path], @"not found bundle");
return [NSBundle bundleWithPath:path];
}
+ (NSBundle *)bundle {
// NSAssert([NSBundle mainBundle], @"not found bundle");
return [NSBundle mainBundle];
}
+ (UIView *)viewWithXibFileName:(NSString *)fileName {
NSAssert([self viewWithXibFileName:fileName inBundle:[self.class bundle]], @"not found view");
return [self viewWithXibFileName:fileName inBundle:[self.class bundle]];
}
+ (UIImage *)imageNamed:(NSString *)imageName {
NSAssert([self imageNamed:imageName inBundle:[self.class bundle]], @"not found image");
return [self imageNamed:imageName inBundle:[self.class bundle]];
}
+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName {
NSAssert([self storyboardWithName:storyboardName inBundle:[self.class bundle]], @"not found storyboard");
return [self storyboardWithName:storyboardName inBundle:[self.class bundle]];
}
+ (UINib *)nibWithName:(NSString *)nibName {
NSAssert([self nibWithNibName:nibName inBundle:[self.class bundle]], @"not found nib");
return [self nibWithNibName:nibName inBundle:[self.class bundle]];
}
#pragma mark - private
+ (UIImage *)imageNamed:(NSString *)imageName inBundle:(NSBundle *)bundle {
if(imageName.length == 0 || !bundle) {
return nil;
}
return [UIImage imageNamed:imageName inBundle:bundle compatibleWithTraitCollection:nil];
}
+ (UIImage *)imageNamed:(NSString *)imageName bundleName:(NSString *)bundleName {
return [self imageNamed:imageName inBundle:[self bundleWithName:bundleName]];
}
+ (UIView *)viewWithXibFileName:(NSString *)fileName inBundle:(NSBundle *)bundle {
if(fileName.length == 0 || !bundle) {
return nil;
}
//如果沒有國際化,則直接去相應(yīng)內(nèi)容下的文件
UIView *xibView = [[bundle loadNibNamed:fileName owner:nil options:nil] lastObject];
if(!xibView) {
//文件國際化之后,所有的bundle的文件資源都在base的目錄下
xibView = [[[NSBundle bundleWithPath:[bundle pathForResource:@"Base" ofType:@"lproj"]] loadNibNamed:fileName owner:nil options:nil] lastObject];
}
return xibView;
}
+ (UIView *)viewWithXibFileName:(NSString *)fileName bundleName:(NSString *)bundleName {
return [self viewWithXibFileName:fileName inBundle:[self bundleWithName:bundleName]];
}
+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName inBundle:(NSBundle *)bundle {
if(storyboardName.length == 0 || !bundle) {
return nil;
}
return [UIStoryboard storyboardWithName:storyboardName bundle:bundle];
}
+ (UIStoryboard *)storyboardWithName:(NSString *)storyboardName bundleName:(NSString *)bundleName {
return [self storyboardWithName:storyboardName inBundle:[self bundleWithName:bundleName]];
}
+ (UINib *)nibWithNibName:(NSString *)nibName inBundle:(NSBundle *)bundle {
if(nibName.length == 0 || !bundle ) {
return nil;
}
return [UINib nibWithNibName:nibName bundle:bundle];
}
@end
創(chuàng)建一個類CommonBundle繼承自ModuleBundle,并實(shí)現(xiàn)以下方法
#import "CommonBundle.h"
@implementation CommonBundle
+ (NSBundle *)bundle{
//TODO:注意Bundle名字需跟模塊名稱一致,否則會找不到path,直接Crash
return [self.class bundleWithName:@"HKLibCommon"];
}
@end
使用
替換系統(tǒng)加載圖片的方式:[UIImage imageNamed:@"navigationbar_background"]
[CommonBundle imageNamed:@"navigationbar_background"]
多個包
spec.resource_bundles = {
'MapBox' => ['MapView/Map/Resources/*.png'],
'OtherResources' => ['MapView/Map/OtherResources/*.png']
}
3.5文件夾分層子組件subspec
我們在編寫podspec文件時,sourcefiles只是告訴pods你需要哪些文件是這個項(xiàng)目中需要的,而沒有包括文件的層級結(jié)構(gòu),那么就需要我們來實(shí)現(xiàn)這個層級結(jié)構(gòu):subspec

比如這里面的每一個文件夾,就是一個子pod,這樣的好處是條理清晰,而且我們可以只用你需要的功能,在編寫podfile時 就可以這樣寫
pod 'HKModuleModels/User' 只使用其中的一個功能。
主podspec
主pod可以是一個頭文件,也可以具有一定的功能,我寫的組件sourcefiles只是一個import子組件的頭文件, sourcebundle是項(xiàng)目中需要的一些圖片

編寫subspec
- 讓pods支持子subspec其實(shí)很簡單,只要搞清楚三件事
- 文件夾結(jié)構(gòu) subspec sourcefiles的路徑
- subspec 所依賴的系統(tǒng)庫
- subspec 所依賴的第三方,和其它subspec的路徑

3.6pod 引入依賴方式
引入本地依賴
pod 'ManageLocalCode', :path => '../ManageLocalCode'
pod 'BioAuthAPI', :path => '../BioAuthAPI'
pod 'HKTool', :path => '../'
遠(yuǎn)程私有庫依賴:
# 基礎(chǔ)宏定義byStevenHu
pod 'HKMacros', :git => 'https://gitee.com/Steven_Hu/HKMacros.git'
指定分支
# 支付代碼測試
iap_pay:
git:
url: https://gitee.com/Steven_Hu/iap_pay.git
ref: master
常規(guī)依賴
pod "AFNetworking", "~>0.2.0"
3.7 組件命名方式
| 組件性質(zhì) | 建議名稱 | 示例 |
|---|---|---|
| 基礎(chǔ)組件拆分 | 項(xiàng)目前綴Lib組件名稱 | HKLibBase:基類模塊 |
| 業(yè)務(wù)組件拆分 | 項(xiàng)目前綴Module組件名稱 | HKModuleHome:首頁模塊 |
| 調(diào)度組件拆分 | 項(xiàng)目前綴Mediator組件名稱 | HKMediatorDriver:司機(jī)端調(diào)度組件 |
| Wdiget組件拆分 | 項(xiàng)目前綴Widget組件名稱 | HKWidgetAddressPicker:地址選擇器組件 |
| 公共組件 | 項(xiàng)目前綴_組件名稱_Common | HKLibCommon,HKModuleCommon |
3.8 App端路由管理
格式
app內(nèi)鏈
舉例:yunquedriver://home/homepage/detail?name=steven&age=18
appscheme://moduleName/pageName/secondPageName?key1=value1&key2=value2
其中value中有中文等特殊字符時需要進(jìn)行urlEncode。
app外鏈外鏈
格式說明
- appscheme分解
- 項(xiàng)目名稱
- yunque
- 業(yè)務(wù)側(cè)
- driver
- user
- 項(xiàng)目名稱
- moduleName
- 業(yè)務(wù)模塊名稱
- pageName
- 頁面名稱
- secondPage
- 二級頁面
scheme
云雀司機(jī): yunquedriver
云雀用戶:yunqueuser
模塊名
lib:工具類,跟業(yè)務(wù)無關(guān)的
頁面

3.9 podspec使用及格式校驗(yàn)
注意事項(xiàng)
- podspec版本號和git倉庫代碼的tag版本必須一致,否則找不到
- 比如:pod lib 默認(rèn)生成的是0.1.0,我們根據(jù)業(yè)務(wù)需要改成0.0.1
- 索引倉庫和組件倉庫關(guān)聯(lián)
- cd到組件倉庫目錄下
- pod repo push
#{本地關(guān)聯(lián)到遠(yuǎn)程倉庫的名字}#{第三方私有庫的podspec文件}--verbose --allow-warnings 示例: pod repo push YNSpecs YNLibDemo.podspec --verbose --allow-warnings
- 項(xiàng)目引入
# 遠(yuǎn)程私有倉庫
source 'https://gitlab.com/xxxx/xxSpecs'
# 引入使用
pod 'xxLibNetwork'
3.10 組件間依賴管理
通過 git submodule add https://gitee.com/Steven_Hu/hk-module-components.git 添加submodule
會在git上添加一個.gitmodules 文件,可以查看各種依賴
[submodule "PrivateRepo/hk-lib-base"]
path = PrivateRepo/hk-lib-base
url = https://gitee.com/Steven_Hu/hk-lib-base.git
[submodule "PrivateRepo/hk-lib-common"]
path = PrivateRepo/hk-lib-common
url = https://gitee.com/Steven_Hu/hk-lib-common.git
[submodule "PrivateRepo/hk-lib-network"]
path = PrivateRepo/hk-lib-network
url = https://gitee.com/Steven_Hu/hk-lib-network.git
[submodule "PrivateRepo/hk-mediator"]
path = PrivateRepo/hk-mediator
url = https://gitee.com/Steven_Hu/hk-mediator.git
[submodule "PrivateRepo/hk-lib-keyboard"]
path = PrivateRepo/hk-lib-keyboard
url = https://gitee.com/Steven_Hu/hk-lib-keyboard.git
[submodule "PrivateRepo/hk-lib-avoid-app-crash"]
path = PrivateRepo/hk-lib-avoid-app-crash
url = https://gitee.com/Steven_Hu/hk-lib-avoid-app-crash.git
[submodule "PrivateRepo/hk-lib-load-picture"]
path = PrivateRepo/hk-lib-load-picture
url = https://gitee.com/Steven_Hu/hk-lib-load-picture.git
[submodule "PrivateRepo/hkmodule-models"]
path = PrivateRepo/hkmodule-models
url = https://gitee.com/Steven_Hu/hkmodule-models.git
[submodule "PrivateRepo/hk-module-uikit"]
path = PrivateRepo/hk-module-uikit
url = https://gitee.com/Steven_Hu/hk-module-uikit.git
[submodule "PrivateRepo/hk-module-components"]
path = PrivateRepo/hk-module-components
url = https://gitee.com/Steven_Hu/hk-module-components.git
[submodule "PrivateRepo/hk-module-main"]
path = PrivateRepo/hk-module-main
url = https://gitee.com/Steven_Hu/hk-module-main.git
最終結(jié)果如下圖所示,點(diǎn)擊跳轉(zhuǎn)新的submodule倉庫地址

本地Clone方式
git clone https://gitee.com/Steven_Hu/hk-iostools.git
git submodule init && git submodule update
#下面這一句的效果和上面三條命令的效果是一樣的,多加了個參數(shù) `--recursive`
git clone https://gitee.com/Steven_Hu/hk-iostools.git --recursive
常見問題
error: Server does not allow request for unadvertised object b22e0a5a2a8dce1d0454bdead70353bf45f33f81
Fetched in submodule path 'PrivateRepo/hk-module-main', but it did not contain b22e0a5a2a8dce1d0454bdead70353bf45f33f81. Direct fetching of that commit failed.
原因分析:
未拉取到該submodule的最新代碼
解決
git submodule foreach git checkout master
git submodule foreach git submodule update
3.11 coapods私有化倉庫搭建
準(zhǔn)備工作
- 安裝cocoapods
- 準(zhǔn)備gitlab/gitee/getlab(下文統(tǒng)一稱為gitlab)等代碼倉庫賬號
創(chuàng)建組建索引Spec倉庫(用于存放組件庫的索引)
- 在gitlab中創(chuàng)建
XXSpecs倉庫,初始化README.md(目的是倉庫不為空)得到倉庫地址 - 在本地cocoapods中添加repo
pod repo add `specFileName(給spec倉庫在本地的命名)` `spec(倉庫的地址)`
實(shí)例:
pod repo add XXSpecs https://gitee.com/Steven_Hu/objective-c-specs
在~/.cocoapods/repos目錄中可以看到創(chuàng)建的文件夾

- 創(chuàng)建組件庫
- pod lib create #{庫的名稱}
- 實(shí)例 pod lib create XXLibDemo
- 修改podspec文件
- 將組件push到gitlab
- 將索引倉庫和組件倉庫關(guān)聯(lián)
- 項(xiàng)目引入
# 遠(yuǎn)程私有倉庫
source 'https://gitlab.com/xxxx/xxSpecs'
# 引入使用
pod 'xxLibNetwork'
4.常見問題補(bǔ)充
4.1target has transitive dependencies that include statically linked binaries:
解決辦法
s.static_framework = true
4.2CocoaPods did not set the base configuration of your project because your project already...
使用CocoaPods安裝三方庫后有兩個警告,如下所示:

解決辦法:
將第三方庫 的 PROJECT → Info → Configurations 下Debug和Release下的.debug和.release選項(xiàng)替換為None,如下圖所示:

然后在pod install即可
4.3清除 CocoaPods 本地緩存
特殊情況下,由于網(wǎng)絡(luò)或者別的原因,通過CocoaPods下載的文件可能會有問題。
這時候您可以刪除CocoaPods的緩存(~/Library/Caches/CocoaPods/Pods/Release目錄),再次導(dǎo)入即可。
4.4pod spec lint編譯時報(bào)error: include of non-modular header inside framework module
解決辦法
pod lib lint --allow-warnings --use-libraries --verbose
有警告??可以使用-allow-warnings忽略。
4.5推送到本地LocalRepo
- 使用了第三方庫
pod repo push driver_spec XXLibBase.podspec --allow-warnings --verbose --use-libraries
- 未使用第三方庫
pod repo push driver_spec XXLibBase.podspec --allow-warnings --verbose
4.6pod lib lint 可選參數(shù)
pod lib lint SPEC_NAME.podspec
可選參數(shù):
--verbose : 顯示詳細(xì)信息
--allow-warnings: 是否允許警告,用到第三方框架時,用這個參數(shù)可以屏蔽講稿
--fail-fast: 在出現(xiàn)第一個錯誤時就停止
--use-libraries:如果用到的第三方庫需要使用庫文件的話,會用到這個參數(shù)
--sources:如果一個庫的podspec包含除了cocoapods倉庫以外的其他庫的引用,則需要改參數(shù)指明,用逗號分隔。
--subspec=Name:用來校驗(yàn)?zāi)硞€子模塊的情況。
注意:如果庫用到了第三方的話要帶上 --use-libraries,否則會報(bào)錯,上傳不上去。
4.7--sources 使用
1.私有pod的驗(yàn)證
使用pod spec lint去驗(yàn)證私有庫能否通過驗(yàn)證時應(yīng)該,應(yīng)該要添加--sources選項(xiàng),不然會出現(xiàn)找不到repo的錯誤。
pod spec lint --sources='私有倉庫repo地址,https://github.com/CocoaPods/Specs'
2.私有庫引用私有庫的問題
在私有庫引用了私有庫的情況下,在驗(yàn)證和推送私有庫的情況下都要加上所有的資源地址,不然pod會默認(rèn)從官方repo查詢。
pod spec lint --sources='私有倉庫repo地址,https://github.com/CocoaPods/Specs'
pod repo push 本地repo名 podspec名 --sources='私有倉庫repo地址,https://github.com/CocoaPods/Specs'
4.組件化案例
1.效果圖

2.代碼地址
https://gitee.com/Steven_Hu/hk-iostools
搬磚不易,轉(zhuǎn)載請注明出處,謝謝!