何為組件化
一種能夠解決代碼耦合的技術(shù)。項(xiàng)目經(jīng)過組件化的拆分挪丢,不僅可以解決代碼耦合的問題登刺,還可以增強(qiáng)代碼的復(fù)用性,工程的易管理性爱葵,減少編譯時(shí)間等
1.組件化分層架構(gòu)圖
2.架構(gòu)分層詳解
1.Lib層
基礎(chǔ)模塊跟業(yè)務(wù)無關(guān)施戴,只定義接口和基本配置,子類可以重寫萌丈,便于擴(kuò)展
- LibBase
- LibBaseController
- LibBaseNavController
- ...
- LibCommon基礎(chǔ)公共組件
- LibFlexBox移動(dòng)端FlexBox布局
Widget層
- 由Lib延伸而來赞哗,便于組件的擴(kuò)展和復(fù)用
2.Mediator層
- 采用Bifrost框架,創(chuàng)建調(diào)度組件并定義交互協(xié)議辆雾,處理業(yè)務(wù)模塊之間的數(shù)據(jù)傳遞及邏輯交互處理
- Module層必須依賴該庫(kù)
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私有化倉(cāng)庫(kù)搭建
**
3.1多Target分模塊開發(fā)湿右,代碼解耦
workspace 依賴多個(gè)功能文件開發(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)目
- 最簡(jiǎn)單的方式罚勾,通過項(xiàng)目名稱:ProjectName
[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleExecutableKey]
- 判斷項(xiàng)目名稱是否和子項(xiàng)目名稱一致即可
3.3組件之間傳值Bifrost
注冊(cè)路由(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];
頁(yè)面?zhèn)髦?/h4>
- 以type為例
//1.當(dāng)前頁(yè)面聲明一個(gè)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];
頁(yè)面回調(diào)處理
//1.當(dāng)前頁(yè)面聲明一個(gè)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組件間訪問公共圖片資源
主工程有一個(gè)a.png
的圖片毅人,而pod
庫(kù)里面也有一個(gè)a.png
的圖片,此時(shí)就產(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
會(huì)自動(dòng)生成bundle
把資源文件打包進(jìn)去
加載本地資源方法
工具類抽取
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ModuleBundle : NSObject
/*
* 根據(jù)bundle的名稱獲取bundle
*/
+ (NSBundle *)bundleWithName:(NSString *)bundleName;
//獲取bundle 每次只要重寫這個(gè)方法就可以在指定的bundle中獲取對(duì)應(yīng)資源
+ (NSBundle *)bundle;
//根據(jù)xib文件名稱獲取xib文件
+ (__kindof UIView *)viewWithXibFileName:(NSString *)fileName;
//根據(jù)圖片名稱獲取圖片
+ (UIImage *)imageNamed:(NSString *)imageName;
//根據(jù)sb文件名稱獲取對(duì)應(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;
}
//如果沒有國(guó)際化送丰,則直接去相應(yīng)內(nèi)容下的文件
UIView *xibView = [[bundle loadNibNamed:fileName owner:nil options:nil] lastObject];
if(!xibView) {
//文件國(guó)際化之后缔俄,所有的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)前頁(yè)面聲明一個(gè)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)前頁(yè)面聲明一個(gè)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];
主工程有一個(gè)a.png
的圖片毅人,而pod
庫(kù)里面也有一個(gè)a.png
的圖片,此時(shí)就產(chǎn)生命名沖突了
# resource_bundles
s.resource_bundles = {
'HKLibCommon' => ['HKLibCommon/**/*.{xib,jpg,gif,png,xcassets}']
}
resource_bundles
會(huì)自動(dòng)生成bundle
把資源文件打包進(jìn)去#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ModuleBundle : NSObject
/*
* 根據(jù)bundle的名稱獲取bundle
*/
+ (NSBundle *)bundleWithName:(NSString *)bundleName;
//獲取bundle 每次只要重寫這個(gè)方法就可以在指定的bundle中獲取對(duì)應(yīng)資源
+ (NSBundle *)bundle;
//根據(jù)xib文件名稱獲取xib文件
+ (__kindof UIView *)viewWithXibFileName:(NSString *)fileName;
//根據(jù)圖片名稱獲取圖片
+ (UIImage *)imageNamed:(NSString *)imageName;
//根據(jù)sb文件名稱獲取對(duì)應(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;
}
//如果沒有國(guó)際化送丰,則直接去相應(yīng)內(nèi)容下的文件
UIView *xibView = [[bundle loadNibNamed:fileName owner:nil options:nil] lastObject];
if(!xibView) {
//文件國(guó)際化之后缔俄,所有的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)建一個(gè)類CommonBundle繼承自ModuleBundle,并實(shí)現(xiàn)以下方法
#import "CommonBundle.h"
@implementation CommonBundle
+ (NSBundle *)bundle{
//TODO:注意Bundle名字需跟模塊名稱一致器躏,否則會(huì)找不到path俐载,直接Crash
return [self.class bundleWithName:@"HKLibCommon"];
}
@end
使用
替換系統(tǒng)加載圖片的方式:[UIImage imageNamed:@"navigationbar_background"]
[CommonBundle imageNamed:@"navigationbar_background"]
多個(gè)包
spec.resource_bundles = {
'MapBox' => ['MapView/Map/Resources/*.png'],
'OtherResources' => ['MapView/Map/OtherResources/*.png']
}
3.5文件夾分層子組件subspec
我們?cè)诰帉憄odspec文件時(shí),sourcefiles只是告訴pods你需要哪些文件是這個(gè)項(xiàng)目中需要的登失,而沒有包括文件的層級(jí)結(jié)構(gòu)遏佣,那么就需要我們來實(shí)現(xiàn)這個(gè)層級(jí)結(jié)構(gòu):subspec
比如這里面的每一個(gè)文件夾,就是一個(gè)子pod揽浙,這樣的好處是條理清晰状婶,而且我們可以只用你需要的功能,在編寫podfile時(shí) 就可以這樣寫
pod 'HKModuleModels/User'
只使用其中的一個(gè)功能馅巷。
主podspec
主pod可以是一個(gè)頭文件膛虫,也可以具有一定的功能,我寫的組件sourcefiles只是一個(gè)import子組件的頭文件钓猬, sourcebundle是項(xiàng)目中需要的一些圖片
編寫subspec
- 讓pods支持子subspec其實(shí)很簡(jiǎn)單走敌,只要搞清楚三件事
- 文件夾結(jié)構(gòu) subspec sourcefiles的路徑
- subspec 所依賴的系統(tǒng)庫(kù)
- subspec 所依賴的第三方,和其它subspec的路徑
3.6pod 引入依賴方式
引入本地依賴
pod 'ManageLocalCode', :path => '../ManageLocalCode'
pod 'BioAuthAPI', :path => '../BioAuthAPI'
pod 'HKTool', :path => '../'
遠(yuǎn)程私有庫(kù)依賴:
# 基礎(chǔ)宏定義byStevenHu
pod 'HKMacros', :git => 'https://gitee.com/Steven_Hu/HKMacros.git'
指定分支
# 支付代碼測(cè)試
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:首頁(yè)模塊 |
調(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中有中文等特殊字符時(shí)需要進(jìn)行urlEncode逗噩。
app外鏈外鏈
格式說明
- appscheme分解
- 項(xiàng)目名稱
- yunque
- 業(yè)務(wù)側(cè)
- driver
- user
- 項(xiàng)目名稱
- moduleName
- 業(yè)務(wù)模塊名稱
- pageName
- 頁(yè)面名稱
- secondPage
- 二級(jí)頁(yè)面
scheme
云雀司機(jī): yunquedriver
云雀用戶:yunqueuser
模塊名
lib:工具類掉丽,跟業(yè)務(wù)無關(guān)的
頁(yè)面
3.9 podspec使用及格式校驗(yàn)
注意事項(xiàng)
- podspec版本號(hào)和git倉(cāng)庫(kù)代碼的tag版本必須一致,否則找不到
- 比如:pod lib 默認(rèn)生成的是0.1.0异雁,我們根據(jù)業(yè)務(wù)需要改成0.0.1
- 索引倉(cāng)庫(kù)和組件倉(cāng)庫(kù)關(guān)聯(lián)
- cd到組件倉(cāng)庫(kù)目錄下
- pod repo push
#{本地關(guān)聯(lián)到遠(yuǎn)程倉(cāng)庫(kù)的名字}
#{第三方私有庫(kù)的podspec文件}
--verbose --allow-warnings 示例: pod repo push YNSpecs YNLibDemo.podspec --verbose --allow-warnings
- 項(xiàng)目引入
# 遠(yuǎn)程私有倉(cāng)庫(kù)
source 'https://gitlab.com/xxxx/xxSpecs'
# 引入使用
pod 'xxLibNetwork'
3.10 組件間依賴管理
通過 git submodule add https://gitee.com/Steven_Hu/hk-module-components.git 添加submodule
會(huì)在git上添加一個(gè).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倉(cāng)庫(kù)地址
本地Clone方式
git clone https://gitee.com/Steven_Hu/hk-iostools.git
git submodule init && git submodule update
#下面這一句的效果和上面三條命令的效果是一樣的,多加了個(gè)參數(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私有化倉(cāng)庫(kù)搭建
準(zhǔn)備工作
- 安裝cocoapods
- 準(zhǔn)備gitlab/gitee/getlab(下文統(tǒng)一稱為gitlab)等代碼倉(cāng)庫(kù)賬號(hào)
創(chuàng)建組建索引Spec倉(cāng)庫(kù)(用于存放組件庫(kù)的索引)
- 在gitlab中創(chuàng)建
XXSpecs
倉(cāng)庫(kù)纲刀,初始化README.md(目的是倉(cāng)庫(kù)不為空)得到倉(cāng)庫(kù)地址 - 在本地cocoapods中添加repo
pod repo add `specFileName(給spec倉(cāng)庫(kù)在本地的命名)` `spec(倉(cāng)庫(kù)的地址)`
實(shí)例:
pod repo add XXSpecs https://gitee.com/Steven_Hu/objective-c-specs
在~/.cocoapods/repos
目錄中可以看到創(chuàng)建的文件夾
- 創(chuàng)建組件庫(kù)
- pod lib create #{庫(kù)的名稱}
- 實(shí)例 pod lib create XXLibDemo
- 修改podspec文件
- 將組件push到gitlab
- 將索引倉(cāng)庫(kù)和組件倉(cāng)庫(kù)關(guān)聯(lián)
- 項(xiàng)目引入
# 遠(yuǎn)程私有倉(cāng)庫(kù)
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安裝三方庫(kù)后有兩個(gè)警告,如下所示:
解決辦法:
將第三方庫(kù) 的 PROJECT → Info → Configurations 下Debug和Release下的.debug和.release選項(xiàng)替換為None,如下圖所示:
然后在pod install
即可
4.3清除 CocoaPods 本地緩存
特殊情況下项炼,由于網(wǎng)絡(luò)或者別的原因,通過CocoaPods下載的文件可能會(huì)有問題。
這時(shí)候您可以刪除CocoaPods的緩存(~/Library/Caches/CocoaPods/Pods/Release目錄)锭部,再次導(dǎo)入即可暂论。
4.4pod spec lint編譯時(shí)報(bào)error: include of non-modular header inside framework module
解決辦法
pod lib lint --allow-warnings --use-libraries --verbose
有警告??可以使用-allow-warnings忽略。
4.5推送到本地LocalRepo
- 使用了第三方庫(kù)
pod repo push driver_spec XXLibBase.podspec --allow-warnings --verbose --use-libraries
- 未使用第三方庫(kù)
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í)拌禾,用這個(gè)參數(shù)可以屏蔽講稿
--fail-fast: 在出現(xiàn)第一個(gè)錯(cuò)誤時(shí)就停止
--use-libraries:如果用到的第三方庫(kù)需要使用庫(kù)文件的話取胎,會(huì)用到這個(gè)參數(shù)
--sources:如果一個(gè)庫(kù)的podspec包含除了cocoapods倉(cāng)庫(kù)以外的其他庫(kù)的引用,則需要改參數(shù)指明湃窍,用逗號(hào)分隔闻蛀。
--subspec=Name:用來校驗(yàn)?zāi)硞€(gè)子模塊的情況。
注意:如果庫(kù)用到了第三方的話要帶上 --use-libraries您市,否則會(huì)報(bào)錯(cuò)觉痛,上傳不上去。
4.7--sources 使用
1.私有pod的驗(yàn)證
使用pod spec lint去驗(yàn)證私有庫(kù)能否通過驗(yàn)證時(shí)應(yīng)該茵休,應(yīng)該要添加--sources選項(xiàng)薪棒,不然會(huì)出現(xiàn)找不到repo的錯(cuò)誤。
pod spec lint --sources='私有倉(cāng)庫(kù)repo地址,https://github.com/CocoaPods/Specs'
2.私有庫(kù)引用私有庫(kù)的問題
在私有庫(kù)引用了私有庫(kù)的情況下榕莺,在驗(yàn)證和推送私有庫(kù)的情況下都要加上所有的資源地址盗尸,不然pod會(huì)默認(rèn)從官方repo查詢。
pod spec lint --sources='私有倉(cāng)庫(kù)repo地址,https://github.com/CocoaPods/Specs'
pod repo push 本地repo名 podspec名 --sources='私有倉(cāng)庫(kù)repo地址,https://github.com/CocoaPods/Specs'
4.組件化案例
1.效果圖
2.代碼地址
https://gitee.com/Steven_Hu/hk-iostools
搬磚不易帽撑,轉(zhuǎn)載請(qǐng)注明出處,謝謝鞍时!