
轉(zhuǎn)載請注明出處:
http://www.itdecent.cn/p/04a7e28f11b9
作者:紀(jì)小衰
framework的使用十分方便,一般來說直接拖入到項目中就可以直接使用接口,而不用在意具體的實現(xiàn)細(xì)節(jié),對于功能的封裝是個很好的途徑。當(dāng)我們寫的工具給別人使用的同時又不想讓別人知道自己的代碼,這個時候使用framework就可以派上用場了(ps:個人覺得開源是一個大牛必須要體會到的思想)。。。
廢話不多說,xcode如今已經(jīng)到了7,對于framework的制作可以說是十分方便了。公司之前的framework的制作都是采用執(zhí)行純腳本的方法,可以直接命令行編譯和融合不同版本(模擬器,真機,debug,release)的framework,個人不是很喜歡,還是喜歡用較為官方的方式來制作framework,當(dāng)然為了方便還是少量地參照了網(wǎng)上的一些腳本。
一、新建framework工程
xcode->file->new->project選中iOS下的cocoa touch framework->next

接下來的步驟和創(chuàng)建一個普通的工程沒什么區(qū)別,創(chuàng)建完畢以后在工程中新建JRModel類和JRModel2類文件,在我們的framework工程創(chuàng)建以后系統(tǒng)會默認(rèn)創(chuàng)建一個和工程名相同的頭文件,我這里是JRDataModel.h。一般來說我們會把framework中需要提供給外部的頭文件都在這個頭文件中import一下,這樣使用者只要包含一個頭文件就可以使用所有的類了。

這個地方需要注意到兩點,一個就是導(dǎo)入的時候必須要使用framework的方式導(dǎo)入,使用<包名/頭文件名.h>,因為在實際使用framework的時候是需要從包中搜索頭文件的。還有一個坑就是右邊的那個設(shè)置,對于總的頭文件還有所有需要用到的頭文件,都需要公開,選中以后把右邊包的編譯屬性改為public,否則打出來的包在別的工程中實際上是不能引用的。
二、編譯工程
接下來就是開始編譯工程了(如下圖),選中運行按鈕右邊的編譯目標(biāo),選擇Generic iOS Device,然后command+b編譯一下,這個時候我們工程中的products文件夾下面的framework文件會由原來的紅色(表示文件丟失)變成黑色(表示文件存在)。如果我們選擇的是Generic iOS Device那么編譯出來的framework只能在真機中使用,如果選中的是普通的模擬器,那么編譯出來framewo只能在模擬器中使用。
tips:這里需要注意一下,如果一開始選擇的是模擬器,那么即使build成功,framework也不會變成黑色,可能是因為這里的framework指向的是真機中對應(yīng)的framework,但是在相對應(yīng)的目錄下的模擬器對應(yīng)的framework是存在的

右擊生成好的framework,選中show in finder可以查看framework在磁盤中的位置。進入目錄以后,一般來說最多有四個目錄,我這里只有三個(如下圖)因為對于模擬器一般不會要release版本的。也可以通過finder,快捷鍵control+command+g輸入~/Library/Developer/Xcode/DerivedData/Build/Products默認(rèn)路徑進入

分別在模擬器和真機選項中編譯,發(fā)現(xiàn)實際只產(chǎn)生了模擬器和真機的debug版本的framework包,而沒有release版本的包。這需要我們調(diào)整一下xcode的build類型,選中運行的target在下來列表中選Edit Scheme,進入以后把run中的Build Configureation修改為Release,這時候就可以編譯出release版本的包了(如下圖)


三、合并framework
到此,我們已經(jīng)制作出對于各種情況下使用的framework了,對于不同的環(huán)境需要使用不同種類的framework,這在很多時候顯得很麻煩。能不能制作一個能在所有場景使用的包呢。
這個時候我們可以考慮合并所有版本的包,一般來說可以使用腳本進行合并,但是每次使用腳本比較麻煩,我們可以在xcode中添加一個共同體aggregate,然后添加編譯腳本來實現(xiàn)。
在工程中點擊上方工具欄File->New->Target,在選項中選擇Other中的Aggregate,命名最好和工程名有關(guān),我這里就寫成JRDataModelAggregate。

新建好以后,選擇targets列表下的JRDataModelAggregate,點擊build phases,點擊+新建一個New Run Script Phase,把下面的腳本復(fù)制到shell下的選項中(腳本來源自網(wǎng)絡(luò),感謝這段腳本的原作者)。有能力的可以根據(jù)自己的需要修改下面的腳本。
# Sets the target folders and the final framework product.
#如果工程名稱和Framework的Target名稱不一樣的話,要自定義FMKNAME
#例如: FMK_NAME = "MyFramework"
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}"

