Fastlane + Jenkins 搭建简单的 iOS 持续集成平台

背景 对于一个产品,肯定有打包测试的需求。如果每次打包,都需要通过原始的 Xcode + Archive 方式(或者脚本打包)的话特别麻烦,需要打包的人有 Mac 系统和 Xcode,还需要拉代码,打包的时候还需要 Build 号加 1,成本非常高。构建一个这样的持续平台,每个人只要能连上 Jenkins,都能打包,非常方便。

搭建环境

  • Xcode 10.2.1
  • MacOS 10.14.5
  • JDK 1.8
  • cocoapods 1.7.3
  • ruby 2.6.3
  • Homebrew 2.1.6
  • Fastlane 2.126.2
  • Jenkins 2.183

Fastlane 部分

安装 Fastlane

如果 ruby 版本满足要求(这里就不介绍 ruby 安装了,网上资料很多),可以直接在命令行执行以下命令安装 Fastlane

bash 复制代码
复制代码
#安装fastlane
sudo gem install -n /usr/local/bin fastlane

初始化项目

使用 Fastlane 初始化你要集成的项目

bash 复制代码
复制代码
cd 项目目录
bundle exec fastlane init

之后会让选 打包的目的,有 4 种,可以参见下面的代码

  1. 📸 Automate screenshots :自动截屏。这个功能能帮我们自动截取APP中的截图,并添加手机边框(如果需要的话)
  2. 👩‍✈️ Automate beta distribution to TestFlight :自动发布beta版本用于TestFlight
  3. 🚀 Automate App Store distribution :自动发布到AppStore
  4. 🛠 Manual setup - manually setup your project to automate your tasks :手动管理设置
markdown 复制代码
复制代码
xxx:xxxxx xxx$ bundle exec fastlane init
[✔] 🚀 
[✔] Looking for iOS and Android projects in current directory...
[13:33:35]: Created new folder './fastlane'.
[13:33:35]: Detected an iOS/macOS project in the current directory: 'G100.xcworkspace'
[13:33:35]: -----------------------------
[13:33:35]: --- Welcome to fastlane 🚀 ---
[13:33:35]: -----------------------------
[13:33:35]: fastlane can help you with all kinds of automation for your mobile app
[13:33:35]: We recommend automating one task first, and then gradually automating more over time
[13:33:35]: What would you like to use fastlane for?
1. 📸  Automate screenshots
2. 👩‍✈️  Automate beta distribution to TestFlight
3. 🚀  Automate App Store distribution
4. 🛠  Manual setup - manually setup your project to automate your tasks
?

这里我选的 2 ,因为我们现在主要还是用 TestFlight 包来测试。 选完后,会需要输入 AppleID 和 密码等信息,在问了你的 Apple ID,Team 的问题之后,Fastlane 会自动检测当前目录下项目的 App Name 和 App Identifier。会将信息自动保存中 Fastlane 目录下的 AppFile 文件中

这里要注意 ,这里的 AppleID 必须是苹果开发者账号,普通账号是不行的。 我还遇到了一个bug,我账号本身是苹果开发者账号(但是已经过期了),同时也在另一个开发者账号 Team 下,在输入我的账号过程中,虽然中途是出现了选择 Team,但是选完之后,还是报错,说我的账号不在真正的开发者账号的 Team 下。

在项目初始化结束后,会生成一个 fastlane文件夹,类似下面这样

复制代码
fastlane
├── Appfile
├── Fastfile

其中: Appfile 主要存储 App 相关的一些信息,比如AppleID,bundleId等。 Fastfile 就是我们要写打包代码的地方了

开始写打包脚本了

我们先来看看 Fastfile 里面长什么样

php 复制代码
复制代码
default_platform(:ios)

platform :ios do
  # 切到 develop 分支
  sh 'git checkout develop'
  # 代码
  git_pull
  # build 号加1
  increment_build_number_in_plist(
    target: "xxx"
  )
  # 下面是拿到新的版本号,提交代码
  build_number = get_build_number_from_plist(target: "xxx")
  git_commit(path:".", message:"Bump build to #{build_number}")
  sh 'git push origin develop'
  
  # pod install
  cocoapods(repo_update: false)

  # 打包上传到 TestFlight
  lane :tf do
    desc "Push a new beta build to TestFlight"
    build_app(
      workspace: "xxx.xcworkspace", 
      scheme: "xxx"
    )
    # 上传到 TestFlight,这里是上传完成就结束了,不等到到苹果那边处理完
    upload_to_testflight(skip_waiting_for_build_processing: true)
  end

  # 打测到包到第三方平台,这里是走的蒲公英
  lane :adhoc do
    desc "Push a new beta build to pgyer"
    # 这里是打的 Debug 版本
    build_app(
      workspace: "xxx.xcworkspace", 
      configuration: "Debug", 
      scheme: "xxx", 
      export_method: "development"
    )
    # 上传版本到蒲公英平台
    pgyer(
      api_key: "xxxxx", 
      user_key: "xxxxx"
    )
  end
