【AICon】硅谷视野+中国实践,汇聚全球顶尖技术的 AI 科技盛会 >>> 了解详情
写点什么

构建 iOS 持续集成平台(一)——自动化构建和依赖管理

  • 2013-09-10
  • 本文字数:4291 字

    阅读完需:约 14 分钟

2000 年 Matin Fowler 发表文章 Continuous Integration【1】;2007 年,Paul Duvall, Steve Matyas 和 Andrew Glover 合著的《Continuous Integration:Improving Software Quality and Reducing Risk》 【2】出版发行,该书获得了 2008 年的图灵大奖。持续集成理念经过 10 多年的发展,已经成为了业界的标准。在 Java, Ruby 的世界已经诞生了非常成熟的持续集成工具和实践,而对于 iOS 领域来说,因为技术本身相对比较年轻和苹果与生俱来的封闭思想,在持续集成方面的发展相对滞后一些,但是,随着越来越多的 iOS 开发者的涌入,以及各个互联网巨头加大对 iOS 开发的投入,诞生了一大批非常好用的持续集成工具和服务,本文的目的就是介绍一下如何有效的利用这些类库,服务快速构建一个 iOS 开发环境下的持续集成平台。

自动化构建

在 MartinFowler 的文章 [1] 中关于自动化的构建定义如下:

复制代码
Anyone should be able to bring in a virgin machine, check the sources
out of the repository, issue a single command, and have a running
system on their machine.

因此,自动化构建的的首要前提是有一个支持自动化构建的命令行工具,可以让开发人员可以通过一个简单的命令运行当前项目。

命令行工具

自动化构建的命令行工具比持续集成的概念要诞生得早很多,几十年前,Unix 世界就已经有了 Make,而 Java 世界有 Ant,Maven,以及当前最流行的 Gradle,.Net 世界则有 Nant 和 MSBuild。作为以 GUI 和命令行操作结合的完美性著称的苹果公司来说,当然也不会忘记为自己的封闭的 iOS 系统提供开发环境下命令行编译工具:xcodebuild【3】

xcodebuild

在介绍 xcodebuild 之前,需要先弄清楚一些在 XCode 环境下的一些概念【4】:

  • Workspace:简单来说,Workspace 就是一个容器,在该容器中可以存放多个你创建的 Xcode Project, 以及其他的项目中需要使用到的文件。使用 Workspace 的好处有,1), 扩展项目的可视域,即可以在多个项目之间跳转,重构,一个项目可以使用另一个项目的输出。Workspace 会负责各个 Project 之间提供各种相互依赖的关系 ;2), 多个项目之间共享 Build 目录。
  • Project:指一个项目,该项目会负责管理生成一个或者多个软件产品的全部文件和配置,一个 Project 可以包含多个 Target。
  • Target:一个 Target 是指在一个 Project 中构建的一个产品,它包含了构建该产品的所有文件,以及如何构建该产品的配置。
  • Scheme:一个定义好构建过程的 Target 成为一个 Scheme。可在 Scheme 中定义的 Target 的构建过程有:Build/Run/Test/Profile/Analyze/Archive
  • BuildSetting:配置产品的 Build 设置,比方说,使用哪个 Architectures?使用哪个版本的 SDK?。在 Xcode Project 中,有 Project 级别的 Build Setting,也有 Target 级别的 Build Setting。Build 一个产品时一定是针对某个 Target 的,因此,XCode 中总是优先选择 Target 的 Build Setting,如果 Target 没有配置,则会使用 Project 的 Build Setting。

弄清楚上面的这些概念之后,xcodebuild 就很好理解了,官网上对其作用的描述如下:

复制代码
xcodebuild builds one or more targets contained in an Xcode
project, or builds a scheme contained in an Xcode workspace or
Xcode project.

xcodebuild 就是用了构建产品的命令行工具,其用法可以归结为 3 个部分:

  • 可构建的对象
  • 构建行为
  • 一些其他的辅助命令

可以构建的对象有,默认情况下会运行 project 下的第一个 target:

  • workspace:必须和“-scheme”一起使用,构建该 workspace 下的一个 scheme。
  • project:当根目录下有多个 Project 的时候,必须使用“-project”指定 project,然后会运行
  • target:构建某个 Target
  • scheme:和“-workspace”一起使用,指定构建的 scheme。
  • ……

构建行为包括:

  • clean: 清除 build 目录下的
  • build: 构建
  • test: 测试某个 scheme,必须和"-scheme"一起使用
  • archive: 打包,必须和“-scheme”一起使用
  • ……

辅助命令包括:

  • -sdk:指定构建使用的 SDK
  • -list:列出当前项目下所有的 Target 和 scheme。
  • -version:版本信息
  • ……

关于 xcodebuild 更多详细的命令行请参见: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html

下图是使用 XcodeBuild 运行一个 scheme 的 build 的结果:

