前言
上一節我們通過把代碼簡單的拆分上傳至github
,通過cocoapods
的遠程私有庫,把拆分的代碼當作第三方庫供我們使用,但是這種方式存在很多問題,實際項目使用這種簡單粗暴的拆分也不可取,所以今天講上一篇博客提到的第二種私有庫創建方式,后面統一把私有庫稱作組件。
最后大概結構
本文要講的是改變組件創建的方式,解決:
- 組件使用
.framework
或者.a
這兩種靜態庫的方式創建 - 組件單獨依賴第三方,即有自己的
podfile
文件配置使用 - 組件有自己單獨的資源文件,在自己組件中使用資源文件
- 組件工程調試及配置使用
吐槽部分可跳過
關于創建靜態庫的方式:
- 使用pod命令也就是
pod lib
命令創建 - 自己通過
xcode
手動創建
兩種方式也無所謂好壞,都能夠達到創建組件的目的。我想要說的是手動創建好處:
- 手動創建可以知道創建過程都做了什么,
pod
命令如果不去深究不能很明白原理。 -
pod
命令創建的組件只能放在Development Pods
文件夾目錄下
,對于手動創建使用target
依賴的方式的方式來說顯得不是很友好。 -
pod
命令創建的組件要添加資源文件時配置麻煩,手動創建簡單。
當然手動創建也有缺點:
-
pod
命令創建方便快捷,手動創建相對步驟多 - 創建和編譯過程需要踩坑。
總結:
- 如果是單純抽取一些小東西用命令就可以沒必要折騰
- 如果項目要大規模使用組件化建議手動創建方式
正文
上面說過創建組件靜態庫有兩種,一種是.framwework另外一種是.a,兩種方式創建大同小異。這里先以創建.a靜態庫的方式創建,相關節點配置不同點我會說明。
創建
打開xcode創建進入選擇創建菜單
上圖中Cocoa Touch Framework
就是創建.framework
靜態庫的方式,我們先創建.a形式的靜態庫 選中Cocoa Touch Static Library
點擊 next
,填寫你組件靜態庫的名稱完成。
創建好之后像這樣:
初始文件:
- 幫我們創建和靜態庫名稱一樣的文件夾和類(頭文件)。
- 把創建的頭文件加入到
Copy Files
里面,這里要關心的一點是,如果你修改了頭文件這里也要添加相應你要暴露的頭文件,這里的頭文件可以是多個也就是你想暴露多少個就添加多少個。
添加podfile:
使用pod init
命令在根目錄添加 podfile
,這里簡單添加Masonry
platform :ios, '8.0'
target 'StaticKit' do
pod 'Masonry'
end
進行pod install
命令之后我們可以看到pod
給我們黃色的警告
主要是前面的錯誤:
[!] The Podfile contains framework or static library targets (StaticKit), for which the Podfile does not contain host targets (targets which embed the framework).
If this project is for doing framework development, you can ignore this message. Otherwise, add a target to the Podfile that embeds these frameworks to make this message go away (e.g. a test target).
這大概的意思是說當前的target
為靜態庫,而且pod
依賴的是當前這個靜態庫不是依賴host targets
,host targets
我的理解是可執行的target
,當時我沒注意這個警告以為是普通的警告,之后添加到殼工程的時候會提示該靜態庫的pod
找不到。
當然最后如果我們認真看提示的警告已經告訴了我們解決的辦法了,最后一行的括號內(e.g. a test target)
。這就是讓我們創建一個測試的target
然pod
依賴它就可以讓這個警告消失。這個很多網上文章都是一筆帶過沒說清楚的,不然就是不提靜態庫添加第三方依賴的問題,當然我的解釋也不一定對。
靜態庫需要添加一個測試target
讓第三方依賴
添加測試target
:
點擊+
按鈕進入選擇target
菜單
選中iOS Unit Testing Bundle
取名為 StaticKitTests
創建好之后是這樣
修改podfile
重新更新
platform :ios, '8.0'
project 'StaticKit'
#修改為測試的target
target 'StaticKitTests' do
pod 'Masonry'
end
更新后的 pod
信息,發現已經正常了
到這里如果你把Masonry 導入項目的類的時候會發現提示無法找到頭文件,這時候我們要設置Heaser Search Paths 設置路徑 添加 "$(SRCROOT)/Pods/Headers/Public"
添加資源文件:
添加資源文件我一般可以簡單創建一個bundle放到工程目錄下,使用時添加工程下就行了。這種方式很簡單也是可以用的,但是這樣的方式不容易管理我們的資源文件。在這里我推薦把資源文件也當作一個target
添加到靜態庫組件中,過程和上面創建測試target
差不多只是需要一些配置。
點擊+
好到創建target
界面,tab頁選中macOS
下面的 Bundle
,下一步 我取名為StaticKit_res
按自己需要可以改名字
創建好之后是這樣的
創建的時候你可以看到我們創建的是macOS
的bundle
,至于為什么要用mac
不用iOS
很簡單因為iOS
沒有這個選項,所以為了適配iOS
我們需要做下面兩個配置
- 配置
Base SDK
為iOS
配置路徑看下圖
- 一般我們圖片有
@2x
@3x
這樣放在bundle
會導致讀取圖片失敗,所以我們要改下配置,把COMBINE_HIDPI_IMAGES
設置為NO
讀取資源文件:
我們的組件的資源文件基礎配置已經好了,接下來要添加一個工具類來讀取資源了,在這里我們以讀取圖片資源為例,其他的資源大同小異。
- 我們添加幾張測試圖片放到
staticKit_res
文件夾下,記得target
的選擇
- 創建我們的工具類名稱為
StaticKitHelper
代碼如下
@interface StaticKitHelper : NSObject
+ (NSBundle *)resBundle:(Class)classtype;
+ (UIImage*)imageName:(NSString*)name;
@end
#import "StaticKitHelper.h"
@implementation StaticKitHelper
+ (NSBundle *)resBundle:(Class)classtype {
static NSBundle *framworkBundle = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
framworkBundle = [NSBundle bundleForClass:classtype];
if (framworkBundle) {
NSString *resourceBundlePath = [framworkBundle pathForResource:@"StaticKit_res" ofType:@"bundle"];
if (resourceBundlePath && [[NSFileManager defaultManager] fileExistsAtPath:resourceBundlePath]) {
framworkBundle = [NSBundle bundleWithPath:resourceBundlePath];
}
}
});
return framworkBundle;
}
+ (UIImage*)imageName:(NSString*)name {
if (name.length == 0) {
return nil;
}
NSBundle *bundle = [StaticKitHelper resBundle:[self class]];
NSString *path = [bundle pathForResource:name ofType:@"png"];
return [UIImage imageWithContentsOfFile:path];
}
@end
//調用
UIImage *image = [StaticKitHelper imageName:@"PlayButtonOverlayLarge"];
添加測試代碼:
通過上面的設置我們的.a靜態庫組件基礎配置已經好了,接下來我們要添加測試代碼,我這里把默認的頭文件普通的類改成一個控制器類,設置背景為藍色,并添加了一張圖片:
#import "StaticKit.h"
#import "StaticKitHelper.h"
#import <Masonry/Masonry.h>
@implementation StaticKit
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"StaticKit控制器";
UIImage *image = [StaticKitHelper imageName:@"PlayButtonOverlayLarge"];
UIImageView *imageView = [UIImageView new];
imageView.image = image;
[self.view addSubview:imageView];
[imageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view).offset(100);
make.top.equalTo(self.view).offset(100);
make.size.mas_equalTo(CGSizeMake(40, 40));
}];
self.view.backgroundColor = [UIColor blueColor];
}
@end
到這里StaticKit組件已經是一個合格的靜態庫組件了,它可以參與模塊的開發了,最后總結下大概的步驟:
- 打開
xcode
創建Cocoa Touch Static Library
設置組件名字 - 添加測試
target
,創建podfile
設置依賴的target
為測試StaticKitTests
- 添加資源文件
target
StaticKit_res 設置兩個編譯參數,導入測試圖片 - 添加讀取資源工具類,添加測試代碼
- 編寫的代碼在自己的靜態庫組件內編譯通過
添加殼工程調試:
- 準備工作
所謂的殼工程就是我平常創建可以直接運行的工程,你可以隨便創建一個帶導航欄的控制器,用于push
到我們的靜態庫組件供調試,這個步驟很簡單就不廢話了默認你已經創建好了殼工程。
- 添加到殼工程
- 打開殼工程將
StaticKit.xcodeproj
拖到殼工程下
- 點擊殼工程選中
Build Phases
在Target Dependencies
下點+
號 添加StaticKit
和StaticKit_res
- 在同一個地方的
Link Binary With Libraries
添加StaticKit
- 在靜態庫中的
Products
文件夾下的StaticKit_res
拖到Copy Bundle Resources
下
- 編譯下如果顯示成功就算大功告成了,如果有報錯你可以回頭看上面那個步驟做錯了或者漏了。
這里解釋下
第一步沒什么好解釋的。
第二步是我們把兩個target
當作子target
依賴殼工程。
第三步表示代碼執行我們鏈接的是StacKit
這個target
而不包含StaticKit_res
。
第四步是把我們靜態庫的資源文件添加到mainBundle
里面這樣我們才可以通過代碼找得到它。
添加殼工程測試代碼:
//第三方方式訪問,這個頭文件在我們創建的時候有說要設置才能訪問
#import <StaticKit/StaticKit.h>
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"點擊跳轉到庫";
}[圖片上傳中...(show.gif-f0b9fe-1530268184126-0)]
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
StaticKit *sk = [[StaticKit alloc]init];
[self.navigationController pushViewController:sk animated:YES];
}
@end
運行截圖
到這里自己手動創建.a靜態庫的全過程就完了,接下來會說.a靜態庫和.framework靜態庫配置,framework的創建和.a基本流程是一致的,某些配置有細微差別。
.framework靜態庫的差異
- framework的靜態庫創建的時候默認都是動態的,但是上架是不允許動態的所以我要在
Build Settings
里面的Mach-O Type
設置為Static Library
2.framework設置的頭文件不一樣,framework創建的時候頭文件都會默認顯示在Project
下我們需要把它拖到Public
下
3.最后一個不同點就是加人殼工程是frameworkKit.framework
不需要加入到Target Dependencies
下
本文到這里就交代完手動創建靜態庫到調試的全部內容了,如果有寫錯的地方或者有什么問題你可以在本文下方評論,也希望大家都交流學習。下篇帶大家編譯靜態庫到遠程私有庫,敬請期待!
參考資料
https://www.raywenderlich.com/65964/create-a-framework-for-ios
https://github.com/jverkoey/iOS-Framework