【iOS】使用pod創建私有組件

創建組件工程

啟動命令行,使用pod命令創建組件

pod lib create ZTTools_Swift // 名字自己取,會自動創建相應的工程和文件夾

之后會彈出一些選項,按需要填即可:

// 選擇平臺
What platform do you want to use?? [ iOS / macOS ]
 > iOS

// 選擇語言
What language do you want to use?? [ Swift / ObjC ]
 > Swift

// 是否創建demo工程(一般都是需要的)
Would you like to include a demo application with your library? [ Yes / No ]
 > Yes

// 是否使用測試框架
Which testing frameworks will you use? [ Quick / None ]
 > None

// 是否創建UI單元測試
Would you like to do view based testing? [ Yes / No ]
 > No

至此,一個空的組件工程創建完畢。

清理單元測試

一般都用不上單元測試,使用可以把它給刪了。

  • 項目里把Tests文件夾刪了
  • 點擊工程,在TARGETS里把單元測試的target刪了
  • Podfile文件里,把單元測試的target全部內容刪了

創建私有xcframework

如果不創建私有庫,那你組件里的東西都會被看到,這不是我們想要的。
所以,我們需要創建一個庫,把代碼全放到這個庫里面,然后再把這個庫弄到組件里面。

xcframework與framework的對比

為什么我們要用.xcframework而不是.framework呢?
首先我們來看看這二者的區別:

  • .xcframework里面裝載了多個平臺的.framework,Xcode會自動選用正確指令集的.framework,也就是說編譯后或者上傳到App Store后只會包含單一平臺,同時也省去了手動移除動態庫中的模擬器指令集的工作
  • .framework雖然可以用lipo指令去合并多個.framework,但是,這是一個包含所有平臺的,這會造成APP體積變大,并且App Store上架時不允許有模擬器版本,還得手動移除模擬器的指令,這顯然很麻煩

創建私有framework工程

我們在組件工程里面再創建一個工程,選擇Framework選項,并且把其添加到組件的xcworkspace工作空間里。
配置工程,在General里取消掉對Mac的支持,并調整支持的iOS系統版本

修改Podfile文件

默認的Podfile文件是不支持多項目的,需要我們修改里面的內容。

  • platform的平臺和最低支持系統版本需要改為和項目的一致,同時項目里面的工程也全部保持一致
  • 添加workspace名字
  • 分別設置每個target的pod
  • target里面聲明對應的project路徑

project路徑是一個相對路徑,以Podfile文件所在的目錄為根目錄;一般來說,Podfile文件就在主工程那里,別的工程就以主工程做相對路徑


以下為Podfile文件示例:

#use_frameworks! # 全局配,也可以每個項目單獨配

platform :ios, '10.0'

# 工作空間名稱
workspace 'ZTTools_Swift.xcworkspace' # 同一個工作空間,多個Project使用pod時,需要添加工作空間名稱

# 主工程(帶podfile的工程)
target 'ZTTools_Swift_Example' do # target的名字
  use_frameworks! # 項目單獨配

  project 'ZTTools_Swift.xcodeproj' # 指明target的工程路徑;使用相對路徑,相對于Podfile文件

  pod 'ZTTools_Swift', :path => '../' # 組件的pod名
end

# 同一個工作空間里面別的項目依賴
target 'ZTTools' do

  use_frameworks! # 項目單獨配
  project '../ZTTools/ZTTools.xcodeproj'

  pod 'Alamofire'
  pod 'SnapKit'
end

如果遇到pod報錯,可嘗試使用sudo gem install cocoapods更新pods解決

創建自動化腳本

我們選中SDK項目,點擊File-New-Target,選中Other,然后選擇Aggregate,命名為SDKBuildScript,點擊完成。

舊版本的Xcode里,Aggregate是在Cross-platform里。

點擊File-New-File,選擇Shell Script,命名為SDKBuild,點擊創建(不要把它添加到Targets,不然會被編譯到Framework里的)。

