本文转载自: David'Blog Cocoapods实现私有库开发和二进制发布,如有侵权请联系删除
近期接到了个需求,要实现一个组件项目在开发时候实现自动输出Framework。即这个项目实际上是一个基于Podspec的组件私有库,开发的时候只有部分同学可以访问私有库的源码,而最后以Framework的形式输出给其他人。
Cocoapods注入脚本
为了实现以上的需求,最先想到的就是希望在每次构建结束后利用脚本来自动化这个功能。经过一番查询,在Cococapods中发现果然可以实现脚本注入。
根据这篇文章在1.4.0之后支持podfile和podspec注入脚本到xcode中对应的工程target中。即在podfile中的脚本会注入到Demo.xcodeproj
而podspec中的脚本注入到Pods.xcodeproj
中的target。
利用cocopods提供的脚本注入语法,注入的脚本的执行时机是在该target进行编译前/中/后。
显然根据需求我们是在制作一个podspec组件,所以我们将要注入Framework制作脚本到Demo.xcodeproj
中触发脚本到Pods.xcodeproj
制作一个Framework。因为我们要制作的framework本身就是Pods.xcodeproj
中的target,假如把脚本注入到Pods.xcodeproj
这个工程中则会引起脚本循环执行。
Framework制作脚本
接下来我们制作Framework的脚本有以下三种方案:
- Carthage Build,需要将target scheme改为shared才能构建,只支持dynamic的Framwork且没有支持mangle技术。
- Cocoapods-packager支持dynamic和static的Framework,并且支持mangle技术可以修改符号表防止方法名冲突,但动态库打包目前只支持到pod 1.5.3版本,引入Swift代码会有问题,长期缺少维护。
- 自制xcodebuild脚本,实际上上面两种第三方方案原理上也是调用xcodebuild来进行打包的所以我们同样可以自定义一个xcodebuild脚本来更自由实现打包工作。
在实践的时候发现还是用自制xcodebuild shell脚本最为简单,Carthage由于需要手动将target scheme设为shared导致无法实现脚本打包,Cocoapods-packager需要先上传代码到远程仓库上。
具体过程可以参考Demo
最后实现在每次构建结束后生成一个Framework,最后将这个Framework输出到最终发布仓库下实现整个开发发布流程。如下图我们实现两个仓库:
- 私有组件仓库Binarization
-
二进制发布公开仓库Binarization_Public
参考
基于 CocoaPods 进行 iOS 开发
一行命令发布 Pod 框架
谈谈CocoaPods组件二进制化方案
iOS脚本打包
工程上的二三事
xcbuild_pack.sh
#!/bin/sh
TARGET="BluetoothSDK"
#如果有输入参数则用输入参数
if [[ $1 ]]
then
TARGET=$1
fi
#定义一下用到的变量,接下去不使用外部环境变量
OUTPUT_FLODER="${PROJECT_DIR}/../ReleaseFameworks"
PROJECT="${PODS_ROOT}/Pods.xcodeproj"
BUILD_DIR="${BUILD_DIR}"
BUILD_ROOT="${BUILD_ROOT}"
CONFIGURATION="Release"
BUILD_IPHONEOS_FRAMEWORK_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET}/${TARGET}.framework"
BUILD_IPHONESIMULATOR_FRAMEWORK_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET}/${TARGET}.framework"
#创建输出目录,并删除之前的framework文件
mkdir -p "${OUTPUT_FLODER}"
rm -rf "${OUTPUT_FLODER}/${TARGET}.framework"
#分别编译模拟器和真机的Framework,同时不使用new build system
xcodebuild -project ${PROJECT} -target "${TARGET}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build -UseModernBuildSystem=NO
xcodebuild -project ${PROJECT} -target "${TARGET}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build -UseModernBuildSystem=NO
#拷贝framework到输出目录上
cp -R ${BUILD_IPHONEOS_FRAMEWORK_PATH} ${OUTPUT_FLODER}
#合并framework,输出最终的framework到build目录
lipo -create -output "${OUTPUT_FLODER}/${TARGET}.framework/${TARGET}" "${BUILD_IPHONESIMULATOR_FRAMEWORK_PATH}/${TARGET}" "${BUILD_IPHONEOS_FRAMEWORK_PATH}/${TARGET}"
#删除编译之后生成的无关的配置文件
dir_path="${OUTPUT_FLODER}/${TARGET}.framework/"
for file in ls $dir_path
do
if [[ ${file} =~ ".xcconfig" ]]
then
rm -f "${dir_path}/${file}"
fi
done
#判断build文件夹是否存在,存在则删除
if [ -d "${SRCROOT}/build" ]
then
rm -rf "${SRCROOT}/build"
fi
rm -rf "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator" "${BUILD_DIR}/${CONFIGURATION}-iphoneos"