我的自动化构建之路之 Jenkins+Fastlane+Github内网测试

很久没写文章了,确实觉得也没什么可写的,最近一直研究自动化打包,遇到了一些问题也解决了一些,就准备写一下这个心得吧

Imagem de capa

很久没写文章了,确实觉得也没什么可写的,最近一直研究自动化打包,遇到了一些问题也解决了一些,就准备写一下这个心得吧。

为什么要采用这一种自动化打包方式呢?

可能看到这一篇文章很多人认为 Jenkins就可以实现自动化打包,并且 Fastlane配置 完毕之后打包更加的轻松。干嘛还搞在一起,这不是重复了吗。

可能 Jenkins 对于一般的工程,可能配置不太复杂十分的可行,并且一些打包完毕上传到 Fir.im进行 App 的托管的确十分的方便。

我在之前的公司的确是把所有的 App 的都托管在 Fir.im上面,让测试人员自己进行打包下载安装。

但是,但是,这已经不符合我们现在 App 打包和不满足测试人员进行安装的需求了。

之前在我们公司不用的 Mac mini上面搭建了 Jenkins环境,确实当时还用了一段时间。

最后随着工程每次打包或者运行都需要更改 谷歌统计Branch统计的 Key,因为是配置在打包的 Plist文件里面的,所以在代码无法进行修改。

我为了防止打包的环境出现测试和正式配置错乱,就做了初始化环境配置的判断。 如果判断出来环境配置不符合运行的规则就直接提示用户配置错误,无法继续的运行。

虽然这个功能是好的,但是为此每次打包和运行都引来很多的麻烦。稍微不注意打包的环境可能没改过来,就直接不能运行。

辛辛苦苦编译之后打包安装,花费了多少心血,浪费我多少时间,竟然配置错误了。

为此我做了一款更改环境配置的软件,之前的文章有说起过。问我为什么不写脚本写 Mac 软件。因为我除了熟悉 Objective-C和了解 Swift对于其他的语言完全不会呀,我只想静静。

环境配置切换的软件做出来了,配置好了。前期确实很好用,最后缺点还是一点点的暴露出来了。

在测试阶段还好,测试人员顶多过来让你打最新的测试包。但是到了后台上线的时候,为了测一下不影响 iOS 现在线上的版本。

测试人员就过来跑到我们的面前。

给我打一个 1.5.1版本的 c分支的包!

给我打一个 1.5.1版本的 trunk分支的包!

给我打一个 1.5.1版本的 预发布包!

……!

测试,你烦人不,烦人不,别跑呀!看我不打断你的腿!

为了不因为分支频繁的打包,我做了可以在程序内部进行 切换分支测试切换到预发布的功能。

其实这个功能早在去年十月份我请假回家那一天上午就做好了,但是最近又优化了功能。

做好之后再也没听到测试要打那个 分支,要打 预发布的包的话了。

虽然现在的打包需求变成了只用打 测试预发布环境的安装包,但是我觉得还是很烦,毕竟每次打包都需要几分钟,那还是在我 这个 拥有下面配置的机器上面。

我觉得还是很烦,觉得还是很影响我安静的敲代码,因为我是一个懒人,能用工具做的绝不自己弄。

当时想着利用 Jenkins进行打包之前写一个 Shell脚本替换环境的配置,为此我那段时间还专门看了 Shell的入门教程,最后我放弃了。

为了这么小的需求还要专门学一下 Shell,我觉得代价有些大,就只看了简单的语法就到此结束了。

看来 Jenkins这条路已经在我这边行不通了,难道就没有其他的方案可以解决掉我们现在的问题吗?

之前还想把 Fir-Ci打包的命令和我需要打包一套功能做成一个客户端,方便我进行打包。

但是因为我竟然没找到怎么在 NSTask执行 Sudo命令和自动输入密码,最后这个方案也是结束了。

在我准备放弃自动化打包这个念头的时候,这个时候不知道从什么地方听到了 Fastlane这个自动化打包的名词。

我看了 Fastlane是上万星的时候,我仿佛看到了希望之光。上万星,这说明主要的公司和大部分的开发者都在用这个进行打包。

以后用 Fastlane进行打包成为主流的打包方式,我觉得学习一下。最后还真的找到了插件可以在打包之前修改我们的配置 Key

但是 Fastlane的安装和配置真实一路的血和泪,因为我安装的是 zsh的脚本命令替换掉了 bash系统自带的命令,导致 Fastlane会打包失败。那是之后的事情了。

