mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-16 22:23:45 +08:00
del
This commit is contained in:
156
极客时间专栏/geek/持续交付36讲/持续交付移动App/31 | 了解移动App的持续交付生命周期.md
Normal file
156
极客时间专栏/geek/持续交付36讲/持续交付移动App/31 | 了解移动App的持续交付生命周期.md
Normal file
@@ -0,0 +1,156 @@
|
||||
<audio id="audio" title="31 | 了解移动App的持续交付生命周期" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/c3/5a/c355363bd949db8ad134f99b27fd1b5a.mp3"></audio>
|
||||
|
||||
你好,我是王潇俊。今天我和你分享的主题是:了解移动App的持续交付生命周期。
|
||||
|
||||
我已经和你分享完的前30个主题里,介绍的都是偏向后端持续交付体系的内容。在服务端持续交付的基础上,我会再用两篇文章,和你聊聊移动App的持续交付。
|
||||
|
||||
与后端服务相比,移动App的出现和工程方面的发展时间都较短,所以大部分持续交付的流程和方法都借鉴了后端服务的持续交付。但是,移动App因为其自身的一些特点,比如版本更新要依赖用户更新客户端的行为等,所以移动App的持续交付也呈现了一些独有的特点。
|
||||
|
||||
同时,移动App的持续交付也存在一些痛点。比如,没有主流的分支模型,甚至产生了Android开发团队使用Gerrit这样一个独特代码管理平台和分支模型的特例;又比如,移动App的编译速度,也随着应用越来越大变得越来越慢;再比如,Apple Store审核慢、热修复困难等问题。
|
||||
|
||||
这样总体来看,移动App的持续交付体系的搭建完全可以借鉴服务端的持续交付的经验。然后,再针对移动App固有的特点,进行改进和优化。
|
||||
|
||||
因此,在这个系列我只会通过三篇文章,和你分享移动App持续交付体系的特色内容,而对于共性的内容部分,你可以再次回顾一下我在前面所分享的内容。如果你感觉哪里还不太清楚的话,就给我留言我们一起讨论解决吧。
|
||||
|
||||
作为移动App的持续交付系列的第一篇文章,我会和你一起聊聊移动App交付涉及的问题、其中哪些部分与后端服务不太一样,以及如何解决这些问题打造出一套持续交付体系。
|
||||
|
||||
## 代码及依赖管理
|
||||
|
||||
**首先,和后端服务一样,移动App的持续交付也需要先解决代码管理的问题**。
|
||||
|
||||
我在专栏的第四篇文章[《一切的源头,代码分支策略的选择》](https://time.geekbang.org/column/article/10858)中,和你分享了各种代码分支策略(比如,Git Flow、GitHub Flow 和 GitLab Flow这三种最常用的特性分支开发模型)的思路、形式,以及作用。
|
||||
|
||||
对于移动App来说,业界流行的做法是采用“分支开发,主干发布”的方式,并且采用交付快车的方式进行持续的版本发布。
|
||||
|
||||
关于这种代码管理方式,我会在下一篇文章《细谈移动App的持续交付流水线(pipline)》中进行详细介绍。
|
||||
|
||||
**其次,移动App的开发已经走向了组件化,所以也需要处理好依赖管理的问题**。
|
||||
|
||||
移动端的技术栈往往要比统一技术栈的后端服务更复杂,所以在考虑依赖管理时,我们需要多方位地为多种技术栈做好准备。比如:
|
||||
|
||||
针对 Android系统,业界通常使用Gradle处理依赖管理的问题。Gradle是一个与Maven类似的项目构建工具。与Maven相比,它最大的优点在于使用了以Groovy为基础的DSL代替了Maven基于XML实现的配置脚本,使得构建脚本更简洁和直观。
|
||||
|
||||
针对iOS系统,我们则会使用CocoaPods进行依赖管理。它可以将原先庞大的iOS项目拆分成多个子项目,并以二进制文件的形式进行库管理,从而实现对iOS的依赖管理。另外,这种管理依赖的方式,还可以提高iOS的构建速度。
|
||||
|
||||
除了以上两个技术栈外,移动App还会涉及到H5、Hybrid等静态资源的构建、发布和管理。那么同样的,我们也就需要Nexus、npm等构建和依赖管理工具的辅助。
|
||||
|
||||
可以说,移动App的技术仍旧在快速发展中,与后端服务比较成熟和统一的状态相比,我们还要花费更多的精力去适配和学习新的构建和依赖管理工具。
|
||||
|
||||
## 项目信息管理
|
||||
|
||||
项目信息管理主要包括版本信息管理和功能信息管理这两大方面。
|
||||
|
||||
**对于移动App的持续交付来说,我们特别需要维护版本的相关信息,并对每个版本进行管理**。
|
||||
|
||||
对后端服务来说,它只要做到向前兼容,就可以一直以最新版本的形式进行发布;而且,它的发布相对自主,控制权比较大。
|
||||
|
||||
但对移动App来说,情况则完全不同了:一方面,它很难保证面面俱到的向前兼容性;另一方面,它的发布控制权也没那么自主,要受到应用商店、渠道市场和用户自主更新等多方面因素的影响。
|
||||
|
||||
所以,在移动App的持续交付中,我们需要管理好每个版本的相关信息。
|
||||
|
||||
另外,为了提高移动App的构建和研发效率,我们会把整个项目拆分多个子项目,而主要的拆分依据就是功能模块。也就是说,除了从技术角度来看,移动App的持续交付会存在依赖管理的内容外,从项目角度来看,也常常会存在功能依赖和功能集成的需要。所以,**为了项目的协调和沟通,我们需要重点管理每个功能的信息。**
|
||||
|
||||
可见,做好项目信息管理在移动App的持续交付中尤为重要,而在后端服务的持续交付中却没那么受重视了,这也是移动App的持续交付体系与服务端的一大不同点。以携程或美团点评为例,它们都各自研发了MCD或MCI平台,以求更好地管理项目信息。
|
||||
|
||||
## 静态代码检查
|
||||
|
||||
静态代码检查的内容,就和后端服务比较相似了。为了提高移动端代码的质量,业界也陆续提供了不少的静态代码检查方案。比如:
|
||||
|
||||
<li>
|
||||
Clang Static Analyzer,被Xcode集成,但其缺乏代码风格的检查,可配置性也比较差;
|
||||
</li>
|
||||
<li>
|
||||
OCLint,其检查规则更多,也更易于被定制;
|
||||
</li>
|
||||
<li>
|
||||
Infer,是Facebook提供的一款静态检查工具,具有大规模代码扫描效率高、支持增量检查等特点。
|
||||
</li>
|
||||
|
||||
我们也可以很方便地把这些静态检查工具集成到移动App的持续交付当中去。基本做法,你可以参考我在第25篇文章[《代码静态检查实践》](https://time.geekbang.org/column/article/14407)最后分享的Sonar代码静态检查的实例的内容。
|
||||
|
||||
## 构建管理
|
||||
|
||||
移动App构建管理的大体流程,我们可以借鉴后端服务的做法,即:通过代码变更,触发自动的持续集成。集成过程基本遵循:拉取代码、静态检查、编译构建、自动化测试,以及打包分发的标准过程。
|
||||
|
||||
移动App和后端服务的持续交付体系,在构建管理上的不同点,主要体现在以下三个方面:
|
||||
|
||||
<li>
|
||||
**你需要准备 Android 和 iOS 两套构建环境**,而且iOS的构建环境还需要一套独立的管理方案。因为,iOS的构建环境,你不能直接使用 Linux 虚拟机处理,而是要采用Apple公司的专用设备。
|
||||
</li>
|
||||
<li>
|
||||
**在整个构建过程中,你还要考虑证书的管理**,不同的版本或使用场景需要使用不同的证书。如果证书比较多的话,还会涉及到管理的逻辑问题,很多组织都会选择自行开发证书管理服务。
|
||||
</li>
|
||||
<li>
|
||||
**为了解决组件依赖的问题,你需要特别准备独立的中央组件仓库,并用缓存等机制加快依赖组件下载的速度**。其实,这一点会和后端服务比较相像。
|
||||
</li>
|
||||
|
||||
## 发布管理
|
||||
|
||||
移动App的发布管理,和后端服务相比,相差就比较大了。
|
||||
|
||||
**首先,移动App无法做到强制更新,决定权在终端用户**。移动App的发布,你所能控制的只是将新版本发布到市场而已,而最终是否更新新版本,使得新版本的功能起效,则完全取决于用户。这与后端服务强制更新的做法完全不同。
|
||||
|
||||
**其次,移动App在正式发布到市场前,会进行时间比较长的内测或公测**。这些测试会使用类似Fabric Beta 或者 TestFlight 这样的 Beta 测试平台,使部分用户优先使用,完成灰度测试;或者在公司内部搭建一个虚拟市场,利用内部资源优先完成内测。而且,这个测试周期往往都比较长,其中也会迭代多个版本。
|
||||
|
||||
**最后,移动App的分发渠道比较多样**。还可能会利用一些特殊的渠道进行发布。为了应对不同的渠道的需求,比如标准渠道版本,控制部分内容,一些字样的显示等等。在完成基本的构建和打包之后,还需要做一些额外的配置替换、增删改查的动作。比如,更新渠道配置和说明等。
|
||||
|
||||
以上这些因素,就决定了移动App与后端服务的发布管理完全不同。关于移动App的发布,我会在下一篇文章《细谈移动App的持续交付流水线(pipeline)》中进行详细介绍。
|
||||
|
||||
## 运营管理
|
||||
|
||||
移动App发布之后,还有一件比较重要的事项,那就是对每个版本的运营管理。
|
||||
|
||||
这里讲的运营主要是指,追踪、分析和调优这个版本发布的表现和反馈。我们运营时,主要关注的内容包括:奔溃报告、区域分析、用户分析、系统资源消耗、流量消耗、响应时长、包体大小、系统监控,以及预警等。
|
||||
|
||||
通常,我们也会对比版本之间的这些运营指标,以判断应用是变好了,还是变坏了。
|
||||
|
||||
## 热修复
|
||||
|
||||
后端服务修复Bug的方式,一般是:发现Bug后,可以立刻再开发一个新版本,然后通过正常的完整发布进行修复。
|
||||
|
||||
而移动App的发布需要用户安装才能起效,这就决定了它不能采用后端服务修复Bug的方式。因为,这会要求用户在很短的时间内重新安装客户端,这样的用户体验相当糟糕。
|
||||
|
||||
但是,我们也无法避免Bug。所以,对移动App来说,我们就要通过特定的热修复技术,做到在用户不重新安装客户端的前提下,就可以修复Bug。这也就是我所说的热修复。
|
||||
|
||||
关于热修复,比如**Android系统**,主要的方式就是以下两步:
|
||||
|
||||
<li>
|
||||
下发补丁(内含修复好的class)到用户手机;
|
||||
</li>
|
||||
<li>
|
||||
App通过类加载器,调用补丁中的类。
|
||||
</li>
|
||||
|
||||
其实现原理,主要是利用了Android的类加载机制,即从DexPathList对象的Element数组中获取对应的类进行加载,而获取的方式则是遍历。也就是说,我们只需要把修复的类放置在这个Element数组的第一位就可以保证加载到新的类了,而此时有Bug的类其实还是存在的,只是不会被加载到而已。
|
||||
|
||||
当然技术发展到今天,我们已经无需重复造轮子了,完全可以利用一些大厂开放的方案和平台完成热修复。比如,百川的hHotFix、美团Robust、手机QQ空间、微信Tinker,都是很好的方案。
|
||||
|
||||
**iOS系统方面**,Apple公司一直对热修复抓的比较严。但是,从iOS7之后,iOS系统引入了JavaScriptCore,这样就可以在Objective-C和JavaScript之间传递值或对象了,从而使得创建混合对象成为了可能。因此,业界产生了一些成熟的热修复方案。比如:
|
||||
|
||||
<li>
|
||||
<p>[Rollout.io](http://Rollout.io)、JSPatch、DynamicCocoa<br />
|
||||
这三个方案,只针对iOS的热更新。目前,Rollout.io和JSPatch已经实现了平台化,脚本语言用的都是JavaScript。Rollout.io除了支持OC的热更新外,还支持Swift。<br />
|
||||
DynamiCocoa源自滴滴,目前还没开源,所以我也没怎么体验过。但是,它号称可以通过OC编码,自动转换成JavaScript脚本,这对编码来说好处多多。</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>React Native、Weex<br />
|
||||
这两个方案,都是跨平台的热更新方案。其中,React Native是由Facebook开发的, Weex是由阿里开发的。就我个人的体验来说,Weex从语法上更贴近编程思路,而且还实现了平台化,使用起来更加便捷。</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Wax 、Hybrid<br />
|
||||
这两个方案,比较特殊。其中,Wax采用的脚本语言是Lua而不是JavaScript,所以比较适用于游戏;而Hybrid主要面向H5,Hybrid App已经被证明不是好的方案,所以用户越来越少了。</p>
|
||||
</li>
|
||||
|
||||
## 总结
|
||||
|
||||
今天我主要和你分享了移动App的持续交付生命周期的几个主要部分,包括代码及依赖管理、项目信息管理、静态代码检查、构建管理、发布管理、运营管理,以及热修复。
|
||||
|
||||
然后,我分享了相比于后端服务,移动App的持续交付体系有哪些不同的地方。比如,项目信息管理、运营管理和热修复,在移动App的交付过程中被提到了更重要的位置;而其他几个主要过程,代码、构建、发布这三部分都因为移动App开发的特性与后端服务相比有所区别,这些区别也是我要在下一篇文章中和你重点分享的内容。
|
||||
|
||||
## 思考题
|
||||
|
||||
对于移动App的交付来说,版本和信息管理非常重要。你所在的公司是如何管理这些信息的,有哪些可以优化的可能吗?
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
||||
|
||||
|
||||
190
极客时间专栏/geek/持续交付36讲/持续交付移动App/32 | 细谈移动APP的交付流水线(pipeline).md
Normal file
190
极客时间专栏/geek/持续交付36讲/持续交付移动App/32 | 细谈移动APP的交付流水线(pipeline).md
Normal file
@@ -0,0 +1,190 @@
|
||||
<audio id="audio" title="32 | 细谈移动APP的交付流水线(pipeline)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/8e/f0/8e295fe1fa86813a6ccd582db6b1d0f0.mp3"></audio>
|
||||
|
||||
你好,我是王潇俊。今天我和你分享的主题是:细谈移动APP的交付流水线(pipeline)。
|
||||
|
||||
在上一篇文章[《了解移动App的持续交付生命周期》](https://time.geekbang.org/column/article/23611)中,我和你分享了移动App的整个交付生命周期,并把移动客户端的交付与后端服务的交付方式进行了对比。从中,我们发现移动App自身的特点,使得其持续交付流程与后端服务存在一定的差异。
|
||||
|
||||
所以,今天我会在上一篇文章的基础上,和你分享移动App持续交付中的个性化内容。这些个性化的内容,主要表现在流水线的三个重要环节上:
|
||||
|
||||
<li>
|
||||
采用与发布快车(Release Train)模式匹配的代码分支管理策略;
|
||||
</li>
|
||||
<li>
|
||||
支持多项目、多组件并行的全新构建通道;
|
||||
</li>
|
||||
<li>
|
||||
自动化发布,完全托管的打包、发布、分发流程。
|
||||
</li>
|
||||
|
||||
接下来,我就从这三个角度,和你详细聊聊移动App的持续交付吧。
|
||||
|
||||
## 发布快车模式
|
||||
|
||||
首先,我先和你说说什么是发布快车。
|
||||
|
||||
顾名思义,发布快车,就像一列由多节车厢组成的火车,每一节车厢代表一个发布版本,整个火车以一节节车厢或者说一个个版本的节奏,定期向前发车。而工程师们,则会把自己开发完成的功能集成到一节节的车厢上,这样集成在一节车厢的功能代码,就形成了一个新的版本。
|
||||
|
||||
如图1所示,就很好地展示了发布快车的含义。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/c8/d2/c802a0f8f0cf4e57e4854b4e227918d2.png" alt="">
|
||||
|
||||
从这张图上,我们可以看到,每个版本(也就是每节车厢)都由多个功能组成。
|
||||
|
||||
关于发布快车还有三个关键点,容易被误解或者疏忽。
|
||||
|
||||
**第一个关键点是,并不是说所有开发的功能,都一定要集成到最近的那节车厢、最近的那个版本中**。任何功能都应该按照既定计划,规划纳入到适合的那节车厢、那个版本中。这也是为什么移动端App的持续交付需要良好的信息管理的原因。
|
||||
|
||||
**第二个关键点是,我们必须要保证固定间隔的发车时间,每周、每两周都可以,但必须保证每个车厢到点即发**。只有这样,我们才能保证持续交付流水线的持续运行,以及不间断地产出。这里需要注意的是,对于一些特殊的、不规则的发布,我们要把它们归类到热修复的流程,而不是在发布快车中处理。
|
||||
|
||||
**第三个关键点是,这个过程的最终产物是可以发布到市场的版本,而不是发布到用户侧的版本**。虽然我们把这个发布模式叫作发布快车,但其实它的最终产物是可以发布的待发布版本。所以这个流程完成后的版本没有被正式发布,或出现了部分缺陷无法发布的情况是很正常的,可以被接受。我们并不需要保证每个版本都一定能发布到用户手上。
|
||||
|
||||
发布快车的发布模式,特别是以上说的三个特性,非常符合移动App对持续交付的需求,即:分散开发,定期集成,控制发布。所以绝大部分的移动App团队,都选择采用发布快车的发布方式。
|
||||
|
||||
那么,如何才能实现这个发布快车模式的真实落地呢?
|
||||
|
||||
<li>
|
||||
选择与发布快车模式匹配的代码分支策略;
|
||||
</li>
|
||||
<li>
|
||||
改造出与发布快车模式匹配的构建通道;
|
||||
</li>
|
||||
<li>
|
||||
实现发布流程的全自动化。
|
||||
</li>
|
||||
|
||||
## 选择与发布快车模式匹配的代码分支策略
|
||||
|
||||
首先,选择一套与之匹配的代码分支管理策略,否则整个发布快车的实施会非常别扭。我们先一起回顾一下专栏的第4篇文章[《一切的源头,代码分支策略的选择》](https://time.geekbang.org/column/article/10858)。
|
||||
|
||||
我在这篇文章中介绍的代码分支策略中,Gitlab Flow与 发布快车模式的思想看上去非常接近。那我们不妨推演一下,这个分支策略是否符合我们的需要。
|
||||
|
||||
首先,项目仓库的初始状态如图2所示。这里有一个版本V1,代码仓库中有2个分支:Master,是集成分支;Production,是发布分支。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ad/9c/adc587c19ca50248a589639e3439019c.png" alt="">
|
||||
|
||||
然后,以V1的commit为基准,建立功能分支1,并进行开发,如图3所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/00/24/006d004b8f4c2fa2d12451ff2de76524.png" alt="">
|
||||
|
||||
如图4所示,功能分支1开发完成后,合并入Master。测试通过之后形成版本V2,V2就可以作为待发布的产物了。另外,在形成V2之前,我们可以看到,另外一个功能分支2也被建立了,但这个功能分支并没有被合并到Master,所以不会出现在版本V2中。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/78/cb/789bece7976130a9722a0ca90acccbcb.png" alt="">
|
||||
|
||||
从图5中,我们可以看到,V2版本后,又出现了一个新的功能分支3,它与功能分支2并行开发。这两个功能分支合并入Master之后,被同时附加到版本V3中。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/df/45/dfb010fd678e02dc9065659657c6c745.png" alt="">
|
||||
|
||||
正如以上的几个步骤,如果每个版本都是定时进行构建和打包,那么这样的代码分支管理模型就是一个典型的符合发布快车的物理实现了。
|
||||
|
||||
## 全新的构建通道
|
||||
|
||||
当然,为了发布快车模式的落地,我们只是建立与之配套的代码分支管理策略还远远不够,还需要有配套的构建通道。
|
||||
|
||||
你可能会问,发布快车模式的落地,为什么还要选择特定的构建通道呢?
|
||||
|
||||
我先和你说说发布快车,以及与之配套的代码分支策略的弱点都有哪些吧。
|
||||
|
||||
如果功能分支合入Master分支的过程缺乏校验,以及必要的构建检查的话,那么Production分支在进行自动定期构建时,就很容易产生问题,而一旦产生问题,就会错过这个要定期发布的版本。
|
||||
|
||||
如果这只会影响到一个或少数几个功能的话,还好;但设想一下,如果你要发布一个大版本,由于某个小功能而影响了所有的其他功能,是不是就得不偿失了呢?
|
||||
|
||||
所以,为了高效的持续交付,我们就必须对构建通道进行一定的改造。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ae/f4/aeb7a2ab53ecb8e2a4d9ebefa63d5bf4.png" alt="">
|
||||
|
||||
如图6所示,我们会在功能分支合并入Master分支前,增加一次构建(Merge CI Service),这次构建的作用是保证功能分支的集成是成功的,否则不允许合并;同时,对于一个代码仓库来说,增加的这次构建过程要保证是串行的,即如果这个仓库正有一个合并构建在进行,则后续的合并构建需要等待。
|
||||
|
||||
这个合并构建过程,保证了Master分支上的任何commit随时都可以成功构建。之后再根据发布快车的要求定期启动版本构建(Auto CI Service),就能顺利地得到可测试版本了。
|
||||
|
||||
构建测试版本之后,流水线还可以继续处理,在production分支上打上对应的tag。
|
||||
|
||||
## 自动化的发布
|
||||
|
||||
构建通道建立之后,就是发布了。我在上一篇文章中提到,移动App的发布与后端服务有所区别。移动App的发布,需要特别注意这两点需求:
|
||||
|
||||
<li>
|
||||
通常在发布到市场之前,会先发布内部,进行针对新功能的内测;
|
||||
</li>
|
||||
<li>
|
||||
通常,为了节省调试信息带来的额外开销,内部发布会采用debug包,而正式发布则采用release包。
|
||||
</li>
|
||||
|
||||
但是,从另一方面看,相比于后端服务的发布,移动App的发布步骤固定,且逻辑相对简单。
|
||||
|
||||
- iOS系统的发布步骤为:构建,导出ipa包,记录符号表,备份,上传至iTC;
|
||||
- Android系统的发布步骤为:构建打包,更新渠道标识,签名,保存mapping文件,备份,上传至发布点。
|
||||
|
||||
理解了iOS和Android系统各自的发布步骤,我们就可以很容易地做到发布自动化了。
|
||||
|
||||
比如,针对iOS的版本发布来说,在构建和打包之后,我们可以获取到对应的ipa包,关联对应的版本信息元数据后,就可以上传到内部的发布站点,供QA下载测试了;或者上传到Apple TestFlight进行公测;当然也可以部署到App Store了。
|
||||
|
||||
接下来,我就和你详细说说如何做到发布的自动化。
|
||||
|
||||
你可以使用Fastlane等类似的工具完成整个发布过程,还可以根据不同发布的渠道定义各自的lane。当然Fastlane也可以提供打包等一系列Action,帮助你完成自动化。
|
||||
|
||||
```
|
||||
lane :release do #发布到AppStore
|
||||
increment_build_number #自增版本号的方法
|
||||
cocoapods #更新pod
|
||||
gym #打包
|
||||
deliver(force: true) #发布到AppStore
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
这是一段最简单的Fastfile脚本。它的功能是:利用Fastlane提供的Action完成了打包,并发布到AppStore。另外,你还可以在Appfile(Fastlane用来描述App基本信息的专用描述文件)中定义关于App的信息。
|
||||
|
||||
当然,你还可以按照发布流程的需求定义自己的lane和Action,完成不同的操作。
|
||||
|
||||
```
|
||||
private_lane :build do |options|
|
||||
project = options[:project] #获取项目对象
|
||||
build_number = project.build_number #获取项目定义的版本号
|
||||
gym(
|
||||
workspace: project.workspace, #编译工作空间
|
||||
configuration: project.config, #编译配置
|
||||
include_symbols: true, #是否包含符号
|
||||
scheme: project.scheme, #编译计划
|
||||
xcargs: "BUILD_NUMBER=#{build_number}", #版本号
|
||||
build_path: project.package_path, #编译路径
|
||||
output_directory: project.package_path, #ipa包输出地址
|
||||
output_name: project.ipa_name, #ipa包的名字
|
||||
silent: false) # 编译Action
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
这段代码展示的就是,用gym action构建一个自定义的、带参数的完整的构建过程了。我们可以看到,这里的参数是具体的一个project对象。当然,这里还有一个叫作output_directory的参数,你可以利用这个参数把构建的ipa包放到内部的下载地址。
|
||||
|
||||
这样看,移动App的自动化发布是不是很简单?[https://github.com/fastlane/examples](https://github.com/fastlane/examples)这里还有更多相关的例子,你可以参考它们完成更加复杂的自动化发布。
|
||||
|
||||
## 总结
|
||||
|
||||
今天,我和你一起分享了移动客户端持续交付流水线的几个详细点:
|
||||
|
||||
<li>
|
||||
利用发布快车的发布模式,可以有效地管理客户端的版本,保证研发工作按节奏持续向前进展;
|
||||
</li>
|
||||
<li>
|
||||
采用带发布分支的GitLab Flow配合发布快车的模型,可以使其做到物理落地;
|
||||
</li>
|
||||
<li>
|
||||
发布快车本身也有一些弊端,比如对Master分支的合并,检查不够严格的话,会拖累项目进度,因此我们采用改造构建通道的方式,避免了这个问题的产生;
|
||||
</li>
|
||||
<li>
|
||||
移动App的发布,有其独特的流程,通常是先内测,后正式发布;但其流程相对固定,且容易自动化。所以,我的建议是,实现发布的完全自动化,以提高研发效率。
|
||||
</li>
|
||||
|
||||
另外,我还介绍了Fastlane这样一个工具,能够帮助你快速完成自动化的实现。
|
||||
|
||||
当然,我今天所分享的只是移App持续交付流水线的一种方式。在工程实践中,不同的产品和组织,往往会存在不同的流水线。
|
||||
|
||||
所以,关于移动App的流水线,并没有对错、优劣之分,合适的才是最好的。
|
||||
|
||||
## 思考题
|
||||
|
||||
你所在的团队,移动App的持续交付流水线,有哪些点与我今天分享的内容有所不同?你可以分析出是什么原因导致了这些不同吗,又是否可以进行优化呢?
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
||||
|
||||
|
||||
169
极客时间专栏/geek/持续交付36讲/持续交付移动App/33 | 进阶,如何进一步提升移动APP的交付效率?.md
Normal file
169
极客时间专栏/geek/持续交付36讲/持续交付移动App/33 | 进阶,如何进一步提升移动APP的交付效率?.md
Normal file
@@ -0,0 +1,169 @@
|
||||
<audio id="audio" title="33 | 进阶,如何进一步提升移动APP的交付效率?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/f5/71/f572fd11afded0441f1590f9809d1771.mp3"></audio>
|
||||
|
||||
你好,我是王潇俊。今天我和你分享的主题是:进阶,如何进一步提升移动App的交付效率?
|
||||
|
||||
通过我在前面分享的《了解移动App的持续交付生命周期》和《细谈移动App的交付流水线(pipeline)》两个主题,你应该已经比较全面和细致地理解了移动客户端持续交付的整个过程。
|
||||
|
||||
当然,搭建持续交付体系的最终目的是,提升研发效率。所以,仅仅能把整个流水线跑起来,肯定满足不了你的胃口。那么,今天我就再和你聊聊,如何进一步提升移动App的交付效率。
|
||||
|
||||
## 提升交付效率的基本思路
|
||||
|
||||
同其他很多问题的解决方式一样,提升移动App持续交付的效率,也是要先有一个整体思路,再具体落实。
|
||||
|
||||
理解了移动App的交付流水线后,你很容易就能发现,它其实与后端服务的交付流水线十分相似。
|
||||
|
||||
后端持续交付流水线包括了:代码管理、环境管理、集成和编译管理、测试管理,以及发布管理这五个核心过程。而与之相比,移动App的运行形势决定了其在环境管理方面没有特别多的要求。
|
||||
|
||||
所以,我们可以从代码管理、集成和编译管理、测试管理,以及发布管理这四个方面来考虑问题。而将这四个方面直接对应到研发流程的话,就是标准的开发、构建、测试、发布过程。因此,移动App持续交付流水线的优化,我们只要从这四个过程中寻找优化点即可。
|
||||
|
||||
**我们优化移动App持续交付体系的整体思路就是**:首先找到这四个核心过程中存在的问题或瓶颈,再进行针对性的优化,从而达到提升效率的目的。
|
||||
|
||||
接下来,我们就逐一击破这四个核心过程中的难题吧。
|
||||
|
||||
## 如何提升开发效率?
|
||||
|
||||
从开发人员的角度看,提升效率最好的方法就是2个字:解耦。落到技术实现上来说,就是通过组件化形成合理的开发框架。
|
||||
|
||||
组件化是指,解耦复杂系统时将多个功能模块拆分、重组的过程。对于移动App来说可以横向地按功能模块进行组件化;也可以纵向地按照架构层次进行组件化。当然目前移动App的架构往往都已经比较复杂了,所以通常都是两者混合的模式。
|
||||
|
||||
组件化带来的好处包括:
|
||||
|
||||
<li>
|
||||
<p>**方便拆分代码仓库,降低分支管理难度,提高开发并行度。**<br />
|
||||
在上一篇文章《细谈移动App的交付流水线(pipeline)》中,我给出了一种适应发布快车模式的代码分支管理模型。试想一下,如果一个巨大的App的所有代码都集中在同一个代码仓库中,而所有的并行开发功能又都会形成一个个的功能分支的话,它们之间相互的影响将是难以想象的。<br />
|
||||
其实,任何一个代码仓库,当需要管理的并行分支超过10个时,都会让人头痛。所以,组件化的好处就是,对整个项目进行解耦,把不相干的功能组件从代码仓库这个层面进行隔离,以免互相影响。</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>**组件可以多版本存在,通过依赖快速选取所需版本。**<br />
|
||||
所有的组件都可以同时发布多个版本,发布的形式可以是代码包、二进制组件等等。这样做的好处是,对于组件的提供方和依赖方来说,只需要通过版本控制就能管理或者选取自己需要的组件功能,这种方式更符合编程习惯,也降低了减少沟通成本。</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>**专业分工,形成更优的组织结构。**<br />
|
||||
一旦实施组件化,各种更专业的通用组建会慢慢形成(比如网络处理、图片处理、语音处理等等),而这些更专业的组件,也会渐渐地由更专业的人或团队进行开发和维护,专业的分工使得研发效率得到进一步提升。<br />
|
||||
所以,组件化其实就是通过专业分工,提升了整个组织的开发效率。</p>
|
||||
</li>
|
||||
|
||||
当然,组件化并非完美无瑕,它同时也会引起一些问题,比如:
|
||||
|
||||
<li>
|
||||
**组件间的依赖问题**。由于多组件、多版本的存在,加之它们之间的传递依赖,所以组件化之后的依赖管理问题不容小觑。
|
||||
</li>
|
||||
<li>
|
||||
**组件间的兼容问题**。兼容性问题,是由组件间的依赖问题引发的,由此组件的发布管理也会成为瓶颈:组件间到底要不要兼容?出现了不兼容的情况,应该怎么办?
|
||||
</li>
|
||||
|
||||
其实,组件化带来的这些负面影响,在开发人员的维度是看不到的,往往会发生在构建阶段。还好,这些问题并不是无解的。接下来,我们就一起看看构建阶段如何解决这些问题,并提高效率吧。
|
||||
|
||||
## 如何提升构建效率?
|
||||
|
||||
从目前业界流行的处理方法来看,提升构建阶段的效率,可以从扁平化依赖管理和二进制交付两个维度解决。
|
||||
|
||||
**第一,扁平化依赖管理**
|
||||
|
||||
组件的依赖问题,到底有多让人头痛。我们一起来看看图1中的组件依赖示例吧。
|
||||
|
||||
一个App中的两个组件B和C都依赖了组件G,但依赖的却是组件G的不同版本。所以,这个组件G的2个版本间就发生了冲突。
|
||||
|
||||
由此可见,由传递依赖带来的不确定性,是我们经常会遇见并非常讨厌的组件依赖形式。因为发现和处理的成本都很高。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/24/87/24a6ebb48588b8a3660d0e357b2db187.png" alt="" />
|
||||
|
||||
通常情况下,一个移动App可以拆分出十几到几十个组件。大型的移动App,如淘宝、美团,甚至可以拆分出几百个组件。要保证这么多组件间依赖传递的准确性,其难度非常大。所以,为了解决这个问题,业界现在普遍直接采用扁平化的依赖管理方式,减少甚至去除传递依赖,以此避免组件、版本冲突的问题。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d7/bc/d7892bb8128b939b28117fa5e05bfbbc.png" alt="" />
|
||||
|
||||
而且,这样的扁平化管理方式,对于一个App版本来说,更清晰、直观。
|
||||
|
||||
那么,实现这种扁平化的管理方式,需要具备什么前提吗。
|
||||
|
||||
答案,当然是需要。这个前提就是:不同组件之间,以及不同版本之间要保证可兼容。但是,你我都清楚,要想保证全部版本的完全可兼容性,其成本是巨大的。所以,在实践中,我们不会去保证所有版本的绝对兼容,而是去实现所有版本、组件间的相对兼容性。
|
||||
|
||||
相对兼容性是指,每个组件在发布新版本时,对于其所依赖的其他组件,都选择组件仓库中的最新版本。这样就保证了这个组件在发布之后的兼容性。如果所有组件都可以这么做,就能保证其各自都兼容。但是这个方法不是绝对的,比如我们会遇到并发发布,或者多个组件间引起的功能逻辑的冲突等问题,所以还是需要对移动App进行集成测试。
|
||||
|
||||
**第二,二进制交付**
|
||||
|
||||
解决了组件的依赖问题之后,我们需要再考虑的问题是,如何才能提高编译速度。
|
||||
|
||||
传统的移动App组件集成及编译的方式如图3所示。组件先以源码的方式集成到目标项目,然后对整个项目进行编译。如果组件比较多的话,采用这种方式的编译时间会非常长。有时,甚至要编译1个多小时。显然,我们不会接受这种低效的集成与编译方式。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/1f/6d/1f35512e72205887d48021e0ab3e1b6d.png" alt="" />
|
||||
|
||||
所以,为了加快编译速度,业界通常会采用二进制交付和集成的方案。如图4所示,二进制交付,会优先把组件编译成二进制包,再形成版本,并通过组件仓库进行版本管理,正如图中的组件A Lib包。在真正编译时,我们只要直接链接二进制包就可以了,无需再进行一次编译。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/42/4b/42ac7ab34eacf9eaea01c8db4affa84b.png" alt="" />
|
||||
|
||||
使用二进制包的方式,可以帮我们大幅提升移动App的编译速度。而且,因为有了中间交付物,我们可以采用与后端服务一样的方式,在本地缓存需要依赖的组件,进一步加速编译过程。
|
||||
|
||||
**通过对开发、构建过程的优化,我们已经将原来的交付效率至少提高了1倍。**
|
||||
|
||||
接下来,我们再一起看看,如何优化测试和发布流程,以求移动App的持续交付体系更高效。
|
||||
|
||||
## 如何提升测试效率?
|
||||
|
||||
提高移动App测试效率的方法,主要的思路有三个:
|
||||
|
||||
<li>
|
||||
<p>**代码静态扫描工具**。<br />
|
||||
移动App的测试,同样可以使用与后端服务一样的代码静态扫描工具。但相比之下,后端服务通常使用的那些工具虽然普适性强,但太重且定制的门槛也很高;所以针对移动App的代码静态扫描,目前多数大厂都采用自研的方式,定制静态代码扫描工具。另外,针对移动App开源的静态代码扫描工具,如Lint等,已经可以满足小团队的使用了。</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>**UI自动化测试**。<br />
|
||||
这部分的关注点是成本和收益比,你我都清楚,UI自动化测试的脚本维护成本高,导致其难以被大规模使用。所以,针对重要的模块和组件,有计划地使用UI自动化测试是重中之重。</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>**自动Monkey测试**。<br />
|
||||
Monkey是一款非常好用的探索性测试工具,可以大幅提升测试效率,有效解决手工测试的盲点。iOS系统的测试,由于系统限制比较多,所以可以在模拟器上执行Monkey的方式。</p>
|
||||
</li>
|
||||
|
||||
合理地利用这些测试工具和方法,就可以有效提升客户端的测试效率。
|
||||
|
||||
当然在测试过程中,合理地搭配监控工具,如性能监控、白屏检测等,可以起到更好的作用。
|
||||
|
||||
## 如何提升发布效率?
|
||||
|
||||
在前面两篇文章中,我提到过,移动App的发布流程与后端服务相比差别较大,根本原因在于移动App天生具备的分批发布特性。
|
||||
|
||||
所以,提升移动App的发布效率,我们也要采用与后端服务不一样的方式。在这里,我总结了提升移动App发布效率,需要注意的两个问题:
|
||||
|
||||
<li>
|
||||
<p>**要注意分发的精准性**。精准性指的是,分发的目标、数量、时长,以及渠道一定要合理、有效,否则就会消耗无谓的分发成本。<br />
|
||||
这里,我和你分享一个关于分发精准性的技巧。其实,说是技巧,更不如说是大家在发布过程中容易疏忽的内容。为了进行小批量的测试,通常我们都会准备一个针对性的测试用户名单。但是,你有没有想过这份名单的更新周期呢?我看到很多组织都极少更新这份名单,其实这样既对用户体验不好,也会影响测试结果。小白鼠也要时常替换的,否则就会失去实验价值。<br />
|
||||
关于这份名单的更新周期,我的建议是:结合业务实际情况,尽量避免一个用户连续多次成为小白鼠。</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>**要注意分发的稳定性**。稳定性指的是,在分发的过程中,一定要做好监控数据的收集和分析,并且要考虑好风险的处理以及必要的回滚和热修复手段。<br />
|
||||
这里,我也和你分享一个关于稳定性的技巧。提高分发稳定性的一个方法就是,减少分发时更新的内容,并同时减少更新的时间。而对于移动App来说,静态资源包的差分发布就是一个优化方案。<br />
|
||||
比如,携程在选择静态资源包的差分发布时,就经历了这样一个优化过程:从全量包发布,到文件二进制差分,再到预差分。前两个方案都是在更新时,进行差分;而预差分则是在版本发布时,就已经做好了差分计算。与前两种方案相比,预差分的目的就是减少更新时间。但预差分的缺点是,可能要对所有要发布的版本进行差分处理,这将是一个巨大的笛卡尔积。<br />
|
||||
所以,携程在经历几次尝试后,最终选择的方案是:结合全量包发布、文件二进制差分,以及预差分三种方案的特点,形成了按需差分的方案。即,先收集用户正在使用的版本,然后只做这些版本与最新版本的差分,从而减少差分处理的成本。</p>
|
||||
</li>
|
||||
|
||||
在我看来,确保每次分发的有效性,以及每次分发都能达到预期,就是提高移动App发布效率的一种最有效的手段。
|
||||
|
||||
## 总结
|
||||
|
||||
在了解了移动App持续交付体系的内容后,你就可以自己去动手搭建一套持续交付体系了。持续交付体系搭建起来后,我们需要考虑的问题就成了,如何优化这个体系的流程,提升这个体系的效率。为此,我从开发、构建、测试和发布这四个核心流程的角度,和你分享了一些实践经验:
|
||||
|
||||
<li>
|
||||
利用组件化的思想提升开发效率,但同时也会带来组件依赖及发布的问题;
|
||||
</li>
|
||||
<li>
|
||||
利用扁平化依赖管理的方法解决组件依赖和发布的问题,同时采用二进制交付的方式,进一步提高构建效率;
|
||||
</li>
|
||||
<li>
|
||||
合理利用静态代码扫描、UI自动化、自动Monkey等测试工具和方法,进一步提升测试效率;
|
||||
</li>
|
||||
<li>
|
||||
确保分发的精准性和稳定性,是提升发布效率的有效手段。
|
||||
</li>
|
||||
|
||||
至此,通过持续交付移动App的三篇文章,再结合着以前我分享的后端服务的持续交付体系的内容,你完全可以自己厘清构建移动App持续交付体系的流程了,也知道了如何去优化这个流程。
|
||||
|
||||
希望这些内容,可以开拓你的思路,能够帮助你解决实际项目中遇到的问题。如果你还有哪些不清楚的内容,欢迎你留言和我一起讨论。
|
||||
|
||||
## 思考题
|
||||
|
||||
在今天的分享中,我介绍了一种扁平化依赖管理的方法。在实际工作中,你是如何管理依赖和bundle的呢?
|
||||
|
||||
感谢你的收听,欢迎你给我留言。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user