IPA的构建原理 iOS

pipeline

既然要构建,那么必然会有一些地方去定义如何构建,对应 Xcode 中的两个配置项:

  • Build Phase:以 Target 为维度定义了构建的流程。可以在 Build Phase 中插入脚本,来做一些定制化的构建,比如 CocoaPod 的拷贝资源就是通过脚本的方式完成的。
  • Build Settings:配置编译和链接相关的参数。特别要提到的是 other link flags 和 other c flags,因为编译和链接的参数非常多,有些需要手动在这里配置。很多项目用的 CocoaPod 做的组件化,这时候编译选项在对应的.xcconfig 文件里。

以单 Target 为例,我们来看下构建流程:

  • 源文件(.m/.c/.swift 等)是单独编译的,输出对应的目标文件(.o)
  • 目标文件和静态库/动态库一起,链接出最后的 Mach-O
  • Mach-O 会被裁剪,去掉一些不必要的信息
  • 资源文件如 storyboard,asset 也会编译,编译后加载速度会变快
  • Mach-O 和资源文件一起,打包出最后的.app
  • 对.app 签名,防篡改

编译

编译器可以分为两大部分:前端和后端,二者以 IR(中间代码)作为媒介。这样前后端分离,使得前后端可以独立的变化,互不影响。C 语言家族的前端是 clang,swift 的前端是 swiftc,二者的后端都是 llvm。

  • 前端负责预处理,词法语法分析,生成 IR
  • 后端基于 IR 做优化,生成机器码

那么如何利用编译优化启动速度呢?

代码数量会影响启动速度,为了提升启动速度,我们可以把一些无用代码下掉。那怎么统计哪些代码没有用到呢?可以利用 LLVM 插桩来实现。

LLVM 的代码优化流程是一个一个 Pass,由于 LLVM 是开源的,我们可以添加一个自定义的 Pass,在函数的头部插入一些代码,这些代码会记录这个函数被调用了,然后把统计到的数据上传分析,就可以知道哪些代码是用不到的了 。

Facebook 给 LLVM 提的order_file的 feature 就是实现了类似的插桩。

链接

经过编译后,我们有很多个目标文件,接着这些目标文件会和静态库,动态库一起,链接出一个 Mach-O。链接的过程并不产生新的代码,只会做一些移动和补丁。

  • tbd 的全称是 text-based stub library,是因为链接的过程中只需要符号就可以了,所以 Xcode 6 开始,像 UIKit 等系统库就不提供完整的 Mach-O,而是提供一个只包含符号等信息的 tbd 文件。

举一个基于链接优化启动速度的例子:

最开始讲解 Page In 的时候,我们提到 TEXT 段的页解密很耗时,有没有办法优化呢?

可以通过 ld 的-rename_section,把 TEXT 段中的内容,比如字符串移动到其他的段(启动路径上难免会读很多字符串),从而规避这个解密的耗时

抖音的重命名方案:

"-Wl,-rename_section,__TEXT,__cstring,__RODATA,__cstring",
"-Wl,-rename_section,__TEXT,__const,__RODATA,__const", 
"-Wl,-rename_section,__TEXT,__gcc_except_tab,__RODATA,__gcc_except_tab", 
"-Wl,-rename_section,__TEXT,__objc_methname,__RODATA,__objc_methname", 
"-Wl,-rename_section,__TEXT,__objc_classname,__RODATA,__objc_classname",
"-Wl,-rename_section,__TEXT,__objc_methtype,__RODATA,__objc_methtype"

复制代码

裁剪

编译完 Mach-O 之后会进行裁剪(strip),是因为里面有些信息,如调试符号,是不需要带到线上去的。裁剪有多种级别,一般的配置如下:

  • All Symbols,主二进制
  • Non-Global Symbols,动态库
  • Debugging Symbols,二方静态库

为什么二方库在出静态库的时候要选择 Debugging Symbols 呢?是因为像 order_file 等链接期间的优化是基于符号的,如果把符号裁剪掉,那么这些优化也就不会生效了

签名 & 上传

裁剪完二进制后,会和编译好的资源文件一起打包成.app 文件,接着对这个文件进行签名。签名的作用是保证文件内容不多不少,没有被篡改过。接着会把包上传到 iTunes Connect,上传后会对__TEXT段加密,加密会减弱 IPA 的压缩效果,增加包大小,也会降低启动速度 (iOS 13 优化了加密过程,不会对包大小和启动耗时有影响)

 

作者:字节跳动技术团队
链接:https://juejin.cn/post/6887741815529832456
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在北京的灯中,有一盏是我家的。这个梦何时可以实现?哪怕微微亮。北京就像魔鬼训练营,有能力的留,没能力的走……
原文地址:https://www.cnblogs.com/huangzs/p/15124271.html