iOS SDK 开发 -- 入微三星
在入微二星里说了如何通过脚本去打包 Lib,这里主要说下如何通过脚本打包 Framework。
我们先说下思路:首先需要把 Framework 里的头文件更新,更新头文件后再生成一个 framework 包,这个时候的 framework 是无实际内容的,只有文件结构,需要向里面添加对应的 Lib 包,最后才可以根据 framework 的头文件去调用 Lib 里面的方法了。
更新头文件
#!/bin/sh
##############################
# 更新项目里的对外 API 头文件,并且做 import 形式的转换工作
##############################
echo "\n=================================================="
echo "Action - updateAPIs"
# 引用公共的文件
source Scripts/common.sh
if [ ! $SDK_REPO_DIR ]; then
echo "SDK_REPO_DIR not exist. Exit.";
exit 1;
fi
SOURCE_PATH_ROOT="${SDK_REPO_DIR}/sdkSample-lib/Lib/Public"
# 这里可以有SOURCE_PATH_ROOT其它的子目录
DEST_PATH_ROOT="${SDK_REPO_DIR}/sdkSample-framework/API"
# 这里可以有DEST_PATH_ROOT其它的子目录
SOURCE_DIRS=($SOURCE_PATH_ROOT)
DEST_DIRS=($DEST_PATH_ROOT)
# 先确认目录环境是否正常
existDir() {
theDir=`ls $1`
if [ ! theDir ]
then
echo -e "$1 does not exist. Not the right path to execute the script."
exit
fi
}
existDir $SOURCE_PATH_ROOT
existDir $DEST_PATH_ROOT
src_imports=('#import \"sdkSample.h\"',
'#import \"SDKConstants.h\"'
)
dest_imports=('#import <sdkSample\/sdkSample.h>',
'#import <sdkSample\/SDKConstants.h>'
)
replace_imports() {
len_imports="${#src_imports[@]}"
for i in `seq $len_imports`
do
`sed -i "" "s/${src_imports[$i-1]}/${dest_imports[$i-1]}/g" $1`
done
}
index=0
for dir in "${SOURCE_DIRS[@]}"
do
for file in $dir/*.h;
do
filename=$(basename $file)
destFile="${DEST_DIRS[$index]}/$filename"
`cp "$file" "$destFile"`
replace_imports "$destFile"
done
let "index+=1"
done
# Insert all .h imports into sdkSample.h - the only import file for App
sdkSampeFile="$DEST_PATH_ROOT/sdkSample.h"
echo "Insert imports into sdkSample.h - $sdkSampeFile"
sed -i "" '9 a\
#import <sdkSample\/SDKConstants.h>\
' $sdkSampeFile
这是主要是做把 import 的转换的,因为对外的 api 的接口中,#import "SDKConstants.h" 应该转换成 #import <sdkSample/SDKConstants.h>,还有就是将其它需要用到的头文件导入到sdkSample.h 里面,目的是只要用户导入 sdkSample.h 后,其头文件也保证已经全部导入,不再需要用户单独去做导入工作,而且也提供单独导入指定头文件的功能。
生成 Framework
B388CE0C-546A-42EB-9D38-4C3E24886481.png在 Framework 根目录下新建 packageTempFramework.sh 和 Rakefile,前面已经有相关的介绍,这里面就不多说了。说下这里面的打包脚本名为什么叫 packageTempFrame,因为生成只是 framework 的文件结构,还没有实际内容,上面已经提过了。
我们看下 packageTempFramework 的内容:
#!/bin/sh
#######################################################
### Package sdkSample.framework folder structure.
#######################################################
echo "\n=================================================="
echo "Action - packageTempFramework"
echo "Current dir - `pwd`"
# 引用公共的文件
if [ ! -f Scripts/common.sh ]; then
echo "ERROR: not found Scripts/common.h"
exit 1
fi
source Scripts/common.sh
# 更新 API 文件
source Scripts/updateAPIs.sh
cd $SDK_REPO_DIR/sdkSample-framework
# rake build
rake
if [ $? == 0 ]; then
echo "Rake build success"
# Validdate result of rake
if [ ! -d $SDK_FRAMEWORK_STRUCT_DIR ]; then
echo "The expect rake build outoput dir does not exist - ${SDK_FRAMEWORK_STRUCT_DIR}"
exit 1
fi
# Write version/buildId into framework info.plist
defaults write $SDK_FRAMEWORK_STRUCT_DIR/Info CFBundleVersion $SDK_BUILDID
defaults write $SDK_FRAMEWORK_STRUCT_DIR/Info CFBundleShortVersionString $SDK_VERSION
else
echo "Rake build failed"
fi
最后会把版本会版本号构建号保存到工程的 info.plist 文件中。
再看下 Rakefile 的内容:
##########################
# Rake for build frameowrk structure. Will dist to RootDir/build/sdkSample.framework
##########################
puts "\nAction - sdkSample-framework rake build"
outputFile = ENV['SDK_FRAMEWORK_STRUCT_DIR']
if !outputFile
outputFile = "../build/sdkSample.framework/"
puts "WARN - Running rake with no build dependency."
end
puts "Will put dist file into - '#{outputFile}'"
$config = "Release"
def xcodebuild(sdk, archs, iphoneos_deployment_target, products_dir)
puts $config
config = $config
sh "xcodebuild -project 'sdkSample-framework.xcodeproj' -target sdkSample -configuration '#{config}' -sdk '#{sdk}' clean build ARCHS='#{archs}' VALID_ARCHS='#{archs}' IPHONEOS_DEPLOYMENT_TARGET='#{iphoneos_deployment_target}' TARGET_BUILD_DIR='#{products_dir}' BUILT_PRODUCTS_DIR='#{products_dir}' "
end
desc "Build arm"
task :build_arm do
xcodebuild('iphoneos', 'armv7 armv7s', '7.0', 'build-arm')
end
desc "Build arm64"
task :build_arm64 do
xcodebuild('iphoneos', 'arm64', '7.0', 'build-arm64')
end
desc "Build i386"
task :build_i386 do
xcodebuild('iphonesimulator', 'i386', '7.0', 'build-i386')
end
desc "Build x86_64"
task :build_x86_64 do
xcodebuild('iphonesimulator', 'x86_64', '7.0', 'build-x86_64')
end
desc "Build fat"
task :build_fat => [:build_arm] do
sh "lipo -create ./build-arm/sdkSample.framework/sdkSample -output ./build-arm/sdkSample.framework/sdkSample"
sh "mv ./build-arm/sdkSample.framework \"$(dirname #{outputFile})\""
end
desc "Clean"
task :clean do
Dir["build-*"].each{ |x|
`rm -r '#{x}'`
}
end
desc "Clean binary"
task :distclean => [:clean] do
Dir["build/*.a"].each{ |x|
`rm -r '#{x}`
}
end
task :debug => [:distclean, :debug_fat]
task :default => [:distclean, :build_fat, :distclean]
这里和 Lib 打包相似,就不单独说了。需要强调的是,这里只是生成 Framework 的文件结构。
提供核心打包函数:
FD4100F5-AD36-4B59-BCCA-3EE1503E5A7A.png新建一个 debugOrReleaseFramework 的脚本,主要提供 Framework 打包的核心功能,把生成的 lib 内容复制到 Framework 的文档结构里面。这里主要是和 Lib 打包相联系的,所以也是需要提供 Debug or release 参数进行打包的。
脚本内容如下:
#! /bin/sh
##############################
# 执行打包 Framework
##############################
# 引用公共的文件
source Scripts/common.sh
if [ ! $SDK_REPO_DIR ]; then
echo "SDK_REPO_DIR not exist. Exit.";
exit 1;
fi
# 核心的打包函数
packageFramework() {
echo "Action - packageFramework - $1"
if [ $# -lt 1 ]; then
echo "At least one param is required - debug/release";
exitAbnormal
fi
if [ ! $1 = debug -a ! $1 = release ]; then
echo "First param should be debug or release";
exitAbnormal
fi
buildVersion=$1;
# lib build
cd $SDK_REPO_DIR
bash ${SDK_REPO_DIR}/sdkSample-lib/packageLib.sh $buildVersion
if [ $? != 0 ]; then
echo "ERROR: packageSdkSampleLib script fail."
exitAbnormal
fi
# Confirm expect output of last step
if [ ! -f ${SDK_LIB_FILE} ]; then
echo "Unexpected - expect file does not exist - ${SDK_LIB_FILE}"
exitAbnormal
fi
# Copy lib file into framework struct
cp "${SDK_LIB_FILE}" "${SDK_FRAMEWORK_STRUCT_DIR}/sdkSample"
if [ $? != 0 ]; then
echo "ERROR: failed to copy sdkSample lib into framework."
exitAbnormal
fi
cd $SDK_REPO_DIR/dist
if [ $buildVersion = debug ]; then
zipDir="sdkSample-debug-${SDK_VERSION}b${SDK_BUILDID}"
else
zipDir="sdkSample-${SDK_VERSION}"
fi
mkdir $zipDir
cp -r $SDK_FRAMEWORK_STRUCT_DIR ${zipDir}/
if [ $? != 0 ]; then
echo "ERROR: failed to copy sdkSample framework into dist."
exitAbnormal
fi
} # end of packageFramework
控制打包流程
结合面两篇文章(入微一星 和 入微一星)已经说完了 Lib 的打包和 Framework 的打包,现在我们需要提供一个统一控制流程的脚本,在根目录下新建一个 packageFramework.sh:
A44676EE-D0C5-4470-BA16-8A2BC84BA45B.png内容如下:
#!/bin/sh
###################################
# Build sdkSample.framework
# If there is one param - debug/release, will package ther version. Otherwise package both debug and release version.
###################################
echo "\n=================================================="
echo "Action - packageDdkSampleeFramework"
echo "Current dir - `pwd`"
# 引用公共的文件
if [ ! -f Scripts/common.sh ]; then
echo "ERROR: cannot found the Script/common.h"
exit 1
fi
source Scripts/common.sh
if [ ! -f Scripts/debugOrReleaseFramework.sh ]; then
echo "ERROR: cannot found the Script/common.h"
exit 1
fi
source Scripts/debugOrReleaseFramework.sh
if [ ! $SDK_REPO_DIR ]; then
echo "SDK_REPO_DIR not exist. Exit.";
exit 1;
fi
if [ $# -gt 0 ]; then
if [ ! $1 = debug -a ! $1 = release ]; then
echo "First param should be debug/release";
exit 1;
fi
buildVersion=$1
fi
# Prepare
clearAndPrepare
# Confirm the git workspace is clean.
checkGitWorkspaceClean $SDK_REPO_DIR
# get and set version
updateBuildID
if [ $? != 0 ]; then exitAbnormal; fi
getVersion
if [ $? != 0 ]; then exitAbnormal; fi
# Expect output definitions
PROJECT_NAME="sdkSample-iOS-SDK"
export PROJECT_NAME
SDK_LIB_FILE="${SDK_REPO_DIR}/build/sdkSample-${SDK_VERSION}b${SDK_BUILDID}.a"
export SDK_LIB_FILE
SDK_FRAMEWORK_STRUCT_DIR="${SDK_REPO_DIR}/build/sdkSample.framework"
export SDK_FRAMEWORK_STRUCT_DIR
SDK_DOCS_DIR="${SDK_REPO_DIR}/build/appledoc"
export SDK_DOCS_DIR
echo "\n\n\n ===================== Begin packaging"
cd $SDK_REPO_DIR
bash ${SDK_REPO_DIR}/sdkSample-framework/packageTempFramework.sh
if [ $? != 0 ]; then
echo "ERROR: packageTempFramework script fail."
exitAbnormal
fi
# Check expected outout dir exist
if [ ! -d $SDK_FRAMEWORK_STRUCT_DIR ]; then
echo "ERROR: expect output dir not exist - $SDK_FRAMEWORK_STRUCT_DIR"
exitAbnormal
fi
# To package debug/release framework zip
cd $SDK_REPO_DIR/sdkSample-lib
if [ $buildVersion ]; then
packageFramework $buildVersion
else
packageFramework debug
packageFramework release
fi
resetGitworkspace $SDK_REPO_DIR
echo "===================== End packaging \n\n\n "
这里需要注意的是,在打包前需要确保当前 git 仓库是 clean 的,最后打包完成后,需要把仓库 reset 下,防止污染到原来的代码。这部分内容主要是控制整个打包的流程,也就不多说明了,直接看脚本和脚本上面的注释应该没有问题了。
小结
SDK 开发的入微三篇写到这里已经算是写完了,这三篇文章主要说的是 SDK 的基础框架的构建和通过脚本进行打包,内容上没有过多提及到实际中的 SDK 开发内容,后面会不定期更新 SDK 开发的相关内容,有兴趣的朋友可以关注下SDK 开发专题。本来应该还有一篇介绍如果通过 appledoc 生成接口文档的,这个下次再以扩展形式出了。源码点这里。
最后打个小广告:长期接 iOS 外包,有需求欢迎联系~~~~