写点什么

Fastlane 实战(五):高级用法

2016 年 12 月 15 日

经过前 4 篇文章的基础知识和不同的场景介绍后,相信大家已经对 Fastlane 有了一个较为完整的认识,同样,今天我还是结合几个实际的场景,来讲讲 Fastlane 的一些高级用法。

前言

软件开发就像是完成一件艺术品一样,是一个循序渐进,不断打磨的过程。刚开始的时候由于我们对某个语言或框架了解的不够充分,所以往往只停留在实现功能的阶段,而不会过多的考虑到是否能够有更好的特性和更高效的方法来解决问题。

随着编程经验的积累和对语言框架的日益了解,发现之前写过的很多代码其实都存在不少问题,都有不少优化和提升的空间,于是出于责任心和对编程的热爱,我们一定会花时间不断的重构和优化代码,直到自己满意为止。

使用 Fastlane 的过程也同样如此,在第一次发现了这样一个新工具时,心中莫名的兴奋,于是不管三七二十一,立刻就动手使用了,然后随着使用的场景增多,问题也逐渐凸显了出来,于是我们开始探寻 Fastlane 的一些高级用法,以便更高效,更优雅的解决问题。

前置和后置 Action

一般情况,我们在处理 iOS 的自动化流程时,会面临着单元测试,库编译发布,APP 打包等等多种不同的场景,而 APP 打包又需要区分不同的环境,比如:Test,Adhoc 和 AppStore,而这些场景和环境的处理方式是有所不同的,所以针对每种情况,我们都需要编写对应的 Lane,比如我们新建一个名叫ios_fastfile的文件,内容如下:

复制代码
# 单元测试的 Lane
lane :test do |options|
git_pull
cocoapods
xctest
end
# AdHoc 环境打包的 Lane
lane :adhoc do |options|
git_pull
cocoapods
increment_build_number
gym
upload_to_fir
end
# AppStore 环境打包的 Lane
lane :appstore do |options|
git_pull
cocoapods
increment_build_number
gym
deliver
end

当然以上的这个些 Lane 都是简写,只是个示意,实际情况会复杂的多。从这些 Lane 中我们可以看到,每个流程其实都有前置的条件:

  1. git pull 最新的代码
  2. 更新最新的 cocoapods 依赖

所以,大家肯定会问,是否有类似 Ruby on Rails 中 controller 的前置过滤器之类的机制,能够方便的处理这个情况。答案是肯定的,类似这样,在一个 Fastfile 中,每个 Lane 共有的前置流程的情况,我们可以借助 Fastlane 提供的 before_all 方法来处理,在ios_fastfile中我们增加如下的代码:

复制代码
before_all do |lane, options|
git_pull
cocoapods
end

before_all 顾名思义,就是在在执行每个方法之前首先执行的代码,使用 before_all 我们可以将ios_fastfile的代码就可以简化为:

复制代码
before_all do |lane, options|
git_pull
cocoapods
end
# 单元测试的 Lane
lane :test do |options|
xctest
end
# AdHoc 环境打包的 Lane
lane :adhoc do |options|
increment_build_number
gym
upload_to_fir
end
# AppStore 环境打包的 Lane
lane :appstore do |options|
increment_build_number
gym
deliver
end

嗯,看上去代码简化不少,而且以后要添加公用的前置代码,都可以放在 before_all 中进行处理,维护起来非常方便。

另外,Lane 本身和使用到的 Options 参数们也可以很方便的传递给 before_all 方法,这样可以更加方便的处理各种特殊情况,比如:有的 Lane 没有处理 git_pull 的流程,那么我们只需要在方法中加一个判断即可。

当然,除了 before_all 之外,Fastlane 还提供 after_all 来处理共有的后置逻辑,比如:我们在所有的 lane 之后,要通过 Slack 或 Hipchat 通知到相关的工程师们,那么我们就可以把这些 action 写在 after_all 方法中。

复制代码
after_all do |lane,options|
slack(message: "fastlane was successful", success: true)
end

对于每个 Lane 在执行过程中,如果遇到错误,我们也需要通过 Slack 或 Hipchat 等工具通知到大家,此时,我们可以在 Fastfile 中添加一个全局的 error 方法:

复制代码
error do |lane, exception|
slack(message: exception.message, success: false)
end

引用机制

当一项新的技术在团队内部引入的时候,往往会从一个非主业务的项目中进行灰度尝试。我们也不例外,所以我们首先将 Fastlane 引入到我们的医生版的 iOS 客户端中,使用一段时间感觉不错之后,就推广到了 Android 平台和用户版客户端中,最后引入到各种私有库项目的管理中。目前大约涉及到了 30 多个项目,在这个过程中,我们发现了两个问题:

  1. 由于我们自定义了很多 action,那么这些 action 都需要拷贝到各个项目的 fastlane 目录中,这样就导致了一个维护的问题,即:添加或修改任意的自定义 action,都需要去各个项目中处理一遍。
  2. 我们目前的项目按类型分为 4 种:iOS App,iOS Pod 库,Android App,Android AAR 库,对于同样的项目类型,lane 的处理流程基本上是一样的,所以每个相同类型的项目的 Fastfile 基本上都是一致的,这就带来了和 1 一样的问题:如果要修改任意一个项目的 Fastfile,那么就意味着同样也得修改其它同类型项目中 Fastfile,因为这些 Fastfile 都是放在各自项目目录下的 fastlane 文件夹中的。

