創建自己的CocoaPods的私有庫

在我們平時的開發中,一定出現過這樣的問題

  1. 創建了2個項目,一個項目卻是另一個項目的分身,修改代碼時需要修改2次。
  2. 新建項目時,從其他項目拖代碼至另一個項目復制代碼塊。
  3. 在眾多項目中,代碼塊重復太多,不知道哪一個是最新的。

以上問題,是我們開發常見的問題,為了解決這些問題,提高開發的質量,加快開發速度,我們有必要自己建立一套成熟的代碼庫,它可以反復使用并且反復迭代更新,一處修改,多處響應。

創建本地Pod

pod lib create ***

將會詢問以下內容:

  1. What Language do you want to use?? [Swift / objC]
  2. Would you like to include a demo application with your Library? [Yes / No]
  3. Would you like to do view based testing? [Yes / No]
  4. What is your class prefix?
    創建成功后會打開Xcode
    路徑

打開JQTools.xcworkspace

目錄結構

注意,所有類都必須放在classes文件夾下,在創建文件的時候,需要自己選擇一次。

Classes文件夾

引用本地的pod

我建議新建的本地庫先在本地進行長時間測試,這樣可以方便的修改和維護,不用每次修改都要提交一次,更新pod。等你覺得它變得已經很穩定了,再提交至pod,當然代碼還是要提交至遠程倉庫的。

pod 'JQTools',:path=> '/Users/***/MyProject/JQTools'

每次修改后,都要clear一次,前期你一定會大量的使用

配置podspec

  • s.version : 版本號,這里的版本號與Github倉庫中的Tag一一對應
  • s.summary : 你的Pod庫的總結性描述.
  • s.description : 你的Pod庫的具體描述,【這里要注意,s.description的長度必須大于s.summary】
  • s.source: 指向對應的GitHub倉庫.
  • s.dependency:表示依賴庫
  • s.public_header_files:是要公開的頭文件
  • s.frameworks:依賴庫
  s.ios.deployment_target = '10.0'
  s.source_files = 'JQTools/Classes/**/*'
  
//圖片,文件等資源
   s.resource_bundles = {
     'JQToolsRes' => ['JQTools/Assets/*']
   }

  # s.public_header_files = 'Pod/Classes/Header.h'

//依賴庫
   s.frameworks = 'UIKit'
   s.dependency 'SnapKit'
   s.dependency 'ObjectMapper'
   s.dependency 'QMUIKit', '~> 4.0.4'
   s.dependency 'IQKeyboardManagerSwift', '~> 6.5.5'
   s.dependency 'RxSwift','~> 5.1.1'
   s.dependency 'RxCocoa','~> 5.1.1'
   s.dependency 'SwiftyUserDefaults', '4.0.0-alpha.1'

以上,你已經成功的建立了自己的pod,已經可以進行使用了,建議你先在本地進行測試和使用,穩定后提交自己的pod。




1. 登錄Github創建一個public倉庫

創建過程略

2. 回到本地和遠程倉庫綁定

git remote add origin https://github.com/***/****.git

提交

  1. 創建trunk賬號

trunk需要pod在0.33及以上版本;pod --version檢查你的版本,如果版本過低sudo gem install cocoapods進行更新。

  • 可以先檢查是否已注冊:pod trunk me
  • 進行注冊:pod trunk register ***@qq.com yourName

然后你的郵件將受到信息,進行認證即可

驗證Pod

pod lib lint **.podspec # 不爆紅就是對的
#或
pod lib lint # 你在你的文件目錄下

提交pod

pod trunk push

查詢你的pod

pod search WKUIKit

常見問題

1. 如何配置Bundle資源

資源文件,需要放在Assets文件夾下,并且在podspec中指定,注意你指定的名稱

   s.resource_bundles = {
     'JQToolsRes' => ['JQTools/Assets/*']
   }

2. 如何引用未使用的類

比如本地pod并沒有引用QMUIKit,但你對它進行了擴展支持,那么在項目將會報錯,可以使用宏canImport,務必將要使用的方法和類用public

#if canImport(QMUIKit)
import QMUIKit

public func A(){
    //todo
}
#end

如果是OC

#if __has_include("QMUIKit/QMUIKit.h")
#import <QMUIKit/QMUIKit.h>
#endif

3. 模擬器與真機判斷

有些方法和類在真機和模擬器有比較大的區別,所有在宏定義上面需要區分

關鍵詞:targetEnvironment

        #if targetEnvironment(simulator)
        if fmodl(Float80(Double(self)), 1) == 0 {//如果有一位小數點
            return (NSString(format: "%.0f", self) as String)
        } else if (fmodf(Float(self*10), 1) == 0) {//如果有兩位小數點
            return (NSString(format: "%.1f", self) as String)
        } else {
            return (NSString(format: "%.2f", self) as String)
        }
        #else
        if fmodl(Double(self), 1) == 0 {//如果有一位小數點
            return (NSString(format: "%.0f", self) as String)
        } else if (fmodf(Float(self*10), 1) == 0) {//如果有兩位小數點
            return (NSString(format: "%.1f", self) as String)
        } else {
            return (NSString(format: "%.2f", self) as String)
        }
        #endif