了解了 xcodebuild 的用法之后,接下来分析一下 xcodebuild 的主要缺陷:

  • 从上图直接可以得到的感觉,其脚本输出的可读性极差,
  • 只能要么完整的运行一个 target 或者 scheme,要么全部不运行。不能指定运行 Target 中特定的测试。
  • 最令人发指的是,XCode 4 中的 xcodebuild 居然不支持 iOSUnitTest 的 Target【5】,当我尝试运行一个 iOS App 的测试 target 时,得到如下的错误:

对于上面提到的缺陷,Facebook 给出了他们的解决方案:xctool【6】

xctool

xctool 在 其主页直接表明了其目的:

<i>xctool is a replacement for Apple's xcodebuild that makes it easier to build and<br></br> test iOS and Mac products. It's especially helpful for continuous integration.</i>其作用是替代 xcodebuild,目的是让构建和测试更加容易,更好的支持持续集成。从个人感受来看,它的确成功取代了 xcodebuild。但是 xctool 说到底只是对 xcodebuild 的一个封装,只是提供了更加丰富的 build 指令,因此,使用 xctool 的前提是 xcodebuild 已经存在,且能正常工作。

安装

xctool 的安装非常简单,只需要 clone xctool 的 repository 到项目根目录就可以使用, 如果你的机器上安装有 Homebrew,可以通过“brew install xctool”命令直接安装。(注意:使用 xctool 前一定要首先确认 xcodebuild 已安装且能正确工作)。

用法

关于 xctool 的用法就更加人性化了,几乎可以重用所有的 xcodebuild 的指令,配置。只需要注意一下几点:

  • xctool 不支持 target 构建,只能使用 scheme 构建。
  • 支持“-only”指令运行指定的测试。
  • 支持多种格式的 build 报告。

例子:

复制代码
path/to/xctool.sh
-workspaceYourWorkspace.xcworkspace
-schemeYourScheme
test -only SomeTestTarget:SomeTestClass/testSomeMethod

下图是我使用 xctool 运行 test 的效果:

常见问题:

No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=armv7 armv7s).

解决方法:到 Project Setting 中,把"Build Active Architecture Only"设置为 NO

Code Sign error: A valid provisioning profile matching the application’s Identifier ‘dk.muncken.MyApp’ could not be found

解决方法:通过“-sdkiphonesimulator”指定 SDK,从而能够使用符合 iOS 约定的 application Identifier。

依赖管理

选定了命令行工具之后, 接下来可以考虑下依赖管理的问题了。我到现在还记得几年前,刚从 Ant 转到使用 Maven 的那种爽快的感觉。后来,进入 Ruby 的世界,其与生俱来的 Gem 管理系统,也让其依赖管理变得极其简单。 对于 iOS 平台来说,在做项目时,经常需要使用到各种各样的第三方 Framework,这同样需要一个爽快的依赖管理系统,不然的话,各位可以想象一下重复的下载 Framework 文件,拖入各个 Target 的 Build Phase 的 Link Binary With Libraries 中的场景。这种重复的劳动对于“懒惰”的程序员来说,是很难接受的,于是,活跃的社区开发者们提供了这样的一个工具:Cocoapods【7】

Cocoapods 开始于 2011 年 8 月 12 日,经过 2 年多的发展,现在已经超过 2500 次提交,并且持续保持活跃更新,目前已成为 iOS 领域最流行的第三方依赖管理工具。从技术层面来说,其是一个 Ruby Gem,从功能层面来说,其是一个 iOS 平台下的依赖管理工具,为 iOS 项目开发提供了类似于在 Ruby 世界使用 Gem 的依赖管理体验。

安装

前面提到 cocoapods 本质上是一个 Ruby Gem,因此,其使用前提首先是 Ruby 开发环境。庆幸的是,Mac 下都自带 Ruby。这样,只需要简单的 2 条命令,就可以把 cocoapods 安装好:

复制代码
$ [sudo] gem install cocoapods
$ pod setup

用法

cocoapods 的使用方式和使用 Ruby Gem 非常相似,首先需要在项目根目录下创建文件 Podfile, 在 Podfile 中,开发人员只需要按照规则配置好如下内容就好:

  • 项目支持的平台,版本(iOS/OSX)
  • 每个 target 的第三方依赖

例子:

复制代码
platform :ios, '6.0'
inhibit_all_warnings!
xcodeproj `MyProject`
pod 'ObjectiveSugar', '~> 0.5'
target :test do
pod 'OCMock', '~> 2.0.1'
end
post_install do |installer|
installer.project.targets.each do |target|
puts "#{target.name}"
end
end

修改好配置文件之后,只需要简单的使用“pod install”即可安装好所有的依赖,执行该命令之后,在项目跟目录下会出现“.xcworkspace”和“Pods”两个目录:

接下来,开发者需要使用 xcworkspace 打开项目而不是使用 xcodeproject,打开项目之后,在项目目录下除了自己的 project 以外,还可以看到一个叫做 Pods 的项目,该项目会为每一个依赖创建一个 target:

在 Podfile 中,还可以指定依赖专属于某个 Target,

复制代码
target :CocoaPodsTest do
pod 'OCMock', '~> 2.0.1'
pod 'OCHamcrest'
end

