Framework制作流程
坑:由于oc的分類會覆蓋同名的方法, 在framework中一定要謹(jǐn)慎對待分類
1. 新建framework 項目
File > New > Project

2. 需要注意配置的地方
1.配置sdk運(yùn)行最低支持的iOS版本
當(dāng)sdk是為項目定制時,直接配置跟項目運(yùn)行版本一致即可;
當(dāng)sdk是封裝了開放給別的開發(fā)者使用時,使用大眾版本,如目前大多應(yīng)用都需要iOS9及以上
2.靜態(tài)庫or動態(tài)庫選擇
首先要搞清楚靜態(tài)庫和動態(tài)庫的區(qū)別,這里有介紹
在這里,我選擇了使用靜態(tài)庫的形式,配置:Build Settings > Mach-O Type 可以配置靜態(tài)庫/動態(tài)庫
3.Build Phases > Headers
Public: 需要暴露給外部的.h文件,只有在public中的.h文件,才能被外部直接使用
3.新建target測試demo
新建一個target用來測試(File > New > Target > Single View App)

如圖,Products>MyTestSDK.framework 產(chǎn)物勾選,現(xiàn)在在Demo中就可以引用SDK中的文件了
#import <MyTestSDK/TestSDKAPI.h>

4.集成第三方庫
項目開發(fā)中會使用到很多第三方庫(AFN,SD等),那么在sdk中集成第三方庫的時候最方便的是使用pods來管理了
在使用的過程中只需要sdk中和使用sdk的項目保持第三方庫的版本一致即可。
創(chuàng)建pod文件,分別添加兩個target所依賴的第三方庫(注意:使用到的相同第三方庫需要保持版本一致)
因為sdk中使用了pod管理依賴庫,所以當(dāng)sdk開發(fā)完成,提供別別人使用時,需要同時提供podspec文件,當(dāng)別人使用pod集成你的sdk的時候,podspec會指明sdk所依賴的第三方庫,pod init的時候會一并安裝
* 使用 pod spec create MyTestSDK 就可以創(chuàng)建一個名為MyTestSDK的podspec文件, 將podspec文件放在項目 ./docs/ 目錄下
* podspec文件配置需要注意的地方:
1. resource文件,sdk中需要使用的圖標(biāo)需要新建一個bundle,統(tǒng)一放在bundle中管理,
spec.resource = "MyTestSDK.framework/*.bundle" 可以包含sdk中的所有bundle文件
2. spec.dependency 配置,將sdk中依賴的第三方庫全都列出來
spec.dependency 'AFNetworking'
spec.dependency 'MJRefresh'
spec.dependency 'YYModel'
5.framework打包腳本
sdk的打包跟需要支持的cpu架構(gòu)有關(guān),當(dāng)運(yùn)行的target選模擬器時,編譯出來的framework是支持x86_64和i386的;當(dāng)運(yùn)行的target選擇真機(jī)時,編譯出來的framework是支持arm64,armv7等架構(gòu);我們需要做的是將支持兩個架構(gòu)的可執(zhí)行文件合并,生成既支持模擬器,也支持真機(jī)運(yùn)行的包,腳本如下:
#!/bin/sh
# 合并在真機(jī)和模擬器上編譯出的 Framework
# 如果工程名稱和Framework的Target名稱不一樣的話,要自定義FMKNAME
FMK_NAME="MyTestSDK"
# 在工程的根目錄創(chuàng)建framework的文件夾.
INSTALL_DIR="./build/MyTestSDK/${FMK_NAME}.framework"
WRK_DIR="./build"
DEVICE_DIR="./build/Build/Products/Release-iphoneos/${FMK_NAME}.framework"
SIMULATOR_DIR="./build/Build/Products/Release-iphonesimulator/${FMK_NAME}.framework"
# Clean兩個架構(gòu)的framework
xcodebuild clean -configuration "Release" -scheme ${FMK_NAME} -workspace ${FMK_NAME}.xcworkspace -sdk iphoneos
xcodebuild clean -configuration "Release" -scheme ${FMK_NAME} -workspace ${FMK_NAME}.xcworkspace -sdk iphonesimulator
# build iphoneos
xcodebuild -configuration "Release" -scheme ${FMK_NAME} -workspace ${FMK_NAME}.xcworkspace -sdk iphoneos build -derivedDataPath ${WRK_DIR}
# build simulator
xcodebuild -configuration "Release" -scheme ${FMK_NAME} -workspace ${FMK_NAME}.xcworkspace -sdk iphonesimulator build -derivedDataPath ${WRK_DIR}
# 刪除之前生成的framework
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# 合成同時支持真機(jī)和模擬器架構(gòu)的 framework
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
# 文檔, 將生成好的podspec文件拷貝到 framework目錄下
cp "./docs/MyTestSDK.podspec" "./build/MyTestSDK/"
#移除多余文件
rm -rf "./build/Build"
rm -rf "./build/Logs"
rm -rf "./build/SourcePackages"
rm -rf "./build/ModuleCache.noindex"
6. 最后的項目結(jié)構(gòu) & 需要提供的產(chǎn)物

