• 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
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    在北京的灯中,有一盏是我家的。这个梦何时可以实现?哪怕微微亮。北京就像魔鬼训练营,有能力的留,没能力的走……
  • 相关阅读:
    【Html】Clipboard.js 实现点击复制,剪切板操作
    【转】【Python】python使用urlopen/urlretrieve下载文件时出现403 forbidden的解决方法
    【Html】div 加载 html页面的方法
    【WPF】创建文本字符串的路径PathGeometry
    【WPF】自定义鼠标样式
    Linux 错误记录
    微信开放平台代公众号管理
    微信开放平台获取授权公众号的流程
    vue-router "path" is required in a route configuration
    最大连接数“65535”的误解
  • 原文地址:https://www.cnblogs.com/huangzs/p/15124271.html
Copyright © 2020-2023  润新知