<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的交付来说，版本和信息管理非常重要。你所在的公司是如何管理这些信息的，有哪些可以优化的可能吗？

感谢你的收听，欢迎你给我留言。


