动手点关注 干货不迷路
2016 年 9 月 26 日,抖音 1.0.0 版本上线,截至目前,抖音日活跃用户突破 6 亿,短短 6 年间,抖音实现了从零开始的爆发性增长。在业务快速发展、数据海量增长、视频/直播形式对画质提出更高要求的背景下,抖音基础技术团队如何以技术革新应对时代变局、以匠人之心优化用户体验不被外界“看好”的 iOS 开发领域,抖音团队又交出了一份怎样的答卷br>
1 月 22 日下午,第三期字节跳动技术沙龙以线上直播的方式与广大观众见面。本次沙龙以《抖音 iOS 基础技术大揭秘》为主题,邀请了陈显财、陈文欢、舒彪、韩建磊、朱峰 5 位抖音 iOS 客户端工程师,从不同角度阐释了亿级 App 抖音在 iOS 客户端开发方面的实践经验,为近 4 万名在线观众带来了一场扎根实践、面向前沿的技术盛宴。
陈显财《大型 App 开发架构演进及挑战》
架构的优劣决定了工程的规模和效率。抖音基础技术 iOS 客户端架构师陈显财老师介绍了抖音团队如何在不影响业务迭代和业务规模扩张的前提下,持续推进抖音从模块化、组件化、到插件化的架构演进历程。
模块化
面对开发初期代码体量膨胀、业务规模扩大、开发人员增加与业务正常迭代的矛盾,技术团队首先考虑从提升效率的角度出发,从主工程中剥离出依赖工程、环境配置和 App 资源,并设计了底层代码的基础依赖能力,形成一个壳工程。团队还从源码环境资源工具的角度设计了相对统一的模板,使得模块能够基于统一的标准进行创建和开发。
组件化
在业务持续发展的背景下,单个业务模块内的代码也在加速膨胀;模块化拆分后,不合理的接口依赖有待进一步分析治理;iOS 新增的扩展插件和基础能力推动 Swift 混编落地成为必然……在此背景下,技术人员开启了组件化进程,降低团队整体的研发能效。
为解决代码复用问题、降低依赖复杂度,团队重新定义了抖音的 5 级架构分层:
-
壳工程;
-
业务层;
-
接口层;
-
服务层;
-
基础层;
这一架构分层将模块化带来的 状依赖结构改造成树状依赖结构,降低了依赖的复杂度,保障各层之间的依赖不劣化。
二进制化带来的另一个问题是接口层的变更。为应对接口冲突带来的二进制污染问题,技术人员结合主干的语法树信息,通过 mr 直接检查真实的调用量,每天拦截二进制污染的问题大概在 10%左右,有效保障了团队整体开发的稳定性。
为提升整体研发能效,团队还提供了一套基于二进制的代码隔离方案,通过绑定适配器协议和获取适配器协议的方法,把业务差异化的代码通过适配器隔离到二进制中。同时,建设了相关的基础配套设施来监控代码变更,使多个 App 的影响可以被感知量化。
为降低底层依赖复杂度、提升代码质量,团队还设计了服务框架,支持把抽象的接口绑定到具体的实现上,并支持实现的热切。这项框架极大满足了解耦服用、动态部署、服务组合、编译期抹平底层语言差异、运行期支持服务热切等方面的能力需求。
此外,技术人员还在本地多模式研发等方面做出了积极探索。
陈文欢《抖音 iOS 自动化服务:容器化和规模化探索》
自动化测试与持续集成对于保障软件工程质量具有重要价值,也是大型项目增量式开发的保障手段之一。抖音基础技术 iOS 客户端工程师陈文欢老师介绍了抖音 iOS 自动化如何做到容器化和规模化服务,以及其中涉及到的一些技术挑战和解决方案。
iOS 容器化测试
容器化测试一方面是为了测试稳定性的提升,另一方面也能隔离不同测试任务间的环境影响。在抖音 iOS 容器化建设的服务分层架构中,最底层的机架平台提供了抽象的机器管理和控制能力。基于此,技术人员搭建了包括单元测试、UI 测试等在内的专项测试服务,平台侧还提供了数据 表消费和一些业务管理的能力。同时,技术人员还基于公司的组件化现状和不同的 CI 系统,接入了研发环境和 CI 工具链。整套架构的运行,使公司众多的项目组件得以使用一些通用的测试服务,目前已应用于抖音、直播中台、今日头条等大型项目中。
iOS 设备控制
设备控制离不开 UI 交互。常见的点击操作、滑动手势、弹窗控件、键盘输入、前台唤起等都是自动化测试中需要使用到的基础能力。基于 XCTest 系统库,测试代码被集成到一个特殊的 App 中(称之为 UI runner),从而安装到测试设备上开始执行。陈文欢老师以XCTest 模拟点击 home 键的 API为切入点,详细分析了 iOS 设备的控制机制。
在字节自研的 iOS 设备控制链方案中,启动一个 App 并通过它的_IDE_authorize 协议授权 App 进程,其 PID 添加到 testmanagerd 接口使用白名单列表中,从而使 App 能通过跨进程调用的方式直接使用 testmanagerd 中所有关于设备控制的接口。
M1 模拟器规模化测试
2020 年 11 月,苹果自研 M1 芯片发布,并能在 M1 芯片上运行 iOS 程序。在此背景下,抖音团队开始探索在 M1 设备上进行测试,以期降低构建成本、为提升测试稳定性提供新可能。
如果在 M1 直接运行真机包测试,会面临 App 运行签名校验、同一个 bundleld 只能对应运行一个 App、没有 home 键且屏幕大小固定、机型和版本固定等局限,这些问题都会制约机架的规模化测试。因此,在 M1 模拟器上运行真机包测试,成为技术团队着力探索的方向。
在 JoJo 中,技术人员基于 clone 和 Swift 的编译器实现对 C 系和 Swift 系代码进行快速依赖计算的工具,2000+C 系文件扫描在数秒内即可完成、Swift 系代码也可实现类似性能。由此,JoJo 在保证正确性的前提下,又几乎不会带来 overhead,实现了正确而又快速的缓存复用体验。
此外,在 JoJo 构建系统中,通过分布式缓存和构建集群来提速构建。对于每一个构建的子任务,JoJo 会根据其依赖计算出一个 key,然后再通过这个 key 去远端缓存服务器查询已有产物,如果匹配成功,则下载产物、文件输出,子任务完成;如果未命中,JoJo 就会真正调用相关工具进行一次构建,在本地或远端执行。为避免从本地上传相关的资源文件到远端集群,JoJo 会通过内部高速 络从缓存服务器下载所需文件,本地只需传输一份清单给集群。远端集群本身可以扩展,可以是 Mac 机器,也可以是 Linux 机器,使集群可扩充性大大提升。最终便形成了一个完整的分布式构建体系。
多工程架构支持
目前常见的仓库管理机制有 Monolith、Multirepo、Monorepo。JoJo 被设计为可以扩展地支持任何架构。目前,JoJo 支持标准 cocoapods 工程直接构建,而无需进行任何业务改造,抖音即以这样的模式来运行。今日头条则采用 Monorepo 进行业务管理、第三方库和基础库继续使用 cocoapods 管理的混合构建模式。同时,JoJo 也在尝试制定公司内部的Monorepo 开发标准范式,以一站式解决学习成本和迁移成本。
此外,技术团队还从索引缓存、二进制调试源码索引、引入智能分析系统进行错误提示优化与指引等方面,对 JoJo 进行了进一步优化,以更好地助力各项业务的发展。
韩建磊《抖音 iOS 体验优化:流畅性优化探索》
目前负责抖音 iOS 客户端基础体验工作的韩建磊老师从具体可感的案例出发,为大家理清了流畅性相关的常见问题和优化策略,并结合实践经验为指标劣化问题提供了一定的排查思路和解决方案。
流畅性简介
什么是流畅性果从场景来区分,包括页面刷新、动画、转场、弹窗、拖拽、滑动等在内的一系列操作,都属于流畅性的范畴。如果从用户体验的视角出发,对流畅性的理解可以包含视觉体验、触觉体验和听觉体验三大指标。总体来说,流畅性可以用来衡量用户在各场景下的交互体验。根据抖音技术团队的实践经验,流畅性优化至少可带来3%的观看时长收益和 6.6%的视频播放数量收益,流畅性优化与人均播放时长、页面渗透率、用户留存、广告营收等业务指标息息相关。
当前,抖音主要以丢帧和FPS作为衡量流畅性问题的核心指标。
此外,技术人员还梳理了滑动、首刷等场景下各关键函数的调用,再通过汇编 Hook 的形式进行函数拦截,在主函数调用周期内,记录子函数的执行耗时,实现了既能采集各子函数耗时,又能采集内部的调用栈。同时,为使函数耗时监控系统能应用到各个场景,上层支持动态配置下发,还支持导出完整的调用链路,在达成监控目标的同时,将整体的性能损耗控制到最小。
优化实践
在回顾了常见的优化策略后,韩建磊老师从帧率和卡顿这两类细节优化入手,针对具体 case 阐述了应对问题的方法论。
这里列举了 3 个帧率优化的 case。
-
第一个在滑动中调用了 self.xxViewControler.view, 而且这个 xxVC 是懒加载的,如果之前没有初始化过,在这里触发 vc 创建、调用 viewdidload 明显是不合理的;
-
第二个在拖拽时进行了 userDefaults 的读取,第一次读取时,会把 plist 里所有数据全部加载到内容,从而导致卡顿。这个问题虽然很简单,但实际开发中却经常出现。
-
第三个在 willDisplayCell 时做了遍历,根据字符串做匹配,如果数组很大(比如几百几千个),也可能会造成丢帧。
整体流程如上图,客户端通过动态库注入,把监控代码植入到宿主 App,然后执行自动化测试任务,当命中各个场景时,会进行数据和堆栈记录;任务结束后,统一进行符 化;进而上 防劣化后台,最后生成数据 表,触发 警或进行智能诊断。
此外,抖音技术团队还在慢函数、动画、耗时任务打散、低端机降级等方面有较多投入,以更好地满足用户的流畅性体验。未来,团队还将在UI/动画、架构、线程管控等方向继续探索,不断交出一份份关于流畅性、关于用户体验的满意答卷。
朱峰《抖音 iOS 稳定性优化与探索》
抖音基础技术 iOS 客户端工程师朱峰老师一直参与抖音 iOS 应用的稳定性优化与保障体系建设,他从稳定性的基础概念出发,详细解读了稳定性框架和核心指标,并畅想了稳定性优化的未来。
基础概念
狭义上的Crash是指代码层面遇到的语言机制错误、CPU 访问异常、主动退出等问题;广义上的Crash则包括了内存过多被系统 kill(OOM)、主线程 block 被系统 kill(WatchDog)、CPU 过高被系统 kill 等问题,而这些都属于稳定性所关注的范畴。
核心指标详解
针对 Objective C 异常、多线程 Crash、杀进程时 Crash、全系统调用栈、编译优化级别导致的 Crash 等常见问题,朱峰老师阐释了问题的形成机制及应对策略。
以应对全系统调用栈 Crash为例,一般的应对流程是,在查看日志分析上下文环境的基础上,进行逆向系统库代码,通过 swizzle/fishhook 绕过有问题代码,结合使用 CoreDump 分析,如果本地能复现问题,可以使用 Xcode Malloc Logging 查找地址分配调用栈。
在应对 Crash 问题时,除了疑难问题的排查,还有线上线下的长效应对机制。线下有 asan 自动化测试、灰度阶段的 monkey 自动化测试、集成阶段启动崩溃自动化测试等;线上则通过安全气垫、安全模式、coredump 等进行应对。
WatchDog常见的成因有文件 IO、 络 IO、CPU 密集、主线程和子线程共用锁等。对应的解决方案通常包括放入子线程, 业务逻辑适配回调形式,优化锁的粒度等。
朱峰老师对每一种解决思路和工具进行了针对性的讲解。
展望未来,抖音 iOS 应用的稳定性优化还将从框架、流程、静态动态分析等层面做出更多的探索和努力,为超大型 App 的建设保驾护航。朱峰老师最后鼓励大家,要永远保持对底层技术的兴趣和不断探索的热情,也不要对自己的成长设限。
每位讲师的分享结束后,在线观众纷纷通过评论区、弹幕与讲师互动交流。5 位老师都结合自己的专业方向与实践经验,耐心、细致地做出了针对性解答。
至此,第三期字节跳动技术沙龙圆满结束。
如何获取 PPT 和回放视频/h2>
你希望在今后的沙龙中听到哪些主题的分享期待看到哪位技术专家分享自己的实践经验迎在文章下方留言,说出你的心声~ 第四期字节跳动技术沙龙预计于3 月份举行,让我们共同相约春暖花开时!
文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览92138 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!