說明
下面的框架是以swift為例創(chuàng)建的框架,引入的第三方框架有OC和swift的谣沸,在framework中使用第三方庫的方法
因?yàn)楣镜男滦枨罅苫埃谠镜目蚣苤性俜庋b一層,本次就拿微信和支付寶的框架做一個demo社证。開始之前我們先對framework和.a這些庫做一個說明。
1.靜態(tài)庫和動態(tài)庫
庫评凝,其實(shí)說白了就是一段編譯好的二進(jìn)制代碼追葡,加上頭文件就可以供別人使用,一般有以下兩種場景要用到分類分為兩種:
- 某些你想給別人用,但是不想別人看到自己源碼辽俗,就需要以庫的形式進(jìn)行封裝疾渣,只暴露出頭文件就行。
- 對于一些不會進(jìn)行很大改動的代碼崖飘,單獨(dú)封裝成模塊,這樣做可以節(jié)省時間杈女,代碼管理也很方便
因?yàn)閹煲呀?jīng)是編譯好的二進(jìn)制文件朱浴,編譯的時候只需要link一下,link的時候有兩種不同的形式达椰,靜態(tài)和動態(tài)翰蠢,與之對應(yīng)的就是靜態(tài)庫和動態(tài)庫。
靜態(tài)庫
平時用到的第三方的SDK基本上都是靜態(tài)庫啰劲,靜態(tài)庫有一下幾個特點(diǎn):
1.在app項(xiàng)目編譯的時候會被拷貝一份編譯到目標(biāo)程序中梁沧,相當(dāng)于將靜態(tài)庫嵌入了,所以得到的APP二進(jìn)制文件會變大
- 2.在使用的時候蝇裤,需要收到導(dǎo)入靜態(tài)庫所依賴的其他類庫廷支,比如這個demo中我們要使用到的類庫,使用的時候只能手動導(dǎo)入栓辜,有的SDK需要導(dǎo)入十幾個其他依賴庫恋拍,??????
支付寶SDK依賴庫3.導(dǎo)入靜態(tài)庫可以減少應(yīng)用對外界的依賴,如果導(dǎo)入的是第三方動態(tài)庫藕甩,動態(tài)庫找不到的話就會奔潰施敢,
4.靜態(tài)庫的最大的優(yōu)點(diǎn)就是減少耦合性,因?yàn)殪o態(tài)庫中是不可以包含其他靜態(tài)庫的狭莱,使用的時候要另外導(dǎo)入它的依賴庫僵娃,可以最大限度的保證了每一個靜態(tài)庫都是獨(dú)立的,不會重復(fù)引用腋妙。
動態(tài)庫
這個使我們常用的動態(tài)庫默怨,使用最多的就是UIkit.framework和Fundation.framework,這兩個都是動態(tài)庫。所有.dylib和.tbd結(jié)尾的都屬于動態(tài)庫辉阶。動態(tài)庫有以下幾個特點(diǎn):
- 1.平時使用的系統(tǒng)庫都放在iOS系統(tǒng)中先壕,在你打包應(yīng)用程序的時候這些庫不會拷貝到你的程序中,當(dāng)需要使用的時候才會動態(tài)的從iOS系統(tǒng)中加載他們谆甜,因?yàn)檫@個原因垃僚,動態(tài)庫也稱為共享庫。編譯的時候才載入的特性规辱,也可以讓我們隨時對庫進(jìn)行替換谆棺,而不需要重新編譯。
- 2.這些庫是所有應(yīng)用公用的,換一種說法就是節(jié)省了應(yīng)用安裝包的體積改淑,這就是區(qū)別靜態(tài)庫的一個重要的特點(diǎn)碍岔,因?yàn)殪o態(tài)庫使用一次就要拷貝一次,比較消耗資源朵夏。
- 3.動態(tài)庫在制作的時候可以直接包含靜態(tài)庫蔼啦,也能自動link所需要的依賴庫
- 4.使用動態(tài)庫的時候不需要再次link依賴庫,即導(dǎo)即用仰猖。需要注意的是在導(dǎo)入自己制作的動態(tài)庫時捏肢,需要在Embedded Binaries中導(dǎo)入,不然會報image not found饥侵。此時這個動態(tài)庫會跟靜態(tài)庫一樣被拷貝到目標(biāo)程序中進(jìn)行編譯
在動態(tài)庫選擇上要考慮能不能上架的問題鸵赫,目前第三方的SDK也都是靜態(tài)庫,至于動態(tài)庫能不能上架這就不是很清楚了躏升,畢竟蘋果也不想你動態(tài)的在系統(tǒng)中下載代碼辩棒。
2. framework 、.a 膨疏、.dylib/.tbd
1.framework
framewoz主要是由Headers一睁、binary文件和.bundle這三部分構(gòu)成,除此之外還有info.plist和Modules,后兩者主要記錄framework的版本之類的信息成肘,一般可以刪掉卖局。
*Headers
包含在我們制作的framework的時候回暴露的頭文件,所有被暴露的.h都放在這里
*binary文件
整個framework的核心双霍,所有的代碼都被編譯成了這樣的一坨二進(jìn)制文件砚偶,這里要注意的就是添加的依賴庫不會被編譯進(jìn)來,用的時候還需要重新link其他的依賴庫
.bundle
資源文件都打包放在這里洒闸,在制作framework的時候不可以把圖片直接放在項(xiàng)目中染坯,否則制作好之后的圖片是一張一張出現(xiàn)在項(xiàng)目中,很是混亂丘逸,這時候需要新建一個bundle將圖片单鹿、xib等一些資源放進(jìn)去,
提示
圖片放進(jìn)bundle中之后不能直接用[UIImage ImageWithName:]
,要找到bundle包再去獲取圖片深纲。
另外說明一下framework是靜態(tài)庫還是動態(tài)庫的問題
其實(shí)framework既可以是動態(tài)庫也可以是靜態(tài)庫仲锄,在取決于編譯的時候Mach-O(就是那個二進(jìn)制文件)是動態(tài)庫還是靜態(tài)庫,如下圖所示湃鹊。
2. .a靜態(tài)庫
這類靜態(tài)庫與framework基本類似萤厅,不同的是在打包成.a文件的同時芥喇,還需要提供頭文件,使用時相對于framework比較麻煩壹店,例如微信執(zhí)法SDK使用的是.a,而支付寶使用的是framework的形式打的包鬼癣。.a打包不夠方便陶贼,而framework編譯完成暴露的頭文件都已經(jīng)放好了
3. .dylib/.tbd 動態(tài)庫
這類動態(tài)庫經(jīng)常用到,基本上就是系統(tǒng)提供的待秃,就算是自己制作了,也肯定上不了架痹屹。
3.framework 動態(tài)庫和靜態(tài)庫的打包
靜態(tài)庫和動態(tài)庫的制作過程基本一樣章郁,包括暴露的頭文件,唯一不同的就是上面圖中顯示的Mach-O Type的編譯形式志衍。demo中介紹framework靜態(tài)庫依賴其他第三方靜態(tài)庫暖庄,支付寶的framework
1.新建工程
右邊的static Library制作出來的是.a靜態(tài)庫
2.導(dǎo)入所有要打包的文件和其他的第三方的靜態(tài)庫
正常導(dǎo)入要打包的文件就行了,在導(dǎo)入第三方靜態(tài)庫的時候要注意楼肪,不要選擇添加到target中培廓,如果添加了要去target中把里面的第三方靜態(tài)庫刪除(只要導(dǎo)入,不要添加進(jìn)target)
修改framework支持的最低版本春叫,添加依賴庫
這個時候編譯會報錯
這是因?yàn)樘砑拥膬蓚€.dylib文件找不到肩钠,刪除這兩個庫,重新添加暂殖。這時候要選擇add other選擇添加价匠,在彈出的窗口中按快捷鍵shift + command + G 調(diào)出finder的前往窗口,輸入/usr/lib呛每,然后添加相應(yīng)的dylib動態(tài)庫.如下圖
3.暴露文件踩窖,在targets->Build Phases->headers中添加public文件
接下來開始編譯,就可以制作一個靜態(tài)包出來晨横。
4.接下來我說一下在整合中遇到的坑洋腮,
因?yàn)樵陧?xiàng)目中拿到添加了framework,但是怎么都引用不了手形,里面的頭文件和其他的都訪問不到啥供,因?yàn)閒rameworkj就是在.a靜態(tài)庫基礎(chǔ)上更上一層的封裝,包含了資源叁幢,二進(jìn)制文件和頭文件并生成了統(tǒng)一格式滤灯,方便用戶調(diào)用,并不是重新生成另外一種格式,只是對老的格式進(jìn)行了一層更規(guī)范的封裝鳞骤,統(tǒng)一管理資源文件窒百,頭文件和庫的二進(jìn)制文件。那么我們就可以把別人的framework變成一個.a靜態(tài)庫文件豫尽。
為了方便測試篙梢,在真機(jī)和模擬其中來回的切換,我們要在打包的framework之間來回切換并重新編譯美旧,詳情請看合并真機(jī)和模擬器的方法
下面說一種比較簡單方便的辦法
1.新建一個target
新建target
2.選擇aggregate新建,命名為UniversalSDK
aggregate創(chuàng)建
3.選中UniversalSDK 在build Phases中點(diǎn)擊左上角的+號,如下圖
添加run script
4.將下面的代碼復(fù)制到shell下面的框中
#!/bin/sh
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}"
在編譯的時候選擇UniversalSDK直接在目錄中生成一個SDK渤滞,這是真機(jī)和模擬器都能用的。測試的時候?yàn)榱吮苊庵貜?fù)打包榴嗅,直接將項(xiàng)目拖到測試工程中妄呕,如下圖:
這樣就可以在項(xiàng)目中直接使用SDK,而且每次修改SDK不用重新引入嗽测,編譯一下即可在測試工程中使用绪励。