iOS持续集成构建

群组
Flutter,iOS,Android,Python等,闲聊工作&技术&问题;
个人主页:https://waitwalker.cn
telegram群链接:https://t.me/joinchat/Ej0o0A1ntlq5ZFIMzzO5Pw

        目前市面上持续集成的方案很多:例如,Jenkins, Fastlane,Xcode server等,这些持续集成的方案大同小异,他们之间的性能差异笔者没有做大量的横向分析,只是大体比较了一下打包时间.总结来说,持续集成主要是三个步骤:1.拉取代码;2.编译打包;3.分发数据(打包结果),下面将通过两种方案(Jenkins和Xcode server)来分析一下这三个过程.

Jenkins集成方案

        Jenkins作为免费集成方案,其社区拥有大量插件,非常友好,所以用户也众多.
首先来安装Jenkins,Jenkins官网提供了多个系统环境的软件包,我选择的是macOs系统,选择下载安装,步骤如下图:

下载Jenkins

下载Jenkins.png

安装Jenkins

安装Jenkins.png

设置管理员账号密码

        安装完成后,一般mac环境集成了Apache服务器会自动配置启动8080端口,Jenkins的初始化页面也会在安装完成后自动弹出.此时只要找到图中红色标记路径cat或者vi看一下里面的秘钥,进入Jenkins初始化设置工作.这个过程会设置管理员账号密码等.
获取初始密码Jenkins.png

Jenkins插件安装

        初始化完成后,就可以利用管理员账号登录.登录后通常可以安装一些常用插件,一般有默认插件和自定义插件,选择默认插件即可.
Jenkins安装插件.png
        基本的环境搭建完成后,就可以实施上面的三个过程了.其实Jenkins的主要工作流程,可以通过下图来直观看出来.
Jenkins工作流程.png

步骤1 拉取代码

git仓库分支配置.png
        拉取代码过程比较简单,主要是从指定仓库中克隆代码到Jenkins的工作目录.

步骤2 编译打包

        编译打包命令主要有xcodebuild,xcrun,xctool(facebook)等,前两个是官方的,后一个是Facebook出品,xctool里面集成了个性化定制,需要的可以细研究一下,文中只是对xcodebuild做出使用分析.
xcodebuild编译过程也主要分三个过程:

- clean
    xcodebuild -workspace MyWorkspace.xcworkspace -scheme SchemeName

- archive
     xcodebuild archive -workspace MyWorkspace.xcworkspace -scheme SchemeName

- export ipa
     xcodebuild -exportArchive -archivePath MyMobileApp.xcarchive -exportPath ExportDestination.ipa -exportOptionsPlist 'exportPlist.plist'

        这里多说两句:由于IDE变化,导致编辑脚本稍微有一些出入,主要是在编译的第三步(- export ipa),这步Xcode 8.0需要指定描述文件,Xcode 9.0需要指定exportOptionsPlist(这个是主要包含一些证书, ipa模式等键值表).下面贴出打包执行脚本的全部命令(Xcode 9.0):

export ETT_APP_NAME=app名称
export ETT_WORKSPACE_NAME=工作区名称
export ETT_SCHEME=scheme名称
export ETT_PROVISIONING_PROFILE=描述文件(Xcode9.0用不到)
export ETT_BUILD_TYPE=编译类型(用于区分发布还是AdHoc模式,可以忽略)
export ETT_CONFIGURATION=编译配置(主要根据自己的多环境进行配置,比如Release,Debug等)

###############################################################################################################
export ETT_JENKINS_TIME=$(date +%m%d)
export ETT_GIT_COMMIT=${GIT_COMMIT:0:7}
export ETT_GIT_REV=`git rev-list HEAD | wc -l | awk '{print $1}'`
export ETT_VERSION_PRO=`/usr/bin/agvtool mvers -terse1`
export ETT_VERSION_NUMBER=$ETT_VERSION_PRO$ETT_BUILD_TYPE
export ETT_BUILD_VERSION=$ETT_GIT_REV.$BUILD_NUMBER
export ETT_BUILD_ID=$ETT_VERSION_NUMBER-$ETT_JENKINS_TIME-$ETT_GIT_REV-$BUILD_NUMBER-G$ETT_GIT_COMMIT

export NEXUS_JENKINS_NAME=打包后上传账号
export NEXUS_JENKINS_PASSWD=密码


export ExportOptionsPlistPath=/Users/用户/Downloads/zhengshu/ExportOptions.plist
export XCODE=/usr/bin
export ETT_DIST_ROOT_PATH=工作区路径
export ETT_DIST_PATH=$ETT_DIST_ROOT_PATH/$BUILD_NUMBER
export ETT_ARCHIVE_PATH=$ETT_DIST_PATH/$ETT_APP_NAME.xcarchive
export ETT_WORK_SPACE=$WORKSPACE/$ETT_WORKSPACE_NAME.xcworkspace

export ETT_FILE_NAME=$ETT_APP_NAME-$ETT_BUILD_ID
export ETT_IPA_NAME=$ETT_FILE_NAME.ipa
export ETT_EXPORT_PATH=$ETT_DIST_PATH/$ETT_IPA_NAME
export ETT_PACKAGE_NAME=$ETT_FILE_NAME.tar.gz
export ETT_PACKAGE_PATH=$ETT_DIST_PATH/$ETT_PACKAGE_NAME
export ETT_NEXUS_FILE_NAME=$ETT_APP_NAME-$ETT_JENKINS_TIME-$BUILD_NUMBER-$ETT_GIT_COMMIT.tar.gz

