iOS SDK 封装和开发实战iOS SDK 开发SDK开发

iOS SDK 开发 -- 入微三星

2016-10-04  本文已影响304人  YxxxHao

入微二星里说了如何通过脚本去打包 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 外包,有需求欢迎联系~~~~

上一篇下一篇

猜你喜欢

热点阅读