4. 自己的pod的Bundle讀取

let mainBundle  = Bundle(for: type(of: self))
let path = mainBundle.path(forResource: "JQToolsRes", ofType: "bundle")
let jqToolsBundle = Bundle(path: path!)
let filePath = jqToolsBundle?.path(forResource: "citysCode", ofType: "txt")

如果在修改自己的庫里的某些代碼,需要資源的時候,建議你這樣寫:

let mainBundle  = Bundle(for: type(of: self))

如果已經被項目引用,上面的寫法就不對了需要改成這樣:

let mainBundle  = Bundle(for: JQTool.self)

例子一:讀區Resources下的城市表:

image.png
        let mainBundle  = Bundle(for: JQTool.self)
        let path = mainBundle.path(forResource: "JQToolsRes", ofType: "bundle")
        let jqToolsBundle = Bundle(path: path!)
        let filePath = jqToolsBundle?.path(forResource: "citysCode", ofType: "txt")
    
        do {
            let content = try String(contentsOfFile: filePath!)
            print(content)
        } catch  {

        }

為什么是JQToolsRes?前面我們已經在podspec里面配置了,成為了一個bundle

   s.resource_bundles = {
     'JQToolsRes' => ['JQTools/Assets/*']
   }

例子二:讀取Resources下的bundle中的圖片

image.png

在Icon.bundle中有一張ty_qrcode_bg的圖片

        var a = Bundle(for: JQTool.self).path(forResource: "Icon", ofType: "bundle")
        let jqToolBundle = Bundle(path: a!)
        let image = UIImage(named: "ty_qrcode_bg", in: jqToolBundle, compatibleWith: .none)

例子三:讀取Resources下的*.xcassets

image.png
        let a = Bundle(for: JQTool.self)
        let image = UIImage(named: "ty_qrcode_line", in: a, compatibleWith: .none)

5. Swift項目中使用OC

為了統一管理OC類,重寫組織了結構:


image.png

并在Header中暴露了兩個OC類


image.png

如果你出現以下錯誤


image.png

將private的類提升至public


image.png

再將header.h放置Support files-> XXXX-umbrella.h 中

然后就可以在Pod里或源項目中使用了。


進一步 提高效率開發

一個真正成熟的庫,就需要運用到實際的開發項目中,當是一個團隊開發時,一個人進行庫的維護所花費精力巨大,所以需要進行協同維護

  1. 定義好命名規則
  2. 定義好模塊分類
  3. 完美的注釋說明
    等等

查看pod trunk --help

image.png

你會發現可以使用add-owner添加擁有者,賦予對庫的更新操作,當不在需要此人來進行維護,remove-owner即可,這種方式比較符合公司庫的管理,這也是建立公司敏捷開發所需要的

更進一步:一切為了安全

  1. 制作frmaework庫
  2. 開發framework庫

NOTE:OC需要將Header進行暴露提升,Swift靠public關鍵詞,同時要將OC文件放置XXXFramework.h

runScript

image.png

image.png
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"

編輯 \*.podspec文件

s.vendored_frameworks = ['JQTools/Classes/Framework/FrameworkDemo.framework'] # 添加私有的Framework

進行pod install

image.png

  1. 報錯:Multiple commands produce....

如果你把framework放在了Classes,重新pod install 時,多引用了,保留以上圖片的,刪除其他引用即可。

  1. 報錯:Framework not found:
#import "TestFramework.h" //改為 #import "TestFramework/TestFramework.h"

總結

trunk 提交至 pod 報錯:

  1. warning: Could not find remote branch 0.1 to clone. fatal: Remote branch 0.1 not found in upstream origin

給git倉庫打上標簽,podspecs.version = 0.1

git tag '0.1'  
git push --tags  
git push origin master

提交倉庫報錯:hint: Updates were rejected because the tag already exists in the remote.

提交時,未提交Tag標簽,導致沖突

git pull --tags

2. error: include of non-modular header inside framework module 'XXXX.Header'
如果你是OC,與Swift的混編,并且出現的錯誤都是OC的XXX.h

本地pod包的建立,算是你所有開發使用的精華,能夠一處變動,全項目修改,你會遇到一個問題:你的代碼封裝定會用到其他第三方,比如你封裝了一個下載圖片的類,A項目適合,但B項目并不需要,如果B項目不去pod依賴的其他的第三方,那么你封裝下載圖片的類會因為沒有引用而報錯,B項目就不得不去pod,從而導致B項目過于臃腫。
解決的方法:
你可以移除本地的pod依賴,在實際項目看情況使用。canImport宏進行了一次判斷,如果不可用,就不能使用,也不會報錯。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容