刚开始项目比较少的时候,手工还可以处理,当项目逐渐增多的时候,问题就愈发严重了,不但要改的地方多,而且还容易出错,于是我们思考是否有能够由一种引用的机制存在,能够在顶层维护一份公用的 action 和 fastfile,这样在项目中只需要引入这些顶层的文件们就能解决上面的问题。

经过仔细研究 Fastlane 的特性之后,我们发现这个问题早就在其作者的考虑之中了。Fastlane 不但提供了引用机制 import,还提供了远程引用模式,即:import_from_git。

有了这个机制之后,我们不但可以在将自定义 action 们和 Fastfile 们统一管理,而且还可以放在 git 上进行远程分布式管理,其带来的好处就是:各个项目只需要在自己的 Fastfile 的顶部进行引用声明即可:

复制代码
# 远程 Git 引用:
import_from_git(url: 'https://github.com/GengmeiRD/Fastfiles', branch: 'master')
lane :appstore do |options|
# ...
end
{1}

这样,每次执行 fastlane 的命令时,首先会从 git 上将需要的文件 clone 这个项目到本地的临时文件夹中,然后再执行相关命令。当然,如果某个项目中,你不想使用远端上的某个 lane,而是需要自定义一份,那么只需要在项目中的 Fastfile 中复写这个 lane 即可:

复制代码
# 远程 Git 引用:
import_from_git(url: 'https://github.com/GengmeiRD/Fastfiles', branch: 'master')
# 复写发布项目的 lane
lane :do_deliver_app do |options|
# ...
end

当然,如果你觉得远程管理这些 action 和 fastfile 们比较麻烦的话,同样可以使用本地引用进行管理,fastlane 提供了两个命令,分别用来引入本地的 Fastfile 和 action 目录:

复制代码
import "../GeneralFastfile"
actions_path '../custom_actions_folder/'
lane :appstore do |options|
# ...
end

我们将团队内部使用到的远程 action 和 Fastfile 管理已经发布到了 github 上,有兴趣的同学可以参考:
https://github.com/GengmeiRD/Fastfiles

上下文常量

在使用 Fastlane 的过程中,我们往往需要一些和上下文相关的常量,比如:AppStore 的账号和密码,ipa 和 dsym 文件的输出的地址,模拟器或设备的 UDID 等等。这些常量如果直接写死在 Fastfile 中显然是不利于维护的。所以我们可以考虑使用以下的方式来处理:

使用 dotenv

首先使用 gem 安装 dotenv ,然后新增一个.env 文件,然后将所有用到的常量定义在里面,比如:

复制代码
WORKSPACE=YourApp.xcworkspace
ITUNESCONNECT_ACCOUNT=your-itunesconnect-account

然后在 fastfile 中使用 ENV 进行调用:

复制代码
lane :appstore do |options|
increment_build_number
gym(workspace: ENV['WORKSPACE'])
deliver(username: ENV['ITUNESCONNECT_ACCOUNT'],)
end

最后将这个.env 文件拷贝到和 Fastfile 的同级目录即可。当然如果有常量需要在多个项目中公用的话(比如:iTunesConnect 的账号),可以建立一个软连接指向同一个.env 文件,然后在目录中创建一个.env.default 文件,放置本项目下专属的常量。

使用 export 命令

如果你使用的是 Mac 或 linux 操作系统,可以在系统的环境的变量中使用 export 命令直接定义系统级别的常量,当然为了不和其它常量冲突,建议增加一个 FASTLANE 前缀,比如:

复制代码
#set env vars
export FASTLANE_WORKSPACE="<YourApp.xcworkspace>"
export FASTLANE_ITUNESCONNECT_ACCOUNT="<your-itunesconnect-account>"

调用方法和使用.env 一样。

复制代码
lane :appstore do |options|
increment_build_number
gym(workspace: ENV['FASTLANE_WORKSPACE'])
deliver(username: ENV['FASTLANE_ITUNESCONNECT_ACCOUNT'],)
end

结语

以上的几个高级用法只是笔者在使用过程中遇到的一隅,更多的惊喜还等待大家自己去探索去发现,官方文档中有全面的介绍: https://docs.fastlane.tools/advanced/