end

从 Fastfile 中可以看到,里面有两个 lane,每个 lane 都可以独立执行,就拿上面的代码来说。 如果要上传到 TestFlight,执行bundle exec fastlane rf 就可以了 如果要上传到蒲公英平台,执行bundle exec fastlane adhoc 就可以了

注意

  • 以上代码,用到了 Fastlane 的插件,一个是 Build 号加 1(Fastlane 本身 Build 号加 1 的功能针对多个 Target(如果项目有 Test 的话,就是多 Target 了)有些问题),一个是上传蒲公英平台
  • 修改版本号插件 fastlane-plugin-versioning
  • 蒲公英插件 pgyer
  • 插件安装方法:先切换到工程目录,执行bundle exec fastlane add_plugin pgyer即可

针对于上传 TestFlight 双重认证问题 如果 AppleID 开启了双重认证,那自动上传 TestFlight 就会有问题了,因为执行脚本过程中,会出现如下提示,要求手动确认并 输入 6 位 code,怎么办呢?

less 复制代码
复制代码
Login to App Store Connect (xxx@email.com)
Two-factor Authentication (6 digits code) is enabled for account 'xxx@email.com'
More information about Two-factor Authentication: https://support.apple.com/en-us/HT204915

If you're running this in a non-interactive session (e.g. server or CI)
check out [https://github.com/fastlane/fastlane/tree/master/spaceship#2-step-verification](https://github.com/fastlane/fastlane/tree/master/spaceship#2-step-verification)

(Input `sms` to escape this prompt and select a trusted phone number to send the code as a text message)

(You can also set the environment variable `SPACESHIP_2FA_SMS_DEFAULT_PHONE_NUMBER` to automate this)
(Read more at: [https://github.com/fastlane/fastlane/blob/master/spaceship/docs/Authentication.md#auto-select-sms-via-spaceship-2fa-sms-default-phone-number](https://github.com/fastlane/fastlane/blob/master/spaceship/docs/Authentication.md#auto-select-sms-via-spaceship-2fa-sms-default-phone-number))

Please enter the 6 digit code:

Fastlane提供的两步验证解决方案:

1.访问 appleid.apple.com/account/man... 2.生成一个 APP-SPECIFIC PASSWORDS,保留生成的特殊密码

3.使用环境变量提供这个密码给fastlane:FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD 4.执行bundle exec fastlane spaceauth -u user@email.com,生成 session cookie。(过程中会提示输入输入 6 位 code,之后就会生成 session 了) 5.通过环境变量 FASTLANE_SESSION 提供 session cookies。

环境变量设置方法: 可以在 Fastfile 中设置,可以在 before_all 里面做这个事情,这个代码会在我们的 lane 之前执行,代码如下

arduino 复制代码
复制代码
before_all do
    ENV["FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD"] = "生成的特殊密码"
    ENV["FASTLANE_SESSION"] = '生成的session cookie'
  end

最终 Fastfile 是这样的

php 复制代码
复制代码
default_platform(:ios)

platform :ios do
  before_all do
    ENV["FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD"] = "生成的特殊密码"
    ENV["FASTLANE_SESSION"] = '生成的session cookie'
  end
  
  # 切到 develop 分支
  sh 'git checkout develop'
  # 代码
  git_pull
  # build 号加1
  increment_build_number_in_plist(
    target: "xxx"
  )
  # 下面是拿到新的版本号,提交代码
  build_number = get_build_number_from_plist(target: "xxx")
  git_commit(path:".", message:"Bump build to #{build_number}")
  sh 'git push origin develop'
  
  # pod install
  cocoapods(repo_update: false)

  # 打包上传到 TestFlight
  lane :tf do
    desc "Push a new beta build to TestFlight"
    build_app(
      workspace: "xxx.xcworkspace", 
      scheme: "xxx"
    )![生成的特殊密码.png](https://upload-images.jianshu.io/upload_images/809937-0e3004d8ab15f6de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    # 上传到 TestFlight,这里是上传完成就结束了,不等到到苹果那边处理完
    upload_to_testflight(skip_waiting_for_build_processing: true)
  end

  # 打测到包到第三方平台,这里是走的蒲公英
  lane :adhoc do
    desc "Push a new beta build to pgyer"
    # 这里是打的 Debug 版本
    build_app(
      workspace: "xxx.xcworkspace", 
      configuration: "Debug", 
      scheme: "xxx", 
      export_method: "development"
    )
    # 上传版本到蒲公英平台
    pgyer(
      api_key: "xxxxx", 
      user_key: "xxxxx"
    )
  end
end

Jenkins 部分

安装 Jenkins

首先要安装 homebrew,怎么安装这里就不说明了 直接命令安装 Jenkins

复制代码
brew install jenkins
ruby 复制代码
运行Jenkins
$ jenkins

###配置 jenkins 管理员账号和密码 打开浏览器,进入 http://localhost:8080/ 如果没有效果,看下shell 中Jenkins 的日志,日志还是较为详细的 根据网站提示,会让创建账号,进行简单的配置,根据提示来就行了,还是比较简单的 配置完毕在jenkins工作目录 /Users/XXXX/.jenkins 下 config.xml 文件会记录登录账户的信息

刚开始Jenkins会让输入一个密码我们cd到红色字体的路径下面打开文件就能看到密码了

###安装 Jenkins 插件 在配置过程中,也会让选,是安装推荐的插件,还是自己来安装插件,我是先安装了推荐的插件,然后再加了一些自己需要的插件

点击 Manage Jenkins -> Manage Plugins, 之后可以看到已经安装过的插件,也可以搜索自己需要的插件进行安装,还是很方便的

我这边 Cocoapods 和 Build,都是走的 Fastlane,所以这里可以不用安装 Cocoapods 和 Xcode 的插件。 我这里安装的插件有(其他的应该大部分都是默认安装的): Git plugin GitLab Plugin JDK Tool Plugin Environment Injector Plugin Localization: Chinese (Simplified)

下面是安装界面

等待进度条走完之后,页面会自动跳转(如果没有跳转手动刷新下界面就行了)

然后进入设置管理员账号密码的界面

Jenkins 首页长这个样子:

配置 Jenkins

1.安装插件
Keychains and Provisioning Profiles Management(管理本地的keychain和iOS证书的插件)

点击管理Jenkins -> 管理插件

在可选插件中搜索 Keychains and Provisioning Profiles Management 勾选安装(ps: 因为我已经安装过了,所以我的在已安装一栏中)

2.配置Keychains and Provisioning Profiles Management

在Manage Jenkins 中点击 Keychains and Provisioning Profiles Management

点击:选取文件->Upload->保存

依次将Jenkins所在的机器的login.keychain(/Users/管理员用户名/Library/keychains/login.keychain-db 复制一份改名成成login.keychain)上传保存

选择上传Profiles 文件

3.文件路径 /Users/apple/Library/MobileDevice/Provisioning Profiles/

这个一定要选对,如果选择错误,在打包的时候就会报签名有问题如果实在不知道是哪一个,可以先全都删除

然后在Xcode里面重新下载

选择你的配置文件

然后文件夹下面那个你添加的配置文件就是你需要选择的

选择完成后 保存就行了

创建 Job

见图

(1)接下来看自己需求,是否保留旧的构建、保持构建的天数和保持构建的最大个数(可以按自己的需要去选择填写)

(2)配置源码管理

SSH 验证方式: 因为我们公司是企业github所以用https 账号密码登录会报错,我这里选择使用SSH验证

复制项目链接(SSH链接)到 Repository URL

在 Credentials 点击添加,选择 SSH Username with private key

在红色框里添加你的SSH私钥(是私钥,不是公钥),因为公钥你是添加到github上了,只有私钥才有权限访问你的github

用户名密码方式

复制项目链接(HTTS链接)到 Repository URL

在 Credentials 点击添加,选择 Username with password

然后填写你的github的用户名和密码,点击添加就可以了

在指定分支填写你的分支名(这个我设置了,但是打包的时候还是会根据当前分支去打,可能是用fastlane执行打包命令的原因)填写源码库浏览器和项目URL

(3)构建触发器 也就是自动打包时间间隔

我这里选择的 Poll SCM 然后在日程表中添加时间间隔

我这里填写的是H 20 * * 这个意思就是H小时然后,后面跟着数字,在后面就是日月年, 代表的我认为是每次都触发,也就是每天每月每年,但是Jenkins的时间不是绝对的,一般都是在随机在半点,也就是设置20点,大概会在20:30分左右会触发,如果需要两个时间,那么格式可以这样H 20,22 * * *

(4)构建环境

选择 Keychains and Code Signing Identities

下面自动填充了,不用管

然后选择 Mobile Provisoning Profiles 红色框里选择刚才在配置 Keychains and Provisioning Profiles Management 中添加的配置文件

(5)构建

然后配置timeout minutes(构建超时时间)这个一定要写大一些,我原先是默认的3分钟,一直提示超时,打包比较慢的话配置的时间短会报超时

这些都完成之后我们就要写构建脚本了,我们选择 Execute shell 脚本

创建好后,就可以构建版本了

以上图就是整个 Jenkins 创建流程了,但是执行过程中会遇到一些问题

配置Jenkins 脚本

打开刚才的Jenkins配置页面

解释下下面的命令的意思

cd 到ios项目的根目录

然后执行fastlane 命令

development_build和fastfire文件中的 lane :development_build 名字要保持相同

然后保存

Jenkins 遇到的问题

  1. 构建过程中,会出现无法切换分支问题(比如执行sh 'git checkout develop'),因为 Jeknins 是会把版本切到最新的 commit, 而不是 branch, 当前显示的分支名会是 HEAD。这种情况下,fastlane 执行一下命令会出错
php 复制代码
复制代码
  sh 'git checkout develop':
  git_pull
  increment_build_number_in_plist(target: "xxx")
  build_number = get_build_number_from_plist(target: "xxx")
  git_commit(path:".", message:"Bump build to #{build_number}")
  sh 'git push origin develop'

解决方案: 直接 checkout 远端分支来修改处理,代码如下

php 复制代码
复制代码
  sh 'git checkout origin:develop'
  git_pull
  increment_build_number_in_plist(target: "xxx")
  build_number = get_build_number_from_plist(target: "xxx")
  git_commit(path:".", message:"Bump build to #{build_number}")
  sh 'git push origin HEAD:develop'
  1. 局域网无法访问 Jenkins, 配置还好后会发现,局域网其他电脑不能通过该机器的 IP 来打开 Jenkins, 如 http://192.168.31.129:8080/ 解决方案: 在 Jenkins 首页,点 Manage Jenkins,选择 Configure System

外网访问 Jenkins

有的时候,可能希望通过外网直接访问 Jenkins (这样不太安全,不建议) 这里可以使用 ngrok (这里只是用的是免费版本), 安装部署很方便,下载安装后,直接执行

bash 复制代码
复制代码
./ngrok http 8080

之后会生成外网地址,直接用这个地方访问 Jenkins 就可以了,如下

相关推荐
知行行行10 小时前
手把手教学系列之R语言绘图——饼图
数据可视化
sre运维14 小时前
运维人员必备的 Mac Zsh 配置技巧
程序员
FreedomLeo120 小时前
Python数据分析NumPy和pandas(二十九、其他Python可视化工具)
python·数据分析·数据可视化·numpy和pandas
B站计算机毕业设计超人21 小时前
计算机毕业设计Python+图神经网络考研院校推荐系统 考研分数线预测 考研推荐系统 考研爬虫 考研大数据 Hadoop 大数据毕设 机器学习 深度学习
爬虫·python·深度学习·机器学习·知识图谱·数据可视化·推荐算法
希艾席蒂恩1 天前
选择适合你的报表工具,山海鲸报表与Tableau深度对比
信息可视化·数据挖掘·数据分析·数据可视化·报表工具·免费软件
qingyunliushuiyu1 天前
智能数据分析系统-助力企业迈向数字化转型时代
数据分析·数据可视化·数据分析系统·智能数据分析系统·bi数据分析系统
陈随易1 天前
anime,超强JS动画库和它的盈利模式
前端·后端·程序员
RestCloud1 天前
ETLCloud支持的数据处理类型包括哪些?
数据库·数据分析·数据可视化
阡之尘埃2 天前
Python数据分析案例64——杭帮菜美食探索数据分析可视化
python·数据挖掘·数据分析·pandas·数据可视化·美食·杭帮菜
陈随易2 天前
秦少卫-耗时5个月收入超过北京工资的超级独立开发者
前端·后端·程序员