写点什么

闲鱼如何解决 iOS 环境搭建与 APP 打包速度问题

2020 年 8 月 13 日

闲鱼如何解决iOS环境搭建与APP打包速度问题

随着 Flutter 等跨端框架的出现,业务开发同学经常需要在 Android/IOS 上跨端进行业务开发,问题定位等。新的不熟悉的环境的搭建总会遇到各种各样的问题,导致搭建失败,特别是 IOS 开发环境,是最复杂的,不仅环境搭建繁琐,而且切分支后的打包速度很慢,所以我们设计实现了两个工具,用于优化闲鱼 IOS 开发体验。


IOS 开发体验存在的问题


开发环境搭建难


  • 开发环境依赖特定软件版本,配置复杂


闲鱼 IOS 工程不仅依赖 XCode,还依赖了 taobaoenv 1.2.0 和 cocoapods 1.2.0 这两个包管理工具。根据大家的经验,这两个工具在 ruby2.3.x 时,问题较少。特定软件版本,系统自带软件版本冲突,环境变量设置等等一些列的操作步骤导致环境搭建复杂,需要求助 IOS 开发同学才能搞定。


  • 维护难


Mac 系统升级后,cocoapod 容易出现问题,不得不重新搭建开发环境。具体原因也是多种多样:系统环境变量变了,导致找不到特定版本 ruby;ruby 随系统升级导致 cocoapod 不能用,需要重新安装;Gem 版本问题;Ruby 源问题等等。这也导致许多开发同学不敢轻易的去升级系统,无法及时体验到新系统的特性。


  • Pod 依赖下载量大


由于 cocoapod 本身的工作原理,pod 更新下载工程依赖时,会下载各个版本的文件信息,总量特别大。以闲鱼 IOS 工程为例,总共需要下载近 20G 的缓存文件,而且大部分都是几 K 的小文件,下载时间可能会持续十几个小时,导致新环境搭建到初次体验时间跨度非常久。


切分后 APP 打包慢


当开发同学在多个分支/版本开发的时候,时常需要切换分支开发调试和 bugfix。但是切换分支之后,整个 IOS 工程打包时间在 30-40 分钟左右。有时候为了修复一个版本的 bug,不得不切换分支,然后重新打包调试。修复和验证 bug 可能只需要五分钟,打包却用了 30 多分钟,投入产出不成比例。


为了解决这些存在的问题,我们进行了一些列的探索,跟大家一起分享下,也欢迎有更好的解决方案出现。


IOS 环境搭建


虚拟化技术的不断发展,为我们统一端侧开发环境提供了新思路,我们设想如果 IOS 开发环境能够跟 Mac 解耦,且可以移植,大家可以轻松复用,那么第一二个问题就迎刃而解了。为此我们做了几个尝试:


虚拟机方案


在 MacOS 本地搭建虚拟机,内装 MacOS 系统。在虚拟机内搭建 IOS 开发环境,然后通过虚拟机镜像 copy 实现 IOS 开发环境移植,解决环境搭建难题。



这个方案存在以下几个问题:


a. 性能问题,IOS 的编译过程是一个 IO 密集型和 CPU 密集型操作,虚拟机通过虚拟 HOST 系统的磁盘和 CPU,性能会大打折扣,导致编译时间变长,影响开发体验。


b. 安全问题。在 Mac 工作机安装虚拟机,需要通过公司安全审核。


c. 黑苹果问题:虚拟机内的 Mac 系统是没有经过授权的,会带来盗版侵权风险。


虚拟机是比较重的虚拟化技术,因此我们转向了更加轻量化的 docker 技术。


完全 Docker 化


将 IOS 开发依赖的软件和环境变量全部 docker 化。通过 docker 镜像实现 IOS 开发环境的移植。对于 cocoapod, taobaoenv 等 ruby 类工具,鉴于 ruby 的跨平台特性,可以很方便的迁移到 docker 内。但是对于强依赖 MacOS 的 XCode,我们尝试用 Facebook 出品的 xcbuild 替代。这是一款兼容 xcodebuild 的编译工具,网上也确实有网友用这个软件搭建 IOS 编译环境。



这个方案存在以下几个问题:


a. Xcbuild 跟 Xcodebuild 的兼容性无法评估


b. xcode 升级后,xcbuild 跟进升级兼容的一段时间内,只能回退到原来的开发方案,来回切换开发环境,体验差。


