写点什么

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

  • 2020-08-13
  • 本文字数:3329 字

    阅读完需:约 11 分钟

闲鱼如何解决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-08-13 10:043782

评论 1 条评论

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

Design for failure常见的12种设计思想

架构精进之路

降级 重试 容错 8月日更

原来select语句在MySQL中是这样执行的!看完又涨见识了!这回我要碾压面试官!

冰河

MySQL 面试 精通MySQL SELECT查询流程 查询缓存

译文 | 四种产品经理成长框架,你是哪一种?

LigaAI

产品经理 产品管理 PM

AudioTracker实用封装

Changing Lin

8月日更

Lucene 倒排索引原理

Qunar技术沙龙

数据库 全文检索 lucene 倒排索引 搜索

【Maven技术专题】如何使用Assembly插件实现自定义打包

码界西柚

maven assembly 8月日更

深度学习中的分布式训练

安第斯智能云

人工智能 深度学习

重磅 | 用友《数字化中台》震撼上市!数智化转型和商业创新实践的企业级经验!

博文视点Broadview

【Vue2.x 源码学习】第二十四篇 - 异步更新流程

Brave

源码 vue2 8月日更

索信达控股:银行4.0的AI世界——开启算法力的时代

索信达控股

人工智能 金融科技 银行

基于docker的分布式性能测试框架功能验证(二)

FunTester

分布式 性能测试 接口测试 测试框架 测试开发

百度爱番番移动端网页秒开实践

百度Geek说

大前端 优化 网页加速 移动端

知道ThreadLocal吗?一起聊聊到底有啥用

华为云开发者联盟

Java 架构 线程 ThreadLocal 链路

高亮的架构毕业总结

高亮

架构训练营

一文带你搞定AOP切面

华为云开发者联盟

spring aop 切面编程 面向切面编程 切面

kafka SpringBoot

Rubble

kafka springboot 8月日更

万字深入HarmonyOS ACE UI框架解析,带你看懂UI渲染流程

科技汇

LeetCode题解:173. 二叉搜索树迭代器,递归,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

多语言ASR?没有什么听不懂,15种语言我全都要

华为云开发者联盟

语言 ASR 多语言ASR 单语模型 Conformer

分布式性能测试框架用例方案设想(二)

FunTester

分布式 性能测试 接口测试 测试框架 测试开发

【LeetCode】加一Java题解

Albert

算法 LeetCode 8月日更

基于ECS快速搭建 Docker 环境

若尘

Docker 服务器 8月日更

复杂多变场景下的Groovy脚本引擎实战

vivo互联网技术

敏捷开发 脚本语言

图分析在吴亦凡事件中的应用场景

6979阿强

图算法 图计算 GraphScope 吴亦凡 一站式图计算平台

PostgreSQL 中如何控制行级安全和列级安全

Qunar技术沙龙

sql postgresql 运维 安全 权限

鸿蒙内核之内存调测:动态内存池信息统计

华为云开发者联盟

鸿蒙 内存 动态内存池 内存信息

Springboot 配置文件、隐私数据脱敏的最佳实践(原理+源码)

程序员小富

Java springboot 数据安全 数据脱敏

科技融合:Hightopo受邀参加厦门公安科技活动周

一只数据鲸鱼

数据可视化 智慧公安 智能化 安全态势

【Flutter 专题】132 图解 PaginatedDataTable 分页表格

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 8月日更

手撸二叉树之对称二叉树

HelloWorld杰少

算法和数据结构 8月日更

应对极端天气,百度智能云推出城市内涝智能监测预警系统

科技热闻

闲鱼如何解决iOS环境搭建与APP打包速度问题_安全_柬超_InfoQ精选文章