export ETT_UPLOAD_DSYM_SRC=$ETT_WORKSPACE_NAME.app.dSYM
export ETT_UPLOAD_DSYM_FILE=$ETT_FILE_NAME-dSYM.zip
export ETT_UPLOAD_DSYM_PATH=$ETT_DIST_PATH/$ETT_UPLOAD_DSYM_FILE

if [ ! -d "$ETT_DIST_ROOT_PATH" ]; then
  mkdir $ETT_DIST_ROOT_PATH
fi
if [ ! -d "$ETT_DIST_PATH" ]; then
  mkdir $ETT_DIST_PATH
fi

#/usr/bin/agvtool vers -terse
#/usr/bin/agvtool mvers -terse1

/usr/bin/agvtool new-marketing-version $ETT_VERSION_PRO
/usr/bin/agvtool new-version -all $ETT_VERSION_PRO.$ETT_BUILD_VERSION

#/usr/bin/agvtool vers -terse
#/usr/bin/agvtool mvers -terse1

$XCODE/xcodebuild clean build BITCODE_GENERATION_MODE=bitcode OTHER_CFLAGS="-fembed-bitcode" archive -archivePath "$ETT_ARCHIVE_PATH" -workspace $ETT_WORK_SPACE -destination generic/platform=iOS -scheme $ETT_SCHEME -configuration "$ETT_CONFIGURATION" BUILD_NUMBER="$ETT_BUILD_ID" CONFIGURATION_BUILD_DIR=$ETT_DIST_PATH UPLOAD_dSYM_FILE=$ETT_UPLOAD_DSYM_FILE
$XCODE/xcodebuild -exportArchive -archivePath $ETT_ARCHIVE_PATH -exportPath $ETT_EXPORT_PATH -exportOptionsPlist $ExportOptionsPlistPath -allowProvisioningUpdates

步骤3 分发数据(发布打包)

        这个过程可以直接发布,也可以上传到自己指定的服务器,第三方托管服务器等.我们直接在执行打包脚本的最后面,将打包处理的ipa文件以及符号化文件打包后直接上传到指定服务器:

cd $ETT_DIST_PATH
zip -r $ETT_UPLOAD_DSYM_PATH $ETT_UPLOAD_DSYM_SRC
tar -C $ETT_DIST_PATH -zcvf  $ETT_PACKAGE_PATH $ETT_IPA_NAME $ETT_UPLOAD_DSYM_FILE
curl -v -u $NEXUS_JENKINS_NAME:$NEXUS_JENKINS_PASSWD --upload-file $ETT_PACKAGE_PATH  服务器路径$ETT_APP_NAME/ios/$ETT_VERSION_PRO$ETT_BUILD_TYPE/$ETT_NEXUS_FILE_NAME

        到这里,Jenkins的简单集成过程算完成了,里面涉及到一些环境变量和参数的设置,笔者因为还涉及到Swift和OC混合打包,问题稍多一点.因为业务需求不一样,需要自己去单独设置,有疑问的地方可以一起沟通一下.

Xcode Server集成方案

        这个方案,将会把上面三个过程穿插进去,不在单列出来.网上有其他方案是macOS Server + Xcode Server集成方案,本文只是简单介绍一下通过Xcode Server集成

打开Xcode Server

打开Xcode Server.png

配置Xcode Server管理员账号

配置Xcode Server管理员账号.png

创建Bot(值守机器人)

        配置完成后,然后通过Xcode->Product->Create Bot创建值守机器人.png

配置仓库分支

        配置代码仓库,Xcode集成了Git所以针对你的项目仓库直接添加分支即可.
配置仓库分支.png

编译打包参数配置

        分支添加完成后,就可配置编译的一些选项:scheme,ExportOptionsPlist,Configuration等.
编译打包参数配置.png

构建触发器

构建触发器.png
构建触发器.png

添加签名文件

        下一步添加证书,描述文件等,作者这里选择的是自动签名模式,如果需要可自己指定签名证书,描述文件等,这里不再细说.
添加签名文件.png

添加环境变量

添加环境变量.png
        下一步就是添加编译之前和编译打包之后的动作

添加打包后的脚本命令

添加打包后的脚本命令.png
        这里你可以把打包结果上传到指定位置,脚本可自行查找.

集成打包

        机器人创建完成后会自动运行编译打包一次,下次打包可以直接通过点击Integrate触发打包.
集成打包.png

总结

        两种方案,整个过程走下来并不是很复杂.这里提醒一下,由于Jenkins打包通过脚本命令执行编译打包,这个又依赖于一些环境变量和参数,如果一些插件和参数变了,IDE更新了,系统更新了等等原因,这些很容易造成打包失败,笔者经历多次了,一般就是先把命令拿到终端里面编译打包试一下,排除编译命令问题,然后在调试Jenkins环境.总结下来就是遇到问题时不要着急,慢慢分析,一点一点调试,总会解决的.

最后打个广告:
模仿推特客户端(纯Swift开发,develop分支):
https://github.com/waitwalker/MyTwitter
针对这个客户端简单用Python写了几个接口:
https://github.com/waitwalker/MyTwitterAPI
文章地址:https://www.jianshu.com/p/42ed698c57ad,因为一直在写code,文章比较糙,还没来及整理,抱歉!


  转载请注明: waitwalker iOS持续集成构建

  目录