公司最近要开发一个SDK,不知如何下手,请教了一个有SDK开发经验的同事,也在网上查了些资料,决定整理一下。整体上讲就是在SVN上创建一个项目路径,再用Xcode创建一个项目工程,把项目工程上传到SVN上就可以开发了,这里只讨论项目工程的创建。
一、创建一个workspace
1、在桌面上创建一个文件夹MyTestSDK(名字自己取)
2、打开Xcode,创建一个workspace,路径放到文件夹MyTestSDK里面,Xcode---File---New---Workspace
之后可以看到MyTestSDK文件夹里面多了一个.xcworkspace文件
二、创建SDK
1、打开MyTestSDK.xcworkspace文件,创建project
选择Cocoa Touch Framework
把framework添加到workspace里面
添加之后的效果图
三、创建Demo
1、打开MyTestSDK.xcworkspace文件,创建project
2、选择Single View Application
3、添加application到workspace
最终效果图
从上图可以看出,上面是demo,下面是sdk,怎么把这两者关联起来呢????????
四、Demo的关联以及SDK的开发调试
1、把SDK打包成framework
这个步骤网上有很多种教程,最后可以手动生成framework也可以用脚本生成framework,这里就以脚本生成framework为例,其他方法有兴趣的同学可以自己研究
参考:qingmang.me/articles/5162103427194116731/
这里创建一个MyView类,继承于UIView,简单的重写了初始化方法,设置了颜色
设置Build Setting参数
更改参数,在Architectures下增加armv7s(iOS11上不支持armv7s,如果报错就不要添加),并选中。将Build Active Architecture only设置为NO
设置Headers,将要公开的头文件拖到Public下,要隐藏的放到Private或Project下,隐藏的头文件不能被引用
然后需要在MyTestSDK.h(必须是公开的,否则无法引用)中将所有要公开的.h引入
创建一个Aggregare
嵌入脚本,选中刚刚创建的Aggregare,然后选中右侧的Build Phases,点击左边的+号,选择New Run Script Phases
下面把这段脚本复制进去(注意:脚本里面PROJECT_PATH_ARR中要设置自己工程路径)
参考链接:iOS 打包FrameWork脚本 - 狂奔_蜗牛113 - 博客园
#!/bin/sh
#----------------------------------可以自定义的配置项--------------------------------------
#1.需要打包的工程路径,全部是绝对路径
#2.路径必须到.xcodeproj
#3.如果该工程有多个Target,需要指定一个特定的Target来编译,在路径后面加(两个下划线)__Target名称 例如:xxx/projectName.xcodeproj__TargetName
PROJECT_PATH_ARR=(
"/Users/xxx/Desktop/MyTestSDK/MyTestSDK/MyTestSDK.xcodeproj" \
)
#将PROJECT_PATH_ARR配置的地址【全部】Build出来的SDK所支持架构,设置0或者1
#0:支持真机和模拟器
#1:只支持真机
BUILD_SUPPORT_PLATFORM=0
#路径相关配置
TMP_PATH="${HOME}/Desktop" #编译后的文件存放根路径,此路径默认是桌面路径,可以自己指定对应的路径
#---------------------------------------------------------------------------------------------------------
#开始时间
start_seconds=$(date +%s);
CURRENT_DATE=`date +%Y-%m-%d_%H-%M-%S`
ROOT_BUILDPATH="${TMP_PATH}/PbLib${CURRENT_DATE}"
TMP_SYMROOT="${ROOT_BUILDPATH}"
TMP_OBJROOT="${TMP_SYMROOT}/TMP_build"
LOG_DIR="${ROOT_BUILDPATH}/Build_Log"
TMP_BUILDSETTING_DIR="${ROOT_BUILDPATH}/TMP_BuildSetting"
#build类型 有elease和dDebug两种选项
BUILD_TYPE="Release"
TMP_TARGET_NAME=""
TMP_FULL_PRODUCT_NAME=""
#创建文件路径
#清除某个目录里面的内容,如果有则清除内容,没有的直接创建该目录
#参数1:目录
clearDirAll(){
if[ ! -d $1];
then
mkdir -p $1
else
#先删除,再创建
rm -rf $1
mkdir -p $1
fi
return0
}
#创建Build根目录
clearDirAll ${ROOT_BUILDPATH}
clearDirAll ${TMP_BUILDSETTING_DIR}
clearDirAll ${LOG_DIR}
#合并真机和模拟器
#参数1:当前创建的Build目录
mergeSDK(){
#1.找到真机和模拟器路径
tmpIphonesPath="$1/${BUILD_TYPE}-iphoneos"
tmpIphonesimulatorPath="$1/${BUILD_TYPE}-iphonesimulator"
tmpSDKName=""
#2.获取当前SDK名称
forfilein${tmpIphonesPath}/*
do
#拿到SDK文件名称
tmpName=`basename ${file}`
if[[ $tmpName =~ $TMP_FULL_PRODUCT_NAME ]];then
tmpSDKName=${tmpName}
fi
done
#3.根据BUILD_SUPPORT_PLATFORM配置项判断Build模拟器还是真机
if[ $BUILD_SUPPORT_PLATFORM -eq0];then #支持真机和模拟器
#判断当前的SDK时.a类型的还是.framework类型的,并且各自合并
tmpAStr=".a"#当前是.a形式的SDK
tmpFStr=".framework" #当前是.framework形式的SDK
if[[ $tmpSDKName =~ $tmpFStr ]];then
#获取SDK名称
tmpFrameWorkName=${tmpSDKName%.*}
#合并SDK
#将真机模式下的FrameWork拷贝一份到根目录下
cp -r ${tmpIphonesPath}/${tmpSDKName} $1/${tmpSDKName}
lipo -create"${tmpIphonesPath}/${tmpSDKName}/${tmpFrameWorkName}" "${tmpIphonesimulatorPath}/${tmpSDKName}/${tmpFrameWorkName}" -output "$1/${tmpSDKName}/${tmpFrameWorkName}"
elif[[ $tmpSDKName =~ $tmpAStr ]];then
#合并SDK
lipo -create"${tmpIphonesPath}/${tmpSDKName}" "${tmpIphonesimulatorPath}/${tmpSDKName}" -output "$1/${tmpSDKName}"
fi
elif[ $BUILD_SUPPORT_PLATFORM -eq1];then#只支持真机
#如果只支持真机,就直接将真机目录下的SDK拷贝到根目录下就可以
cp -r ${tmpIphonesPath}/${tmpSDKName} $1/${tmpSDKName}
fi
#4.将.h文件拷贝到.a文件的同级目录下
find $1-maxdepth1-type d -name"*.h"-exec rm -rf {} \;
find ${tmpIphonesPath} -maxdepth1-type f -name"*.h"-exec mv -f {} $1\;
#5.移除iphones目录和iphonesimulator目录
rm -rf"${tmpIphonesPath}"
rm -rf"${tmpIphonesimulatorPath}"
}
#.a库打包方法,接收两个参数
#参数1:工程路径,精确到xxx.xcodeproj
#参数2:TARGET名称
buildLibrary(){
if[ -n $1];then
if[ -n $2];then
#创建每个.a的Build路径
buildDir="${ROOT_BUILDPATH}/$2"
objRootPath="${TMP_OBJROOT}/$2"
echo"--正在编译 $2........."
#创建目录
clearDirAll ${buildDir}
logFile="${LOG_DIR}/$2-Build.log"
#根据BUILD_SUPPORT_PLATFORM配置项判断Build模拟器还是真机
if[ $BUILD_SUPPORT_PLATFORM -eq0];then #支持真机和模拟器
echo"---------------开始Build模拟器---------------" >>${logFile}
#开始Build模拟器
xcodebuild -configuration"${BUILD_TYPE}"ONLY_ACTIVE_ARCH=NO -project"$1"-target"$2"SYMROOT="${TMP_SYMROOT}"OBJROOT="${objRootPath}"BUILD_DIR="${buildDir}"-sdk iphonesimulator clean build >>${logFile}
echo"---------------开始Build真机---------------" >>${logFile}
#开始Build真机
xcodebuild -configuration"${BUILD_TYPE}"ONLY_ACTIVE_ARCH=NO -project"$1"-target"$2"SYMROOT="${TMP_SYMROOT}"OBJROOT="${objRootPath}"BUILD_DIR="${buildDir}"-sdk iphoneos clean build >>${logFile}
elif[ $BUILD_SUPPORT_PLATFORM -eq1];then#只支持真机
echo"---------------开始Build真机---------------" >>${logFile}
#开始Build真机
xcodebuild -configuration"${BUILD_TYPE}"ONLY_ACTIVE_ARCH=NO -project"$1"-target"$2"SYMROOT="${TMP_SYMROOT}"OBJROOT="${objRootPath}"BUILD_DIR="${buildDir}"-sdk iphoneos clean build >>${logFile}
fi
#3.合并真机和模拟器
mergeSDK ${buildDir};
#4.移除工程根目录下的build目录
tmpPath=$1
projectPath=${tmpPath%/*}
rm -rf"${projectPath}/build"
rm -rf"${TMP_OBJROOT}"
else
echo"Target不能为空"
fi
else
echo"工程路径不能为空"
fi
}
#导出BuildSetting文件并且找出TARGET_NAME和PRODUCT_NAME环境变量的值
#param1:工程路径
#param2:TARGET名称,如果没有可以传nil
readBuildSetting(){
#0.清除全局变量的值
TMP_TARGET_NAME=""
TMP_FULL_PRODUCT_NAME=""
#1.将工程工程对应Target的BuildSetting文件导出到本地
BuildSettingFile="${TMP_BUILDSETTING_DIR}/tmp_buildSetting.txt"
if[ -n"$1"];then
cmdStr="xcodebuild -list -project $1 -showBuildSettings >${BuildSettingFile}"
if[ -n"$2"];then
cmdStr="xcodebuild -list -project $1 -target $2 -showBuildSettings >${BuildSettingFile} "
fi
#执行导出BuildSetting的文件
# echo "命令:${cmdStr}"
eval ${cmdStr}
fi
#2.解析导出的BuildSetting文件,找出其中的TARGET_NAME和PRODUCT_NAME,并赋值给TMP_TARGET_NAME,TMP_PRODUCT_NAME
IFS='='
whilereadk v
do
if[["$k"== *FULL_PRODUCT_NAME* ]];then
TMP_FULL_PRODUCT_NAME=$(echo $v | sed's/[[:space:]]//g')
elif[["$k"== *TARGET_NAME* ]];then
TMP_TARGET_NAME=$(echo $v | sed's/[[:space:]]//g')
fi
done< ${BuildSettingFile}
# echo "TMP_FULL_PRODUCT_NAME=${TMP_FULL_PRODUCT_NAME} TMP_TARGET_NAME=${TMP_TARGET_NAME}"
rm -rf"${BuildSettingFile}"
}
startBuild(){
#1.遍历数组,根据路径截取到相应的工程路径以及工程名
forproPathin${PROJECT_PATH_ARR[*]}
do
#2.获取工程路径
projectPath=${proPath}
targetName=""
#3.判断工程路径中是否包含__,如果包含了则说明指定了Target
tmpStr="__"
if[[ $proPath =~ $tmpStr ]]
then
projectPath=${proPath%__*}
#取到需要的Target名称
targetName=${proPath#*__}
fi
#4.判断targetName是否为空,如果为空则代表TargetName和工程名称相同
# if [ -z "${targetName}" ];then
# xcodeproj=${projectPath##*/}
# projectName=${xcodeproj%.*}
# targetName=${projectName}
# fi
#5.读取TARGET_NAME和PRODUCT_NAME
readBuildSetting ${projectPath} ${targetName}
#6.调用Build函数进行Build
buildLibrary ${projectPath} ${TMP_TARGET_NAME}
done
}
echo "-----------------开始Build-----------------"
startBuild;
end_seconds=$(date +%s);
echo "-----------------Build完成 耗时:$((end_seconds-start_seconds))s-----------------"
#移除BuildSetting工作目录
rm -rf "${TMP_BUILDSETTING_DIR}"
open ${ROOT_BUILDPATH}
如图所示:
最后编译,command + B,编译通过在桌面(不一定在桌面,需要看脚本中自己设置的路径)中找到framework,拷贝出来
2、Demo与SDK的关联
把打包好的framework拖到demo里面
使用SDK,运行demo
运行的结果
这时候SDK跟Demo就关联起来了,此时修改下面SDK中的代码,运行demo就是修改后的效果,然后就可以愉快的在这个工程里面开发调试SDK了,如果我把MyView的颜色设置为yellow,再去运行demo,看一下效果
最后的最后,把这个工程上传到SVN就可以愉快的开发了。。。以上是我个人的理解,如有错误,请各位大牛批评指正,文中framework的打包方法参考网上资料,参考链接:qingmang.me/articles/5162103427194116731/