制作靜態(tài)庫
- 動態(tài)庫:
.dylib.framework - 靜態(tài)庫:
.a.framework
兩者區(qū)別*:動態(tài)庫時在程序運行時動態(tài)鏈接的,且可以被多個程序鏈接,相當(dāng)于以動態(tài)庫為中心,系統(tǒng)只會加載動態(tài)庫到內(nèi)存一次,這樣動態(tài)庫就始終只占一份內(nèi)存,而靜態(tài)庫是提前把需要編譯的實現(xiàn)文件編譯為二進制文件,每個程序都需要復(fù)制一份,這是在使用靜態(tài)庫就決定了的特性,我們需要把靜態(tài)庫復(fù)制到工程文件內(nèi),供我們程序使用,而在制作時靜態(tài)庫時,我們可以選擇暴露哪些文件給使用者,當(dāng)然大部分都只需暴露頭文件,我們當(dāng)然也可以暴露實現(xiàn)文件,供我們參考學(xué)習(xí),了解其中原理,眾使我們修改了該文件的內(nèi)容也沒關(guān)系,因為該文件已經(jīng)在制作靜態(tài)庫時已經(jīng)編譯成二進制文件,我們使用時不會再次編譯該文件,資源文件如圖片等也是可以我們替換,因為編譯時只是簡單的COPY,所以我們可以替換SVProgressHUB里的error或success成我們個性化的圖片。蘋果官方不允許我們App包含動態(tài)庫。
.a與.framework的區(qū)別:
制作.a 都需要我們手動在Header Search Paths加頭文件搜索路徑
制作 .framework不需要
制作.framework靜態(tài)庫
我們先說.framework 的制作過程,我們新建項目選擇iOS的framwork / library ,建好后默認(rèn)有一個頭文件,這不是我們需要的,直接刪掉,這里我們可以任意建文件夾和文件,把我們需要的功能庫搭建好后,我們在Build phase > Headers > public 內(nèi)添加我們需要暴露的文件,這樣我們就建好了,然后我們分別選著模擬器 和 Generic iOS Device 來構(gòu)建我們的product ,只有當(dāng)我們構(gòu)建完Generic iOS Device才能看到product內(nèi)的target由紅色變?yōu)楹谏?,這說明文件存在,構(gòu)建完畢,然后我們右鍵 show in finder 找到編譯好的文件,當(dāng)然,這個文件只包含armv7 和arm64 架構(gòu)的。我們還需要在Mach-type修改類型為Static Library,當(dāng)然我們也可以制作動態(tài)庫,只是不能發(fā)布。如果你制作動態(tài)庫就需要在Embedded Binaries 內(nèi)添加庫。
對于這幾種CPU架構(gòu)分類:
真機:
3gs ~ 4s :armv7
5 ~5c :armv7s
5s~ 6plus:arm64
模擬器:
4s~5 : i386
5s~6plus : x86_64
所以我們需要合并這幾種包,并且都是debug包,我們一般發(fā)布給別人Release包,這需要我們Edit Scheme 選擇Run > info >build configuration 為Release。Release包會比debug包要小一點,因為編譯時作了代碼優(yōu)化,運行效率會高一點,但不會明顯提高。
為了保證都能運行,我們還需要合并包,這里的包是.framework 文件里的同名的無擴展名的二進制文件,使用下面命令合并,更多使用方法( man lipo)
lipo -create test1 test2 -output test3
然后替換之前任意一個同名的二進制文件,這里多次強調(diào)同名,因為系統(tǒng)就是根據(jù)根據(jù)靜態(tài)庫名在靜態(tài)庫內(nèi)尋找二進制文件,不然會報找不到該文件的錯誤。
這樣我們直接把替換二進制文件后的.framework文件拖進我們其它工程直接使用。
當(dāng)然如果我們還需要在靜態(tài)庫內(nèi)使用資源文件,我們使用Bundle,在該項目內(nèi)Add Target ,選擇OSX 內(nèi)的Bundle,我們需要刪除一系列,修改sdk,修改product name等等。
制作.a靜態(tài)庫
類似制作.framework靜態(tài)庫,我們新建項目XHQ_StaticFramework,選擇Cocoa Touch Static Library
這時可以看到兩個文件夾:XHQ_StaticFramework 和Product , Xcode 為我們自動建好的XHQ_StaticFramework(.h/.m)文件,一般我們只需要頭文件,頭文件寫下我們所有需要公開的頭文件,其它全部刪掉,以便客戶使用時只需引入這個頭文件。Product存放我們生成的二進制文件。這里我們引入<UIKit/UiKit.h>框架,(網(wǎng)上多個版本都提到需要在Build Phrases >Link Binary With Libraries 內(nèi)添加UIKit.framework,但是作者沒有添加也能正常使用,如果你知道原因請告訴我,謝謝?。?/p>
我們在XHQ_StaticFramework 文件夾下建好我們自己的代碼庫后,把需要公開的頭文件加到Build Phases >Headers ,如果你沒有這個目錄,你需要手動Editor > Add Build Phases> Add Headers Build Phases 來添加。(提示:如果無法選擇,你需要點擊Build Phases 空白處后再重復(fù)上面的步驟。)
點開 Headers 默認(rèn)是有三個文件目錄: public&&private&&project, 其中pulic和private都是放對外公開的文件,兩者區(qū)別就是存儲的路徑可能不一樣,我們可以在Packaging> Private/Public Headers Folder Path設(shè)置路徑。這里我們設(shè)置為include/$(PROJECT_NAME),project 存放我們私有的文件。
然后我們需要在Build Settings設(shè)置一些值:
Dead Code Stripping > NO(去掉不會執(zhí)行到的代碼)
Strip Style > Debugging Symbols
Strip Debug Symbol During Copy > NO(去掉Debug相關(guān)符號)
Strip Linked Product > NO
這樣做是為了后期產(chǎn)生bug時,我們能通過符號文件定位到我們需要的類的信息, 但是如果是iOS 或者 OSX則配置完全相反。相關(guān)文章
我們編譯成功后就可以正常使用。使用時我們有兩種方式
一種是在其它項目中拖進該項目,在新項目中添加依賴
Build Phases > Target Dependencies添加.a靜態(tài)庫,然后就是link library內(nèi)添加.a靜態(tài)庫;
上面的方式適合我們自己內(nèi)部使用,好處就是可以動態(tài)的修改靜態(tài)庫的文件,Xcode會根據(jù)是否需要重新編譯來生成靜態(tài)文件,而其實我們可以是直接使用生成的
.a靜態(tài)庫和包涵頭文件的include文件夾,只不過我們每次都需要配置Search Headers Paths,這種方式適合給外部使用。
使用腳本生成集成包
相信上面的這些分別生成支持不同架構(gòu)的包已經(jīng)讓你精疲力竭,我們有更加方便的方法制作通用的包,那就是使用腳本來構(gòu)建支持多個架構(gòu)的包.首先我們在前面制作framework的基礎(chǔ)上添加
Aggragate target,然后在Build Phases 內(nèi)添加 Run Script
把下面代碼添加進去。直接運行,然后生成的包目錄會自動打開。
FMK_NAME=${PROJECT_NAME}
# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework
# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# -configuration ${CONFIGURATION}
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build
# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ];then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
rm -r "${WRK_DIR}"
open "${INSTALL_DIR}"