ipa包体分析脚本

主要介绍一下 https://github.com/sunyanyan/ipaAnalyze 里的脚本。
该脚本输入ipa文件以及对应linkmap文件,输入该ipa各类资源的大小、以及各个模块的大小。

ipa内部文件

iOS打包出来的ipa,本质上是一个压缩包,所以可以将.ipa的后缀改为.zip,然后进行解压缩,之后会得到一个Payload文件夹,里面又一个xxx.app的文件,这个xxx.app就是包含所有文件的包了,选中xxx.app,右键显示包内容,即可看到里面具体包含的东西了,大致如下

  • _CodeSignature: ipa包签名文件
  • .lproj: 语言文件
  • Frameworks: 第三库、SwiftSupport库
  • Plugins: App创建的扩展,比如:Widget、Push、分享
  • Assets.car: 由Assets.xcassets生成的资源文件,里面包含各种分辨率的图片
  • embedded.mobileprovision:证书配置文件
  • Info.plist: 项目配置
  • exec格式的xxx: 可执行包
  • 其它资源文件
    • .mp3格式的文件
    • .html的文件
    • .json的文件
    • .png或者.jpg的文件

资源分类

脚本对于资源分类 简单粗暴根据文件后缀名分类:

模块分类

根据linkmap文件分析,Link Map 中的包含的区块内容有:

1
2
3
4
5
Path: Link Map 文件对应的可执行二进制文件
Arch: 编译生成的可执行二进制文件的 CPU 架构
Object files: 每一个源代码文件编译后生成的对象文件列表
Sections: 在最终可执行二进制文件中不同类型代码所在的节列表
Symbols: 所有代码中的函数、变量、字符串等实际生成的符合列表

我们不用关心 Sections 中的内容,因为它只是对应到不同符号存储的位置,不影响它实际占用的体积。我们需要关注 Object files 和 Symbols 这两块内容,因为它实际包含了在可执行二进制文件中占有体积的部分。

其中 Object files 包含了每个代码文件编译出来的对象文件路径,以及它的编号。每个对象文件的编号,将在后续符号列表中被引用,从而标识那些符号是由哪个代码文件中的代码生成的。

例如上面示例中的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
......
# Sections:
# Address Size Segment Section
0x100002CC0 0x0000CAF2 __TEXT __text
0x10000F7B2 0x000000C0 __TEXT __stubs
0x10000F874 0x00000150 __TEXT __stub_helper
0x10000F9C4 0x00002BD0 __TEXT __objc_methname
......
# Symbols:
# Address Size File Name
0x100002CC0 0x00000080 [ 1] -[LMWindowController windowDidLoad]
0x100002D40 0x00000059 [ 1] -[LMWindowController windowShouldClose:]
0x100002DA0 0x00000170 [ 2] -[ViewController viewDidLoad]
0x100002F10 0x00000070 [ 2] -[ViewController setRepresentedObject:]
0x100002F80 0x00000140 [ 2] -[ViewController saveURL:forKey:]
0x1000030C0 0x00000220 [ 2] -[ViewController retriveURLForKey:]
0x1000032E0 0x00000120 [ 2] -[ViewController chooseLinkMap:]
......

在符号列表中,我们就可以获取到每个类的每个函数的大小,再通过对象文件编号进行关联,就可以将每个代码文件所生成的指令在最终可执行二进制文件所占的体积大小统计出来。

最终得到如图输出