這裏輸入引用文本本文記錄一下,在SDK開發完成後,如何高效率製做framework。swift
##iOS關於靜態庫、動態庫的一些基本概念和理解誤區 ###1. 庫 庫是源代碼通過編譯,造成的二進制代碼,別人項目中使用咱們的庫的時候,庫在參與編譯的時候,直接link就OK了,按照link的方式,能夠把庫分爲靜態庫和動態庫 ###2. 靜態庫 靜態庫在編譯的時候會被直接拷貝一份,複製到目標程序裏,這段代碼在目標程序裏就不會再改變了。xcode
通常以**.a** 和 .framework爲文件後綴名安全
這種作法是犧牲應用「體量」來節省編譯時間。 ###3. 動態庫 與靜態庫相反,動態庫在編譯時並不會被拷貝到目標程序中,目標程序中只會存儲指向動態庫的引用。等到程序運行時,動態庫纔會被真正加載進來。app
動態庫的優勢是,不須要拷貝到目標程序中,不會影響目標程序的體積,並且同一份庫能夠被多個程序使用(由於這個緣由,動態庫也被稱做共享庫)。框架
同時,編譯時才載入的特性,也可讓咱們隨時對庫進行替換,而不須要從新編譯代碼。動態庫帶來的問題主要是,動態載入會帶來一部分性能損失,使用動態庫也會使得程序依賴於外部環境。若是環境缺乏動態庫或者庫的版本不正確,就會致使程序沒法運行iphone
以**.tbd**(以前叫.dylib) 和** .framework** 爲文件後綴名工具
蘋果系統爲咱們提供了不少動態連接庫,咱們能夠在咱們項目工程中查看一下性能
###4. Framework Framework 是一種打包方式,將庫的二進制文件,頭文件和有關的資源文件打包到一塊兒,方便管理和分發。測試
Framework只是一種打包方式,其自己和靜態、動態無關!ui
但Cocoa Touch Framework 的實際內容爲 Header + 動態連接庫 + 資源文件
###5. 對Framework認識的誤區 誤區①:.framework是動態庫,.a是靜態庫,前面已經講過,再也不贅述
誤區②:有人說「自定義的動態庫蘋果審覈不經過」,那我打的framework是否是通不過審覈?
任何沒有時間前提的結論都是耍流氓!!!
在 **iOS 8 / iOS6以前,**iOS 平臺不支持使用動態 Framework,開發者可使用的 Framework 只有系統的framework,這種限制多是出於安全的考慮
換一個角度講,由於 iOS 應用都是運行在沙盒當中,不一樣的程序之間不能共享代碼,同時動態下載代碼又是被蘋果明令禁止的,沒辦法發揮出動態庫的優點,實際上動態庫也就沒有存在的必要了
可是,碼農老是喜歡折騰的,一方面骨子裏面有一種「你不讓我作我偏要作的倔強」,另外一方面用framework確實比用.a加頭文件的方式簡單,因此這一時期的開發者用了不少**「奇淫技巧」來製做framework**,這就有了Fake Framework 和 Real Framework的區分
華麗的分割線------
在 **iOS 8 / iOS6後,iOS平臺添加了動態庫的支持,同時, Xcode 6 也原生自帶了 Framework 支持,注意,先後兩個維度的不一樣是兩件事,不要混淆。。。
那麼,爲何 iOS 8 要添加動態庫的支持?
主要的理由大概就是 Extension 的出現。Extension 和 App 是兩個分開的可執行文件,同時須要共享代碼,這種狀況下動態庫的支持就是必不可少的了。可是這種動態 Framework 和系統的 UIKit.Framework 仍是有很大區別;還有就是爲了支持swift
雖然一樣是動態框架,可是和系統 framework 不一樣,app 中的使用的 Cocoa Touch Framework 在打包和提交 app 時會被放到 app bundle 中(App 和 Extension 的 Bundle 是共享的),運行在沙盒裏,而不是系統中。也就是說,不一樣的 app 就算使用了一樣的 framework,但仍是會有多份的框架被分別簽名,打包和加載,所以蘋果又把這種 Framework 稱爲** Embedded Framework**,也正是代碼簽名機制,經過AppStore發佈的APP是沒法經過替換服務端下發framework的方式來進行熱更新!
##項目遇到的痛點 項目組原本是使用腳本結合xctool
(Facebook的一個開源項目)的方式來打包製做framework,但在升級xcode8以後,xctool
在xcode8下出現了bug,並且Facebook並無在第一時間維護這個項目,一時間一臉懵逼。。。
因爲項目時間緊,無奈之下只能採用了一個臨時解決方案,就是從新下載一個xcode7版本,讓xctool在xcode7環境下打包,但這絕非長久之計!
大概一個月以後,雖然xctool
項目更新了對 xcode8 以及 xcode8.1 的支持,但仍是決定放棄原有的方案,緣由有二,首先,Facebook有着很好的開源精神,可是也是出了名的喜歡撒手無論的角兒,萬一哪天中止對這個工具的維護,我怎麼辦!!!用一種簡單、穩定、可靠的解決方案是咱們急需的;第二,xctool
有很強大的功能,但咱們在項目中只用了其中一小塊,有點殺雞用牛刀的意思,項目中不少冗餘。 ##解決方案 替代方案就是用xcode提供的aggregate
結合腳原本製做framework ##製做過程 ###1. 用workspace管理SDK project 新建一個workspace,命名爲TestSDKWorkspace
如今生成的workspace仍是一個空的什麼都沒有,接着往裏面添加咱們的靜態庫project
點擊左下角的**+**號
project類型選擇cocoa touch framework,取名爲TeskSDK
在SDK項目中添加測試源代碼,寫一個Test類,對外提供testMethod
方法,注意,這個類要添加到SDK target中去!
#import <Foundation/Foundation.h> @interface Test : NSObject - (void)testMethod; @end #import "Test.h" @implementation Test - (void)testMethod{ NSLog(@"--------"); NSLog(@"this is a test method"); NSLog(@"--------"); } @end
咱們決定對外暴露Test.h,將其添加至接口文件中
此時,咱們編碼準備工做已經作好了,command+B
,咱們能夠在product文件夾下面看到有一個TestSDK.framework從紅變黑,這是否是意味着咱們須要的framework已經大功告成了呢?
no!!!咱們此時只是在特定平臺下編譯的,獲得的也只是這個平臺下的framework,咱們在文件夾中查看以下圖
這就意味着咱們要打同平臺的包,須要通過屢次編譯,最後再去合成,這太麻煩了 ###2. 用「Aggregate+腳本」製做framework 選擇TARGETS點擊而後添加Aggregate
添加以下腳本到Aggregate target對應的build phases-->run script中
#!/bin/sh #要build的target名 TARGET_NAME=${PROJECT_NAME} if [[ $1 ]] then TARGET_NAME=$1 fi UNIVERSAL_OUTPUT_FOLDER="${SRCROOT}/${PROJECT_NAME}_Products/" #建立輸出目錄,並刪除以前的framework文件 mkdir -p "${UNIVERSAL_OUTPUT_FOLDER}" rm -rf "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework" #分別編譯模擬器和真機的Framework xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build #拷貝framework到univer目錄 cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework" "${UNIVERSAL_OUTPUT_FOLDER}" #合併framework,輸出最終的framework到build目錄 lipo -create -output "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}" #刪除編譯以後生成的無關的配置文件 dir_path="${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/" for file in ls $dir_path do if [[ ${file} =~ ".xcconfig" ]] then rm -f "${dir_path}/${file}" fi done #判斷build文件夾是否存在,存在則刪除 if [ -d "${SRCROOT}/build" ] then rm -rf "${SRCROOT}/build" fi rm -rf "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator" "${BUILD_DIR}/${CONFIGURATION}-iphoneos" #打開合併後的文件夾 open "${UNIVERSAL_OUTPUT_FOLDER}"
###3. 生成framework 在target中選擇TestAggregate,build device選擇Generic Device,而後 command + B
因爲腳本末尾添加了open命令,編譯結束以後會打開framework所在的文件夾
至此,SDK生成完畢,咱們須要寫個demo工程驗證一把 ###4. 驗證framework 在workspace中新建一個demo工程,而後把TestSDK.framework引入
在viewController中調用SDK方法
從控制檯的輸出能夠看出,咱們已經成功的調起TestSDK中的方法。
個人另一篇文章解決引用百度地圖sdk衝突問題,其中介紹瞭如何查看framework的內部結構,你能夠用裏面的方法來查看咱們打出來的framework是不是通平臺的包 ##總結