Framework制作流程
坑:由于oc的分类会覆盖同名的方法, 在framework中一定要谨慎对待分类
1. 新建framework 项目
File > New > Project
2. 需要注意配置的地方
1.配置sdk运行最低支持的iOS版本
当sdk是为项目定制时,直接配置跟项目运行版本一致即可;
当sdk是封装了开放给别的开发者使用时,使用大众版本,如目前大多应用都需要iOS9及以上
2.静态库or动态库选择
首先要搞清楚静态库和动态库的区别,这里有介绍
在这里,我选择了使用静态库的形式,配置:Build Settings > Mach-O Type 可以配置静态库/动态库
3.Build Phases > Headers
Public: 需要暴露给外部的.h文件,只有在public中的.h文件,才能被外部直接使用
3.新建target测试demo
新建一个target用来测试(File > New > Target > Single View App)
如图,Products>MyTestSDK.framework 产物勾选,现在在Demo中就可以引用SDK中的文件了
#import <MyTestSDK/TestSDKAPI.h>
4.集成第三方库
项目开发中会使用到很多第三方库(AFN,SD等),那么在sdk中集成第三方库的时候最方便的是使用pods来管理了
在使用的过程中只需要sdk中和使用sdk的项目保持第三方库的版本一致即可。
创建pod文件,分别添加两个target所依赖的第三方库(注意:使用到的相同第三方库需要保持版本一致)
因为sdk中使用了pod管理依赖库,所以当sdk开发完成,提供别别人使用时,需要同时提供podspec文件,当别人使用pod集成你的sdk的时候,podspec会指明sdk所依赖的第三方库,pod init的时候会一并安装
* 使用 pod spec create MyTestSDK 就可以创建一个名为MyTestSDK的podspec文件, 将podspec文件放在项目 ./docs/ 目录下
* podspec文件配置需要注意的地方:
1. resource文件,sdk中需要使用的图标需要新建一个bundle,统一放在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架构有关,当运行的target选模拟器时,编译出来的framework是支持x86_64和i386的;当运行的target选择真机时,编译出来的framework是支持arm64,armv7等架构;我们需要做的是将支持两个架构的可执行文件合并,生成既支持模拟器,也支持真机运行的包,脚本如下:
#!/bin/sh
# 合并在真机和模拟器上编译出的 Framework
# 如果工程名称和Framework的Target名称不一样的话,要自定义FMKNAME
FMK_NAME="MyTestSDK"
# 在工程的根目录创建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两个架构的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}/"
# 合成同时支持真机和模拟器架构的 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. 最后的项目结构 & 需要提供的产物
如图,./build/MyTestSDK/ 目录下的 MyTestSDK.framework 和 MyTestSDK.podspec 就是需要提供给别人使用的
7. 如何集成导出的framework到项目中使用
只需要将第6步中导出的产物放到项目目录下,然后使用pod集成就可以了
- 在项目的pod 中加入:pod 'MyTestSDK', :path => './MyTestSDK'
- pod install, ok 大功告成!
遇到问题及解决办法
- 关于第三方库引用,怎么避免类重名?
使用pods来管理第三方依赖库
-
关于在静态库中使用分类时报错 unrecognized selector sent to instanceunrecognized selector sent to instance?
如果静态库中有category类,则在使用静态库的项目配置中【Other Linker Flags】需要添加参数【-ObjC]或者【-all_load】。
不能断点调试framework中的源码?
调试中发现在framework的源码打断点没有效果, 排查后发现是因为 framework target的 Generate Debug Symbols 设置为NO, 导致的, 改成YES即可 (Generate Debug Symbols 对app target也是相同的效果, 可以缩小framework的包大小, 但是不会生成调试信息, 导致不能断点调试)使用lipo合并真机&模拟器framework时报错: have the same architectures (arm64) and can't be in the same fat output file
在Xcode12之前:
编译模拟器静态库支持i386 x86_64两架构
编译真机静态库支持armv7 arm64两架构
使用lipo -create -output命令可以将两个库合并成一个支持模拟器和真机i386 x86_64 armv7 arm64四种架构的静态库。
但是Xcode12编译的模拟器静态库也支持了arm64,导致出现真机库和模拟器库不能合并的问题。
---> 解决: 在 Build Settings -> Excluded Architectures 设置 Any iOS Simulator SDK : arm64
在打包时, 模拟器上的库就不会在支持arm64架构了, 合并也就没问题了
---> 解决2: 可以使用 lipo xxx.a -remove arm64 -output xxx_no64.a, 将模拟器静态库中的arm64移除, 然后再进行合并
- 问题4中连带出的问题, 经过问题4中打包出来的framework同时支持了 真机:arm64、armv7, 模拟器:i386、x86_64 这4种架构, 但是在Xcode13(目前使用的13)或以上使用时, 在模拟器上编译会报错: in XXX.a(XXXXXXX.o), building for iOS Simulator, but linking in object file built for iOS, for architecture arm64
---> 模拟器运行需要支持模拟器的arm64, 但是静态库中没有, 所以报错了
---> 解决: 在 Build Settings -> Excluded Architectures 设置 Any iOS Simulator SDK : arm64 (Debug模式, 因为运行的时候一般是设置的debug)