一、配置Architectures
TARGETS->Build Settings -> Architectures ->Excluded Architectures->Release
下添加arm64
该配置是为了去除模拟器打包后的包中所包含的
arm64
,新的Xcode中,使用模拟器打包的Framework中包含arm64
,导致与真机冲突,从而不能合并;故需要去掉;
二、配置Scheme
Run->Build Configuration
改为Release
三、配置脚本
TARGET->Build Phases
中添加一个运行脚本
复制脚本内容:
# 脚本功能:合并对应模拟器cpu架构和真机架构的不同framework
# 使用方法:在framework工程中,TARGETS-Build Phases-加号-New Run Script Phase,
# 粘贴脚本,分别选择真机和模拟器各编译一次即可,成功合并后会在finder中打开。
# (很多教程写新建一个Aggregate Target再添加脚本,但是
# 由于默认已经有一个与项目名相同的TARGET,不能重名,如果又要保持framework名称一致
# 又需要修改,不如这样方便。)
# 用到的xcode环境变量: 参考https://www.jianshu.com/p/b5c85dcd6b04
# ${SRCROOT} 项目根目录
# ${PROJECT_NAME} 项目名
# ${BUILD_ROOT} 编译输出根目录,通常为~/Library/Developer/Xcode/DerivedData/项目名-乱七八糟的字符串/Build/Products
# ${CONFIGURATION} release或debug
# ${ACTION} 编译时为build
# 真机编译时生成的framework位置
DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework
# 模拟器编译时生成的framework位置
SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework
# 定义合并后framework的存放位置 这里放在项目根目录
INSTALL_DIR=${SRCROOT}/${PROJECT_NAME}.framework
# build时执行,且两类cpu架构均已编译成功生成framework
if [ "${ACTION}" = "build" ] && [ -d "${DEVICE_DIR}" ] && [ -d "${SIMULATOR_DIR}" ]
then
# 删除原有的合并文件(.framework其实是个文件夹)
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
# 新建合并文件
mkdir -p "${INSTALL_DIR}"
# 将真机framework拷贝至合并文件(因为后面的lipo -create只合并输出.framework下的"项目名"二进制文件,
# 还需要剩余的其他文件才能被使用,本脚本以真机framework的为基准,
# 这一步合并了Modules/xxx.swiftmodule文件夹,以及下面提到的Headers/xxx-Swift.h
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# 利用lipo合并两个.framework里的二进制文件,结果保存在合并后目录
lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"
# ***如果是swift工程,还需要拷贝.swiftmodule下的文件
SIMULATOR_SWIFT_MODULES_DIR=${SIMULATOR_DIR}/Modules/${PROJECT_NAME}.swiftmodule/.
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]
then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${INSTALL_DIR}/Modules/${PROJECT_NAME}.swiftmodule"
fi
# *** xcode10.2以后,如果包含Swift文件,
# 还需要合并处理xx.framework/Headers/PROJECT_NAME-Swift.h里的内容
SIMULATOR_SWIFT_HEADER_FILE=${SIMULATOR_DIR}/Headers/${PROJECT_NAME}-Swift.h
DEVICE_SWIFT_HEADER_FILE=${DEVICE_DIR}/Headers/${PROJECT_NAME}-Swift.h
INSTALL_SWIFT_HEADER_FILE=${INSTALL_DIR}/Headers/${PROJECT_NAME}-Swift.h
if [ -e "${SIMULATOR_SWIFT_HEADER_FILE}" ] && [ -e "${DEVICE_SWIFT_HEADER_FILE}" ]
then
# 合并-Swift.h
# 写入.h文件
echo "#if TARGET_OS_SIMULATOR" > "${INSTALL_SWIFT_HEADER_FILE}"
# 模拟器
cat "${SIMULATOR_SWIFT_HEADER_FILE}" >> "${INSTALL_SWIFT_HEADER_FILE}"
echo "#else" >> ${INSTALL_SWIFT_HEADER_FILE}
# 真机
cat "${DEVICE_SWIFT_HEADER_FILE}" >> "${INSTALL_SWIFT_HEADER_FILE}"
echo "#endif" >> "${INSTALL_SWIFT_HEADER_FILE}"
fi
# 合并-Swift.h结束
# 打开项目目录,得到合并后的.framework
open "${SRCROOT}"
fi
四、打包
分别在模拟器与真机下进行编译;
两种模式下编译成功后,脚本会自动把二者合并为一个新的包
五、查看Framework
打开项目所在目录