上面两个方案都没有很好的解决 IOS 开发环境移植和解耦的问题,但是在完全 docker 化的尝试中,我们发现最复杂的 cocoapod 和 ruby 安装配置部分是能够 docker 化的,xcode 安装后并不需要特殊的配置,因此我们设计实现了一个折中方案:Host 内开发(部分 docker 化)


Host 内开发(部分 docker 化)


本方案中:开发编译调试工作仍然在 MacOS 本地,使用 xcode; 而将 cocoapod 和 taobaoenv 相关的软件和环境变量配置等 docker 化。这样既遵循了开发同学一贯的开发体验,又兼顾了开发环境的可移植问题。



为了能够让 Docker 内 cocoapod 拉取的依赖文件和生成的 pod 工程能被本地的 XCode 识别,我们将本地 pod 缓存目录挂载到 docker,这样 Pod 拉取的依赖既能在 docker 内更新,也能在 MacOS 中被 XCode 访问,具体如下图(统一编程平面端+Faas 软件架构图):



这样既做到了简化开发环境搭建的复杂度,方便了想尝试 IOS 开发的同学快速搭建环境,还能给开发同学无差别体验。而且通过这个方案,我们的 IOS 开发环境可以方便的在各个同学的开发环境中迁移,而且也可以统一进行升级改造。


本方案将 Pod 相关的依赖迁移到了 Docker 中,与 MacOS 解耦,因此 IOS 开发同学可以自由升级 Mac 系统,不用担心开发环境被破坏,解决了维护难的问题。


为了解决新搭建的环境需要大量拉取 pod 依赖的问题,我们将 pod 的本地中间文件上传到 OSS 云盘(上图蓝色 OSS 云盘),开发同学只需要一次性下载压缩包并解压到本地,然后增量更新就可以了。


切分支后 APP 打包速度问题


客户端开发同学经常需要在多个分支(版本)上面开发业务,且时常需要来回切换进行业务开发和问题定位。这带来的一个问题是:当开发同学从 A 分支切换到 B 分支的时候,需要重新打包 APP,整个过程大概需要 30-40 分钟左右。


在分析了闲鱼 IOS 工程打包过程后,我们将耗时锁定在两个阶段:Pod 操作和 XCode 编译。打包速度优化也将分为两个阶段进行:


Pod 操作加速


Pod install/update 主要的工作是读取 Podfile,进行依赖版本控制和冲突解决,并生成 Pod 工程。生成的相关文件存储在 Pods 目录和 Pods.xcodeproj 中。当切换回之前分支时,Podfile 经常是不会发生变化的,因此重新生成 pod 工程实属浪费。


经过测试,如果我们将这些中间文件保存起来,多次切换分支后,这些中间文件仍然能够还原之前的 Pod 工程,从而避免切分支后重新生成 Pod 工程的步骤,省去 10 分钟左右的开销。


XCode 编译速度优化


对于 XCode 编译速度优化,网上有很多方案,大致可以分为三类:


  • Cocopods 依赖编译加速


比如 cocoapods-packager,它可以将 pod 依赖打包成 static library,IOS 工程以静态库的形式引入 pod 依赖,省去重复编译的时间。


但是这个方案也存在一些问题;私有库和第三方库更新很麻烦,每次都需要重新打包静态库,并上传到代码仓库;且很难调试源码


  • 分布式编译:比如 distcc


分布式编译的原理是将需要编译的文件分散到编译集群的其他机器上编译,然后将编译好的二进制文件传回。本地编译器再将这些二进制文件链接在一起。分布式编译对于大工程提速明显,但是对于小工程,反而会拖累编译速度。


  • 缓存编译的中间结果:CCache,BUCK


更为广泛的加速方案是缓存编译的中间结果,比如 CCache,Buck 等,这些方案,网上有详细的资料,不再一一赘述。但是引入这些方案,都需要对目前的 IOS 工程进行改造,甚至需要改变用户的开发习惯,因此不符合我们的要求。但是缓存中间编译结果的方案给我们提供了一些启发:


我们知道 XCode 是具有增量编译能力的,这其实也是利用了上一次编译的中间产物,本地再次编译的时候,如果发现文件没有变化,则忽略这个文件,如果源码文件时间戳更新了,那么就重新编译这个文件,因为每次变化的源码都是少量的,这样就可以达到加快编译速度的目的。


对于闲鱼 IOS 工程,如果我们在切分支之前保存当前 IOS 分支编译的中间产物,然后在切换回当前分支的时候,恢复之前保存的中间产物,那么是不是就可以触发 XCode 增量编译了呢?事实确实如此。