如果你记不清楚某个依赖库的名称,可以使用“pod search ”模糊搜索依赖库中的相似库, 另外,如果你想使用的库在 cocoapods 的中央库中找不到,那么,你可以考虑为开源社区做做贡献,把你觉得好用的库添加到中央库中,Cocoapods 的官网上有具体的步骤【8】

原理

CocoaPods 的原理思想基本上来自于 Jonah Williams 的博客“Using Open Source Static Libraries in Xcode 4”【9】, 当使用“pod install”安装文件时,cocoapods 做了如下这些事:

  • 创建或者更新当前的 workspace
  • 创建一个新的项目来存放静态库
  • 把静态库会编译生成的 libpods.a 文件配置到 target 的 build phase 的 link with libraries 中
  • 在依赖项目中创建 *.xcconfig 文件, 指定在编译时的一些参数和依赖
  • 添加一个新的名为“Copy Pods Resource”的 Build Phase,该 build phase 会使用"${SRCROOT}/Pods/Pods-CocoaPodsTest-resources.sh"把 Pods 下的资源文件拷贝到 app bundle 下。

注意事项

当使用 xctool 作为命令行工具构建项目时,使用 cocoapods 管理依赖时,需要做一些额外的配置:

  • 编辑 Scheme,把 pods 静态库项目作为显式的依赖添加到项目的 build 中,
  • 把 pods 依赖项目拖动到本来的项目之上,表示先编译 pods 静态库项目,再编译自己的项目。


感谢张凯峰对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2013-09-10 00:1318666

评论

发布
暂无评论
发现更多内容

week4作业

Asha

JS Array数组几个循环实用方法总结

MegaQi

JavaScrip 测试发开 web前端开发

深入浅出 Java FileChannel 的堆外内存使用

Apache IoTDB

深入垂直业务场景,SaaS版供应商业务协同管理系统促进企业与供应商高效协同

数商云

数字化转型 供应链系统

加密货币监控和区块链分析如何帮助避免加密货币欺诈?

CECBC

区块链等技术助力北京海关监管

CECBC

数字医疗时代的数据安全如何保障?

CECBC

从二十年开源经历出发,70 后大龄程序员谈成长、困境与突围

TDengine

数据库 tdengine 开源

基于微信小程序的实验室预约小程序平台详细设计

CC同学

360大数据技术专家 程建云:IoTDB在360的落地实践 | Apache IoTDB Talk

Apache IoTDB

时序数据库 IoTDB Apache IoTDB

OceanBase 开源负责人纪君祥聊 社区版 2022 Roadmap

OceanBase 数据库

oceanbase OceanBase 开源

前端食堂技术周刊第 30 期:Vercel 支持零配置部署使用 pnpm 项目、React 新文档更新、Angular Roadmap、Remix Stacks

童欧巴

JavaScript 编程 前端 周刊 资讯

高层次人才一站式服务平台系统开发

a13823115807

区块链架构下 智慧城市发展加速

CECBC

《LeetCode 刷题报告》题解内容Ⅱ

謓泽

3月月更

Rust Cell 与RefCell,有啥区别?

非凸科技

华为云GaussDB专家走进课堂,跟莘莘学子聊聊数据库

华为云数据库小助手

GaussDB GaussDB(for openGauss) GaussDB(for MySQL)

墨天轮访谈 | 华为云温云博:从客户视角出发,GaussDB(for Redis)究竟“香”在哪里?

墨天轮

数据库 redis 华为云 国产数据库 键值数据库

昇思MindSpore行至2022,开源社区成就生态共赢

这不科技

华为 昇思MindSpore

一文带你了解 Python 中的迭代器

踏雪痕

Python 3月程序媛福利 3月月更

明天直播:如何测试硬件设备与龙蜥操作系统的兼容性?

OpenAnolis小助手

硬件 直播 开源社区 sig 兼容性

Tapdata 肖贝贝:实时数据引擎系列(六)-从 PostgreSQL 实时数据集成看增量数据缓存层的必要性

tapdata

数据库 实时数据

软件定义存储厂商大道云行加入龙蜥社区

OpenAnolis小助手

生态 存储技术 龙蜥社区 大道云行 CLA

春暖花开,等你而来!4月月更挑战开始啦!

InfoQ写作社区官方

热门活动 4月月更

VuePress 博客搭建系列 33 篇正式完结!

冴羽

JavaScript Vue 前端 vuepress 博客搭建

叮咚!参与微服务免费试用,有机会获得腾讯内推资格!

InfoQ写作社区官方

腾讯云 微服务 热门活动

Facebook 开源 Golang 实体框架 Ent 现已支持 TiDB

Geek_2d6073

云时代,租电脑还是初创型企业最好的选择吗?

阿里云弹性计算

远程办公 无影云电脑 初创型企业

异构注册中心机制在中国工商银行的探索实践

SOFAStack

GitHub 开源 分布式架构 注册中心 工商银行

“中本聪岛”加密乌托邦

CECBC

如何快速实现持续交付

阿里云云效

云计算 阿里云 软件开发 CI/CD 持续交付

构建iOS持续集成平台(一)——自动化构建和依赖管理_DevOps & 平台工程_刘先宁_InfoQ精选文章