把這段腳本復制到SDKBuild中,然后根據注釋修改為你自己的。
完成腳本編寫后,可以把Xcode里的SDKBuild文件刪了(但不要移除到廢紙簍

CONFIG="${CONFIGURATION}" # "Release" "${CONFIGURATION}" "Debug" 編譯模式,使用Release即可
SCHEME_NAME="${PROJECT_NAME}" # 要build的scheme名,如果和scheme名不一致,需要修改為正確的scheme名
OUTPUT_SDK="${SCHEME_NAME}" # 產物名字
OUTPUT_SDKNAME="${OUTPUT_SDK}.framework"

# 項目里存放Framework的路徑
TARGET_FOLDER="${SRCROOT}/../ZTTools_Swift/Classes"

# 工作空間路徑
WORK_FOLDER="${SRCROOT}/../Example/ZTTools_Swift.xcworkspace"

# ---------- 以上配置是可以修改的,下面的配置則不需要改 ----------

# 編譯時存放xcarchive的路徑
SIMULATOR_ARCHIVE_PATH="${SRCROOT}/build/${OUTPUT_SDK}-iphonesimulator.xcarchive"
DEVICE_ARCHIVE_PATH="${SRCROOT}/build/${OUTPUT_SDK}-iphoneos.xcarchive"

# 編譯時存放framework的路徑
SIMULATOR_DIR_PATH="${SIMULATOR_ARCHIVE_PATH}/Products/Library/Frameworks/${OUTPUT_SDKNAME}"
DEVICE_DIR_PATH="${DEVICE_ARCHIVE_PATH}/Products/Library/Frameworks/${OUTPUT_SDKNAME}"

function removeBuild()
{
    if [ -d "${SRCROOT}/build" ]
    then
    rm -rf "${SRCROOT}/build/"
    fi
}

function removeBuildFile()
{
    for FILE in $(ls "${1}"|tr " " "?")
    do
    if [[ "${FILE}" =~ ".xcconfig" ]]
    then
    rm -f "${1}/${FILE}"
    fi
    done
}

removeBuild
rm -rf "${TARGET_FOLDER}/${OUTPUT_SDK}.xcframework"

# 分別clean模擬器和真機
xcodebuild clean -workspace "${WORK_FOLDER}" -scheme "${SCHEME_NAME}" -configuration "${CONFIG}" -derivedDataPath "./build" -archivePath "${DEVICE_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES -sdk iphoneos
xcodebuild clean -workspace "${WORK_FOLDER}" -scheme "${SCHEME_NAME}" -configuration "${CONFIG}" -derivedDataPath "./build" -archivePath "${SIMULATOR_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES -sdk iphonesimulator

# 編譯真機的Framework
xcodebuild archive -workspace "${WORK_FOLDER}" -scheme "${SCHEME_NAME}" -configuration "${CONFIG}" -derivedDataPath "./build" -archivePath "${DEVICE_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES -sdk iphoneos

# 編譯模擬器的Framework
xcodebuild archive -workspace "${WORK_FOLDER}" -scheme "${SCHEME_NAME}" -configuration "${CONFIG}" -derivedDataPath "./build" -archivePath "${SIMULATOR_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES -sdk iphonesimulator

removeBuildFile "${DEVICE_DIR_PATH}"
removeBuildFile "${SIMULATOR_DIR_PATH}"
    
# 合并framework,創建xcframework
xcodebuild -create-xcframework \
-framework "${SIMULATOR_DIR_PATH}" \
-framework "${DEVICE_DIR_PATH}" \
-output "${TARGET_FOLDER}/${OUTPUT_SDK}.xcframework"

open "${TARGET_FOLDER}" # 打開文件夾

removeBuild

點擊SDK項目,然后在TARGETS里選中SDKBuildScript,上面選中Build Phases,點擊左上角的“+”號,選擇New Run Script Phase
在黑框里輸入./SDKBuild.sh

  • 當然你也可以直接把腳本寫在黑框里,這樣子就不需要創建腳本文件了
    如果使用腳本文件的話,會報沒權限的錯誤,所以需要使用命令行來打開權限(因為使用文件方便管理和編寫代碼,所以這里我選擇了使用文件的方式):
    打開命令行,cd到SDKBuild.sh所在的目錄,然后執行sudo chmod +x SDKBuild.sh即可解決權限問題
  • 在執行腳本前,需要配置好.podspec文件
  • 第一次運行腳本,編譯好庫后,需要自行執行一次pod install為demo工程安裝該SDK。此后就不需要再執行該命令了,因為腳本會把新打包好的SDK替換掉舊的SDK,如果配置有變,還是需要用pod命令進行更新
  • 更多SDK開發知識請看這篇文章:iOS】使用workspace搭建SDK開發框架

配置SDK工程

  • 點擊SDK項目,然后在TARGETS里選中SDK的target,點擊上面的Build Settings,找到Build Active Architecture Only項設置為NO(意思就是當前打包的framework支持所有的設備,否則打包時只能用當前版本的模擬器或真機運行)
  • Build Settings,找到Excluded Architectures項,點擊展開,在Release選項下點擊+號,選擇Any iOS Simulator SDK,值設置為arm64(處理arm64架構合并報錯的問題;當然,也可以在腳本里處理)
  • 點擊Edit Scheme..選中腳本的target,選中Run,把Build Configuration的值改為Release(設置生成的SDK為release版,當然也可以在腳本上設置,可以看腳本里的注釋)
  • 對于Swift工程,需要在Build Settings里找到Build libraries for Distribution,設置YES,否則在合并.xcframework時會報No ‘swiftinterface’ files found within xx.swiftmodule的錯(也可以在腳本設置)
  • 對于Swift工程,需要在Build Settings里找到Skip Install,設置NO,否則在歸檔的文件目錄Products下會沒有輸出文件(也可以在腳本設置)
  • PROJECTTARGETSBuild Settings里,找到
    Allow non-modular includes in Framework Modules,并都設置為YES;當動態庫需要引用第三方庫的Framework,需要告訴編譯器允許這種行為

如果工程報錯no such module 'XXX',并且pods工程下的Products文件夾里的產物全是紅的,說明了沒生成對應的庫。解決方法為:點擊Pods工程,在PROJECTBuild Settings里,找到Build Active Architecture Only設置為NOBase SDK設置為iOS;每次pod install后可能會被重置

git管理

創建組件的時候,已經默認創建了git,但是,這個git是組件的,現在得把SDK的git和組件的git進行分開,使得SDK的git作為組件git的子模塊進行管理。

創建遠程私有庫

因為SDK本身是沒有git的,所以需要用git init命令給它創建一個本地git倉庫。
創建好SDK工程的git后,需要編輯.gitignore文件,內容如下:

*~
.DS_Store
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xcbkptlist
*.xccheckout
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode
iOSInjectionProject/

然后再編輯組件的.gitignore文件,同樣是上面的內容。
隨后創建2個遠程倉庫,并把它們和本地git倉庫關聯起來。
需要注意的是,遠程倉庫里,SDK的是私有的,pod組件可以是公開的。(因為代碼都在SDK里,所以公開pod組件庫也不會有什么問題,而且使用起來也更方便

子模塊管理

我們為組件工程git添加子模塊,這個時候的git得是主模塊的git,即使用組件的git來執行添加命令。
添加子模塊的命令為git submodule add <url> <path>,其中url可以是遠程地址和本地地址,本地地址要用絕對對路徑,path則是該子模塊存儲的目錄路徑(使用相對路徑)。

  • 添加模塊之前,組件和SDK的git都需要先提交到遠程
  • 如果提交子模塊提示The following paths are ignored by one of your .gitignore files,則用git submodule add -f來添加

配置pod的索引文件

項目名.podspec文件(我這里是ZTTools_Swift.podspec),這個文件是用來描述這個pod的說明信息的。當pod install安裝庫時,只會引入你在.podspec中配置的那些文件。

Pod::Spec.new do |s|
  s.name             = '組件名'
  s.version          = '版本號'
  s.summary          = '組件精簡描述'

  s.description      = <<-DESC
組件詳細描述
                       DESC

  s.homepage         = '組件主頁'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { '用戶名' => '郵箱' }
  s.source           = { :git => 'git地址', :tag => s.version.to_s }
  
  # 需要設置,不然項目引入庫后會崩潰
  s.pod_target_xcconfig = {
  'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES'
 }
  s.user_target_xcconfig = { 'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES' }

  s.ios.deployment_target = '12.0' # 最低系統版本
  s.swift_versions = ['5.0'] # Swift版本
  s.vendored_frameworks = 'ZTTools_Swift/Classes/ZTToolsSDK.xcframework' # 使用私有庫
  s.frameworks = 'UIKit', 'Foundation', 'Photos', 'UserNotifications', 'AVFoundation', 'CoreGraphics'
  s.dependency 'Alamofire' # 依賴庫
  s.dependency 'SnapKit'

end

如果集成組件后,項目運行報One of the two will be used. Which one is undefined.,說明是符號沖突了,這個是pod的問題。實際上是因為你的組件包含了第三方pod,然后使用組件的工程也包含了這個第三方pod導致的,不喜歡這個提示是話,可以在使用組件的工程里,找到Pods文件夾,在該文件夾下所有的Pods-項目名.debug.xcconfigPods-項目名.release.xcconfig文件,找到文件里面的OTHER_LDFLAGS,把有提示重復的-l"第三方pod名"刪除即可

發布組件

校驗文件合法性

在發布之前,需要先轉到組件所在的文件夾,使用命令校驗.podspec文件。(可能需要翻墻
pod lib lint是基礎校驗命令,用來校驗本地.podspec文件的,如果要校驗遠程,把lib改為spec即可。(spec會同時驗證本地和遠程是否通過

  • 如果使用了第三方庫,需要在后面加上--use-libraries參數
  • 如果因為有警告導致報錯的,可以加上--allow-warnings參數解決
  • 如果需要輸出詳細信息,可以加上--verbose參數
  • 如果是私有的repo庫要就要加上--sources=“私有庫的地址”
  • 提示passed validation即為校驗通過
  • 提示[!] The spec did not pass validation即為校驗失敗
  • 只有校驗通過了,才能進行下一步操作
  • 一般來說,只需要校驗本地即可

發布

需要先轉到組件所在的文件夾,使用命令pod trunk me查看是否注冊trunk。
如果提示[!] Authentication token is invalid or unverified. Either verify it with the email that was sent or register a new session.說明還沒注冊過trunk或者登錄已經過期了,需要執行pod trunk register 郵箱 '名字' --description='描述文本' --verbose。(后面2個參數是可選的

如果輸出名字、郵箱和注冊時間等信息,說明已經是注冊并是登錄狀態。這個時候就可以提交組件到pod了。

使用命令pod trunk push xxx.podspec發布組件到pod,同樣的可以加上--allow-warnings--verbose參數;如果要跳過驗證pod是否導入,還可以加上--skip-import-validation參數。

  • 發布之前請先打上tag,不然會發布失敗
  • tag必須和.podspec文件的s.version一致
  • 如果之前打了tag并發布了,更新了文件后請用新的tag,不然不生效(也就是說,你修了一個小bug,想同一個版本號,把本地和遠程的tag刪了,再打上同樣的tag并推上遠程,這種方法是不可行的
  • 提交成功后,并不一定能馬上搜索到,需要等待一天左右

更新組件

  • 更新改動推送到遠程倉庫
  • 打tag,并推送到遠程倉庫
  • 執行發布命令即可

如果提示[!] You need to register a session first.,說明需要驗證會話。使用pod trunk register "你之前注冊的郵箱"后,去郵箱點擊鏈接驗證即可

其他

  • 使用命令pod trunk delete 組件名 版本號可以刪除已發布的庫的某一版本
  • 在組件文件夾里,有一個和組件名一樣的文件夾,里面有2個文件夾,分別是放置資源的Assets和放置源碼或者庫的Classes
  • 在組件文件夾里,有一個叫Example的文件夾,里面就是demo工程
  • 打開demo的工作空間后,在Pods工程里,有一個叫ReplaceMe的文件,是創建組件時默認生成的,刪除即可


歡迎來群139322447玩耍

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

推薦閱讀更多精彩內容