因为使用 Fastlane我才又一次接触 Fabric这个软件的。之前我还仅以为这只是用来统计崩溃和发布 APP 的软件。

没想到 Fastlane竟然是也是这个公司出的,棒棒的!我把打好的包托管上了 Fabric这个平台上面,但是测试反应下载 APP 是特级慢,特级慢!

我之前经常搭建企业安装的环境,无非就是 点击安装转接到 Plist 的地址,从 Plist读取 Ipa的安装路径进行安装。

不过从 iOS7开始必须让 Plist是正规的地址,不然无法进行安装。

搭建本地安装 ipa 的环境

还可能需要修改的地方

为了防止不和其他的服务端口进行冲突,我们修改一下端口。

  1. 点击 MAMP的配置功能

  1. 点击配置的端口界面

我这边设置上面的端口,其实端口你们可以随便的定义,只要不进行冲突就可以了。

搭建 Jenkins 服务

使用如下的命令进行安装

brew install jenkins

启动

jenkins

现在有个问题当执行 Jenkins的终端关闭之后 Jenkins 服务也就停止了,我也没去研究怎么让服务开机启动不随着中断关闭。

对于 Jenkins安装我也不多说了,可以自己去 谷歌百度也可以参考下面一位简书大神的文章 Mac 安装 Jenkins

安装 Fastlane

  1. 前往 Fastlane的项目地址

    FastlaneGithub 地址

  2. 按照下面的教程进行安装

配置Fastlane(参考我公司项目)

  1. 在终端 cd到项目的主目录

    cd xxx
    

  2. 执行 fastlane init

安装安装的步骤配置完毕之后就自动在工程的目录生成 fastlane的文件夹了。

对于 Fastlane安装不太了解的,也可以去百度和谷歌。

  1. 打开 Fastlane目录下面的 Fastfile文件,可以用记事本打开,也可以用其他的编辑软件,这里我推荐 Github出的 Atom编辑器。

  2. 删除自动生成的代码

  3. 配置测试和线上两种环境

    lane :beta do |values|
      increment_build_number
      test_key
      archiveipa "Debug"
    end
    
    lane :applive do |values|
      increment_build_number
      kive_key
      archiveipa "Release"
    end
    

对于还有其他环境的可以自动的进行配置 其实语法应该还是挺简单的,对于我这个没学过 Ruby的都写出来了,不相信你写不出来。

increment_build_number这个是让每次打包让编译号自动的+1.

  1. 配置CURRENT_PROJECT_VERSION 字段

    前往 Target->Build Setting->current project version字段设置为当前的 Build 号我设置是正整数简单。

  2. 设置环境配置的环境

    def test_key
      set_info_plist_value(key:"branch_key", value:"xxxxxx", path: "./GearBest/Info.plist")
      set_info_plist_value(key:"TRACKING_ID", value:"xxxxxx", path: "./GearBest/Others/GoogleService-Info.plist")
    end
    
    def kive_key
      set_info_plist_value(key:"branch_key", value:"xxxxxx", path: "./GearBest/Info.plist")
      set_info_plist_value(key:"TRACKING_ID", value:"xxxxxx", path: "./GearBest/Others/GoogleService-Info.plist")
    end
    

    我们设置 test_keykive_key两个方法用于每次打包进行正确的配置,解决了我们每次打错环境包的问题。

    一定要配置好 path的路径,不然无法配置正确。

  3. 设置快速切换配置的环境

    lane :test_key_configuration do |values|
      test_key
    end
    
    lane :live_key_configuration do |values|
      kive_key
    end
    

    这样方便我们开发自己撸代码的时候十分切换配置环境 还十分快速。

  4. 配置打包

    def archiveipa(configuration)
      build_number = get_build_number(xcodeproj: "GearBest.xcodeproj") #获取当前的 Build 号码
      version = get_version_number(xcodeproj: "GearBest.xcodeproj") #获取当前的版本号
      output_directory = "/Applications/MAMP/htdocs/ipa/"+configuration+"/GearBest_" + version + "_" + build_number #导出打包文件和 ipa 的目录
      output_name = "GearBest_temp" #导出的ipa 的名字
      gym(scheme: 'GearBest', export_method: 'ad-hoc', configuration: configuration, output_directory: output_directory, output_name:output_name, clean:true) # 进行打包
    end
    

    导出到我们 MAMP服务的地址和生成对应版本和 Build目录是为了方便进行自动发布