具体方案:


  1. 在切分之前缓存当前分支的 Pods Project, Flutter Project 以及编译的中间产物,Podfile.lock, linkmap 等等相关文件。

  2. 切换分支

  3. 恢复新分支之前缓存的中间产物

  4. 重新打包 IOS APP。


通过这两步优化,我们将闲鱼 IOS 工程切分支后的打包时间由原来的 30-40 分钟降低到五分钟以内,效率提升近六倍。


总结


IOS 环境搭建中复杂和耗时的步骤,通过 docker 镜像和缓存优化后,搭建的难度大大降低,IOS 新手也基本可以在三小时内搞定



同时,通过缓存和复用打包过程产生的中间产物,切换分支后的打包耗时控制在五分钟内,降低为原来的六分之一,提升了开发效率。


本文转载自公众号闲鱼技术(ID:XYtech_Alibaba)。


原文链接


https://mp.weixin.qq.com/s/R2XYOczL4-qftewWM7VKNg


2020 年 8 月 13 日 10:041047

评论 1 条评论

发布
用户头像
IOS还是好好写成iOS吧,名称还是要规范的
2020 年 08 月 13 日 12:43
回复
没有更多了
发现更多内容

如何利用小熊派获取MPU6050六轴原始数据

华为云开发者社区

物联网 IoT 小熊派

为什么说区块链完全去中心化做不到且没有意义

CECBC区块链专委会

区块链 去中心化

架構師訓練營第 1 期 - 第 11 周總結

Panda

架構師訓練營第 1 期

详解TCP IP网络协议栈底层原理到徒手实现

赖猫

c++ Linux 编程 程序 网络协议栈

二本毕业、两年Javacrud经验,面试阿里侥幸通过成功拿到P6级offer,分享面经!

Java成神之路

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

我把Github上最牛b的Java教程和实战项目整合成了一个PDF文档

Java成神之路

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

云图说|AI开发难!难!难!端云协同多模态AI开发套件你需要了解一下

华为云开发者社区

AI 分布式协同 开发

第11周学习总结

饭桶

腾讯云区块链总经理李力:产业区块链的四大发展趋势

CECBC区块链专委会

区块链 大数据

天啊!怎么会有人把Spring Cloud微服务架构讲得这么透彻?

Java成神之路

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

架构师训练营第 1 期 - 第十一周总结

Todd-Lee

极客大学架构师训练营

Gemini双子新约软件系统开发|Gemini双子新约APP开发

开發I852946OIIO

系统开发

字节总监首发1121道LeetCode算法刷题笔记(含答案)

Crud的程序员

程序员 面试 算法 字节 面试刷题

通用软件快速开发平台对企业信息化的影响

雯雯写代码

软件 快速开发 企业信息化

Reactor线程模型浅析

赖猫

c++ Linux 编程 reactor 编程语言

第十一周课后练习

饭桶

开源软件联盟PostgreSQL分会投稿指南

PostgreSQLChina

数据库 postgresql 软件 投稿

如何在高速发展中等一等老人 银行数字化服务显温度

CECBC区块链专委会

银行 养老服务

我是因为这个才选择当程序员的,那么你呢?

Java架构师迁哥

量化交易系统APP软件开发(现成)

开發I852946OIIO

系统开发

京东T8Java架构师总结整理的《15w字的Java面试手册》,涵盖了大厂所有主流技术面试题及答案!

Java成神之路

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

从构建小系统到架构分布式大系统,Spring Boot2的精髓全在这里了

Java成神之路

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

架構師訓練營第 1 期 - 第 11 周作業

Panda

架構師訓練營第 1 期

追忆

刘旭东

回忆 情绪

解析—MyBatis在SpringBoot中动态多数据源配置

比伯

Java 编程 程序员 架构 计算机

【硬件篇之电源纹波噪声测试】

良知犹存

硬件

架构师训练营第 1 期 - 第十一周作业

Todd-Lee

极客大学架构师训练营

Java对IPv6的支持详解:支持情况、相关API、演示代码等

JackJiang

Java 网络编程 ipv6 ipv4

一文搞懂RESTful API

bigsai

RESTful Rest

深入理解Git的实现原理

程序员小灰

c++ git Linux 项目管理 架构师

大企软件系统问题多?归乡名企工程师:解决很简单,分分钟做个新系统

Philips

敏捷开发

NLP领域的2020年大事记及2021展望

NLP领域的2020年大事记及2021展望

闲鱼如何解决iOS环境搭建与APP打包速度问题-InfoQ