復(fù)制完以后,點擊左上角運行旁邊的target(上圖左上角那個黃色的選項),在下拉的列表中選中我們剛才創(chuàng)建的JRDataModelAggregate,command+B編譯一下,如果沒什么意外,等到編譯成功便會彈出我們編譯好的framework了。
四、驗證framework
framework其實可以看做是一個帶擴展名的文件夾,所以我們可以直接進入framework的內(nèi)部。通過下面的控制臺指令進入到framework中(cd后面是你自己的framework路徑)
cd /Users/ctzxh/Desktop/JRModel/JRDataModel/Products/JRDataModel.framework
執(zhí)行下面的命令判斷當(dāng)前framework支持的架構(gòu)
lipo -info JRDataModel

Tips1:
對于上面的每種處理器架構(gòu)對應(yīng)的設(shè)備請自行百度。這里說明一下,如果讓你的包可以支持armv7s的架構(gòu)(這里說的支持指的是針對這種架構(gòu)的優(yōu)化),可以根據(jù)下圖的方式添加,新版的xcode默認(rèn)便沒有加上armv7s的架構(gòu),由于處理器向下兼容,所以即使不添加,所使用包的工程也是可以在armv7s架構(gòu)上的機器運行的。個人推薦還是不必考慮了,按照官方的來就可以了。添加完以后在驗證包的時候會多顯示一個armv7s。

Tips2:
上面用Aggregate制作的庫是拖入到使用的工程是直接可以使用的,但是之前分別制作的庫直接拖入是不能使用的,解決的方式有兩種:
第一種:制作鏈接庫的時候,選擇生成靜態(tài)庫

第二種:在使用動態(tài)鏈接庫的時候嵌入二進制庫,在下面的選項中添加要導(dǎo)入的動態(tài)庫

網(wǎng)上有種方式是把framework的屬性從required變成Optional,親測行不通,能導(dǎo)入但是不能用。。。
就到這兒吧~~~
Add:如果只做的是.a的靜態(tài)庫可以使用下面的腳本,方法一樣
if["${ACTION}"="build"]
then
#要build的target名
target_Name=${PROJECT_NAME}
echo"target_Name=${target_Name}"
#build之后的文件夾路徑
build_DIR=${SRCROOT}/build
echo"build_DIR=${build_DIR}"
#真機build生成的頭文件的文件夾路徑
DEVICE_DIR_INCLUDE=${build_DIR}/Release-iphoneos/include/${PROJECT_NAME}
echo"DEVICE_DIR_INCLUDE=${DEVICE_DIR_INCLUDE}"
#真機build生成的.a文件路徑
DEVICE_DIR_A=${build_DIR}/Release-iphoneos/lib${PROJECT_NAME}.a
echo"DEVICE_DIR_A=${DEVICE_DIR_A}"
#模擬器build生成的.a文件路徑
SIMULATOR_DIR_A=${build_DIR}/Release-iphonesimulator/lib${PROJECT_NAME}.a
echo"SIMULATOR_DIR_A=${SIMULATOR_DIR_A}"
#目標(biāo)文件夾路徑
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}
echo"INSTALL_DIR=${INSTALL_DIR}"
#目標(biāo)頭文件文件夾路徑
INSTALL_DIR_Headers=${SRCROOT}/Products/${PROJECT_NAME}/Headers
echo"INSTALL_DIR_Headers=${INSTALL_DIR_Headers}"
#目標(biāo).a路徑
INSTALL_DIR_A=${SRCROOT}/Products/${PROJECT_NAME}/lib${PROJECT_NAME}.a
echo"INSTALL_DIR_A=${INSTALL_DIR_A}"
#判斷build文件夾是否存在,存在則刪除
if[ -d"${build_DIR}"]
then
rm -rf"${build_DIR}"
fi
#判斷目標(biāo)文件夾是否存在,存在則刪除該文件夾
if[ -d"${INSTALL_DIR}"]
then
rm -rf"${INSTALL_DIR}"
fi
#創(chuàng)建目標(biāo)文件夾
mkdir -p"${INSTALL_DIR}"
#build之前clean一下
xcodebuild -target${target_Name}clean
#模擬器build
xcodebuild -target${target_Name}-configuration Release -sdk iphonesimulator
#真機build
xcodebuild -target${target_Name}-configuration Release -sdk iphoneos
#復(fù)制頭文件到目標(biāo)文件夾
cp -R"${DEVICE_DIR_INCLUDE}""${INSTALL_DIR_Headers}"
#合成模擬器和真機.a包
lipo -create"${DEVICE_DIR_A}""${SIMULATOR_DIR_A}"-output"${INSTALL_DIR_A}"
#打開目標(biāo)文件夾
open"${INSTALL_DIR}"
fi