如圖,./build/MyTestSDK/ 目錄下的 MyTestSDK.framework 和 MyTestSDK.podspec 就是需要提供給別人使用的
7. 如何集成導(dǎo)出的framework到項目中使用
只需要將第6步中導(dǎo)出的產(chǎn)物放到項目目錄下,然后使用pod集成就可以了
- 在項目的pod 中加入:pod 'MyTestSDK', :path => './MyTestSDK'
- pod install, ok 大功告成!
遇到問題及解決辦法
- 關(guān)于第三方庫引用,怎么避免類重名?
使用pods來管理第三方依賴庫
-
關(guān)于在靜態(tài)庫中使用分類時報錯 unrecognized selector sent to instanceunrecognized selector sent to instance?
如果靜態(tài)庫中有category類,則在使用靜態(tài)庫的項目配置中【Other Linker Flags】需要添加參數(shù)【-ObjC]或者【-all_load】。
不能斷點調(diào)試framework中的源碼?
調(diào)試中發(fā)現(xiàn)在framework的源碼打斷點沒有效果, 排查后發(fā)現(xiàn)是因為 framework target的 Generate Debug Symbols 設(shè)置為NO, 導(dǎo)致的, 改成YES即可 (Generate Debug Symbols 對app target也是相同的效果, 可以縮小framework的包大小, 但是不會生成調(diào)試信息, 導(dǎo)致不能斷點調(diào)試)使用lipo合并真機(jī)&模擬器framework時報錯: have the same architectures (arm64) and can't be in the same fat output file
在Xcode12之前:
編譯模擬器靜態(tài)庫支持i386 x86_64兩架構(gòu)
編譯真機(jī)靜態(tài)庫支持armv7 arm64兩架構(gòu)
使用lipo -create -output命令可以將兩個庫合并成一個支持模擬器和真機(jī)i386 x86_64 armv7 arm64四種架構(gòu)的靜態(tài)庫。
但是Xcode12編譯的模擬器靜態(tài)庫也支持了arm64,導(dǎo)致出現(xiàn)真機(jī)庫和模擬器庫不能合并的問題。
---> 解決: 在 Build Settings -> Excluded Architectures 設(shè)置 Any iOS Simulator SDK : arm64
在打包時, 模擬器上的庫就不會在支持arm64架構(gòu)了, 合并也就沒問題了
---> 解決2: 可以使用 lipo xxx.a -remove arm64 -output xxx_no64.a, 將模擬器靜態(tài)庫中的arm64移除, 然后再進(jìn)行合并
- 問題4中連帶出的問題, 經(jīng)過問題4中打包出來的framework同時支持了 真機(jī):arm64、armv7, 模擬器:i386、x86_64 這4種架構(gòu), 但是在Xcode13(目前使用的13)或以上使用時, 在模擬器上編譯會報錯: in XXX.a(XXXXXXX.o), building for iOS Simulator, but linking in object file built for iOS, for architecture arm64
---> 模擬器運(yùn)行需要支持模擬器的arm64, 但是靜態(tài)庫中沒有, 所以報錯了
---> 解決: 在 Build Settings -> Excluded Architectures 設(shè)置 Any iOS Simulator SDK : arm64 (Debug模式, 因為運(yùn)行的時候一般是設(shè)置的debug)