Fastlane 是一个持续维护,快速发展的工具,从笔者的第一篇文章到现在,短短两个月的时间,Fastlane 已经发布了 20 多个版本,在 Github 上新增了 2000 多个 star,同时又多了 100 多位工程师加入到了 Contributors 的大家庭中。事实再次证明优秀的开源项目总能得到大家的认可,关注和参与。

本文是 Fastlane 实战系列的第五篇文章也是最后一篇,希望这个系列的文章能够真正帮助大家了解 Fastlane,也希望看完这个系列的文章后,有更多的同学借助 Fastlane 和各种自动化工具来提升自己的效率,毕竟重复性的劳动和流程化的工作就交给机器们去做吧。

最后祝大家使用 Fastlane 愉快。


感谢徐川对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016 年 12 月 15 日 16:214522

评论 1 条评论

发布
用户头像
您好,有个问题想要请教一下,不知道您能否看到。我在Linux机器上使用fastlane match ,出现错误:/var/lib/gems/2.3.0/gems/fastlane-2.131.0/fastlane_core/lib/fastlane_core/ui/interface.rb:141:in `user_error!': [!] Could not locate the provided keychain. Tried: (FastlaneCore::Interface::FastlaneError)
/root/Library/Keychains/login-db
/root/Library/Keychains/login.keychain-db
/root/Library/Keychains/login
/root/Library/Keychains/login.keychain
/home/www/login-db
/home/www/login.keychain-db
/home/www/login
/home/www/login.keychain
这个问题该如何解决,不胜感激
展开
2019 年 09 月 18 日 18:25
回复
没有更多了
发现更多内容

面试被问:JDBC底层是如何连接数据库的?

田维常

JDBC

区块链发展的3个必经阶段究竟是什么

CECBC区块链专委会

去中心化

四年Java开发,面试核心知识点(腾讯+阿里+快手面经)附答案

Java成神之路

Java 程序员 架构 面试 编程语言

大厂offer直通车:并发编程28题+JVM21题+Redis 16题+Java集合22题

Java架构之路

Java 程序员 架构 面试 编程语言

第十周学习总结

晴空万里

极客大学架构师训练营

【mybatis-plus】什么是乐观锁?如何实现“乐观锁”

Java架构师迁哥

北漂七年Java开发的一路辛酸史:面试腾讯、阿里、美团、字节后的一点心得

Java架构之路

Java 程序员 架构 面试 编程语言

注册中心Eureka源码解析

李浩宇/Alex

久等了,Rancher 2.5中文文档新鲜出炉

RancherLabs

容器 k8s

一个月吃透这份阿里高级专家的《Java500道面试手册》成功拿下了腾讯offer!

Java架构之路

Java 程序员 架构 面试 编程语言

微服务网关的技术架构

积极&丧

分布式缓存架构设计和一致性HASH

我们新四军不拿群众一针一线

科技抗疫,少年可期,为这群有AI的天使开发者疯狂打call

华为云开发者社区

人工智能 华为云 modelarts 医疗AI 对象存储服务OBS

职责链模式

soolaugust

设计模式 七日更 职责链模式

京东技术解密

田维常

京东

亚马逊 CTO 预测 2021 将改变世界的八大技术趋势:云加速向边缘推进

亚马逊云科技 (Amazon Web Services)

云计算 AWS

2021年阿里、腾讯、百度、华为、京东、美团和滴滴最新Java面试题汇集!

Java架构之路

Java 程序员 架构 面试 编程语言

华为大佬亲自手码Dubbo服务暴露源码解析!这次够清楚了吧

比伯

Java 编程 架构 程序人生 计算机

谷歌大佬回国发展,吊打各大厂面试官!吐血总结大厂面试高频点及笔记解析

Java成神之路

Java 程序员 架构 面试 编程语言

金融知识图谱的构建与应用

DataFunTalk

AI 知识图谱

史上最全1000道Java高频面试题:集合、IO流、多线程、网络、算法、Git、设计模式、springboot

Java架构之路

Java 程序员 架构 面试 编程语言

TypeScript | 第六章:理解声明合并,以及编写声明文件

梁龙先森

typescript 前端 七日更

Spring源码高级笔记之——Spring AOP应用

Java架构师迁哥

第五周命题作业

cc

Presto入门

HQ数字卡

presto 七日更

星环科技作为信通院隐私计算联盟成员亮相2020数据资产管理大会

星环科技

大数据

第五周学习心得

cc

浅谈优秀工程师的成长因素

数据社

程序员 七日更

如何使用数据仓库?

数据社

数据仓库 七日更

工作1-3年的Java工程师们,如何变得更值钱?,这2个点帮你8个月达到阿里P7水平

Java成神之路

Java 程序员 架构 面试 编程语言

第十周课后练习

晴空万里

极客大学架构师训练营

技术为帆,纵横四海- Lazada技术东南亚探索和成长之旅

技术为帆,纵横四海- Lazada技术东南亚探索和成长之旅

Fastlane实战(五):高级用法-InfoQ