新建Jenkins 项目

  1. 新建一个项目

    名字不要包含%%特殊的字符串,防止影响我们自动上传软件的使用。

  2. 配置项目

    配置好我们的 SVN地址这个其实很简单的。

  3. 新建一个构建 Shell脚本

    #!/bin/bash
    
    #rm -rf  /Users/zhangxing/Library/Developer/Xcode/DerivedData/* #这个本来是想打包之前清理 DerivedData 数据的但是清理会影响我本地其他项目 就屏蔽了
    fastlane beta #执行打测试包 需要打其他环境请复制一份修改这里即可。
    cd /Applications/MAMP/htdocs #前往 MAMP服务的文件夹
    touch "jenkins%%${JOB_NAME}%%${BUILD_NUMBER}" #生成最新打包的配置文件
    open /Applications/IPIPA.app #打包自动上传的 APP
    sleep 60 #休眠60秒等待 APP 执行完毕
    

保存等待全部配置完毕执行即可。

在 Github 新建一个存放 Plist 文件的项目。

Github项目新建项目我就不多说了。

  1. Clone 项目到 MAMP的主目录

配置 MAMP目录

  1. 存放 Icon图片

    57x57512x512的图片保存在 MAMP服务的主目录 /Applications/MAMP/htdocs

  2. 新建 ipa目录存放在 /Applications/MAMP/htdocs目录

  3. 保存 mainfest.plist文件到主目录

    模板 Plist 配置文件下载地址

写自动化上传软件

软件源代码不小心删除了。

唉!

唉!

唉!

下面说一下软件逻辑的实现吧。

当时考虑怎么让打包完毕之后让自动生成 Plist 上传最新的 Plistgithub 目录之后生成最新的下载地址。

我当时考虑用 php或者用 Swift的第三方库做一个接口,打包完毕发送一个请求服务器做处理。

考虑到自己 php是菜鸟, Vapor自己又不精通就放弃了,准备再次写一个 Mac 的应用程序

当我们执行 open /Applications/IPIPA.app会打开我们写的应用程序 我们就可以写一些处理的逻辑了。

根据刚才的创建文件的命令

touch "jenkins%%${JOB_NAME}%%${BUILD_NUMBER}"

我们查询 /Applications/MAMP/htdocs目录下面是否存在 jenkins%%开头的文件,没有说明不存在最新的打包 我们直接重新生成本地现有即可。

我们利用字符串分割 %%分割为三部分,读取出最近打包的 项目名称打包的编译号删除 jenkins%%文件。

我们查找 /Applications/MAMP/htdocs/ipa目录是否存在 GearBest_temp.ipa的文件如果存在就是最新打包的 ipa.

我们在 GearBest_temp.ipa上层文件夹 /Applications/MAMP/htdocs/ipa/Debug/GearBest_1.5.1_244找到是 Debug还是 Release的包。并且解析安装包的 版本编译号

我们使用 Copy命令用 NSTask执行一个简单的 Shell脚本把 /Applications/MAMP/htdocs/mainfest.plist的文件复制到 GearBest_temp.ipa的同级目录。

copy $1 $2

利用查找出来的信息 替换到 mainfest.plist里面的 {version}{ipa}字段。重新命名 PlistGearBest_版本号_编译号.plist

GearBest_temp.ipa复制一份 ipa命名为 GearBest.ipa删除 GearBest_temp.ipa文件

复制我们的配置 Plist/Applications/MAMP/htdocs/iPiPa/plist目录。

执行上传脚本

 cd /Applications/MAMP/htdocs/iPiPa
 git add .
 git commit -m "change"
 git push

请一定要用 SSH 进行 Clone并且配置你的 SSH key

我们上传完毕 用同步获取最新的 Log 信息。

获取 Log 的地址 http://ip 地址:端口/job/项目名称/ Build 号/api/json?pretty=true

如果项目名称有中文一定要 URL Encode

我们把当前打包的 APP 下面信息 存放在 类里面用于保存

我们可以利用 ModelJson存在本地 每次重新生成安装界面从本地读取之后生成安装的 Html存在到我们 MAMP的主目录即可。

sleep 60 #休眠60秒等待 APP 执行完毕 让 Jenkins强行的休眠60秒是等待我们的软件执行完毕。

之前没注意 发现我们的软件没走完就停止了。

可能大家看完听得云里雾里,不止所云。我之后有时间把自动化上传软件再次写一遍 开源,这样大家就可以部署一下。

说一下这样部署的优点吧。

我们现在 Fastlane在自己电脑,导致每次打包都会很卡。希望公司贡献一台测试机出来就好了。