在入微二星里說了如何通過腳本去打包 Lib遏餐,這里主要說下如何通過腳本打包 Framework历恐。
我們先說下思路:首先需要把 Framework 里的頭文件更新软棺,更新頭文件后再生成一個 framework 包诫欠,這個時候的 framework 是無實際內(nèi)容的艰赞,只有文件結(jié)構(gòu),需要向里面添加對應(yīng)的 Lib 包提佣,最后才可以根據(jù) framework 的頭文件去調(diào)用 Lib 里面的方法了泽艘。
更新頭文件
#!/bin/sh
##############################
# 更新項目里的對外 API 頭文件欲险,并且做 import 形式的轉(zhuǎn)換工作
##############################
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)
# 先確認目錄環(huán)境是否正常
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 的轉(zhuǎn)換的,因為對外的 api 的接口中匹涮,#import "SDKConstants.h" 應(yīng)該轉(zhuǎn)換成 #import <sdkSample/SDKConstants.h>,還有就是將其它需要用到的頭文件導(dǎo)入到sdkSample.h 里面槐壳,目的是只要用戶導(dǎo)入 sdkSample.h 后然低,其頭文件也保證已經(jīng)全部導(dǎo)入,不再需要用戶單獨去做導(dǎo)入工作务唐,而且也提供單獨導(dǎo)入指定頭文件的功能雳攘。
生成 Framework
在 Framework 根目錄下新建 packageTempFramework.sh 和 Rakefile,前面已經(jīng)有相關(guān)的介紹枫笛,這里面就不多說了吨灭。說下這里面的打包腳本名為什么叫 packageTempFrame,因為生成只是 framework 的文件結(jié)構(gòu)刑巧,還沒有實際內(nèi)容喧兄,上面已經(jīng)提過了。
我們看下 packageTempFramework 的內(nèi)容:
#!/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
最后會把版本會版本號構(gòu)建號保存到工程的 info.plist 文件中啊楚。
再看下 Rakefile 的內(nèi)容:
##########################
# 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 打包相似吠冤,就不單獨說了。需要強調(diào)的是恭理,這里只是生成 Framework 的文件結(jié)構(gòu)拯辙。
提供核心打包函數(shù):
新建一個 debugOrReleaseFramework 的腳本,主要提供 Framework 打包的核心功能颜价,把生成的 lib 內(nèi)容復(fù)制到 Framework 的文檔結(jié)構(gòu)里面涯保。這里主要是和 Lib 打包相聯(lián)系的,所以也是需要提供 Debug or release 參數(shù)進行打包的周伦。
腳本內(nèi)容如下:
#! /bin/sh
##############################
# 執(zhí)行打包 Framework
##############################
# 引用公共的文件
source Scripts/common.sh
if [ ! $SDK_REPO_DIR ]; then
echo "SDK_REPO_DIR not exist. Exit.";
exit 1;
fi
# 核心的打包函數(shù)
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
控制打包流程
結(jié)合面兩篇文章(入微一星 和 入微一星)已經(jīng)說完了 Lib 的打包和 Framework 的打包夕春,現(xiàn)在我們需要提供一個統(tǒng)一控制流程的腳本,在根目錄下新建一個 packageFramework.sh:
內(nèi)容如下:
#!/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 下狈蚤,防止污染到原來的代碼困肩。這部分內(nèi)容主要是控制整個打包的流程,也就不多說明了脆侮,直接看腳本和腳本上面的注釋應(yīng)該沒有問題了锌畸。
小結(jié)
SDK 開發(fā)的入微三篇寫到這里已經(jīng)算是寫完了,這三篇文章主要說的是 SDK 的基礎(chǔ)框架的構(gòu)建和通過腳本進行打包靖避,內(nèi)容上沒有過多提及到實際中的 SDK 開發(fā)內(nèi)容潭枣,后面會不定期更新 SDK 開發(fā)的相關(guān)內(nèi)容比默,有興趣的朋友可以關(guān)注下SDK 開發(fā)專題。本來應(yīng)該還有一篇介紹如果通過 appledoc 生成接口文檔的盆犁,這個下次再以擴展形式出了命咐。源碼點這里。