iOS 性能优化(二)安装包瘦身

目录

前言

一、安装包组成

二、资源瘦身优化

2.1 无用资源删除

2.2 资源压缩

2.3 图片管理方式

2.4 动态下载资源

三、可执行文件优化

3.1 找到方法和类的全集:Link Map 文件分析

3.2 找到已使用的方法和类: Mach-O 文件

3.3 使用AppCode

四、编译选项优化

总结


前言

随着版本迭代和业务的堆积,安装包会越来越大,安装包变大也带来了其他隐患,比如之前在App Store下载的应用超过150MB时,是无法使用流量下载的,只能连接到无线局域网下载。虽然现在可以设置允许所有App使用蜂窝数据下载,但是有个“超过200MB时请求许可”的选项可能是默认勾选的,而且对流量和手机存储空间敏感的用户,有时候安装包的大小就决定了是否拥有这个用户,所以,对于安装包的瘦身是App发展和优化过程中不可避免的重要一步。

一、安装包组成

iOS的安装包就是ipa,把一个ipa文件将后缀.ipa修改为.zip,然后将其解压出来,在Payload中的.app 选择显示包内容,就可以查看里面的资源文件。

.app 里面的主要内容

  • _CodeSignature:存放文件的 hash 列表。里面有一个文件 CodeResources ,这个文件是一个属性列表,包含 bundle 中所有其他文件的列表。这个属性列表只有一项 files,这是一个字典,键是文件名,值通常是 Base64 格式的散列值。如果键表示的文件是可选的,那么值本身也是一个字典,这个字典有一个 hash 键和一个 optional 键(布尔值 true)。它的作用是用来判断一个应用程序是否完好无损,能够防止不小心修改或损坏资源文件。

    iOS 性能优化(二)安装包瘦身_第1张图片

  • 一些.bundle文件:bundle是一种标准化的层次结构,保存了可执行代码以及代码所需要的资源。bundle文件可以理解为一个资源包,用于存储图片、音频、文本、nib文件等,方便在其他项目中引用包内的资源。bundle包是静态的,不参与编译,也就意味着,bundle 包中不能包含可执行的文件。它仅仅是作为资源,被解析成为特定的二进制数据。从.app的包里可以看到,.bundle文件基本上都是一些SDK制作的。
  • Assets.car:把放在Assets.xcassets中的图片(除了AppIcon和LaunchImage,这两种图片是直接放在包中的)打包后统一压缩成一个Assets.car的文件,减小包的大小。
  • 一些.nib文件:使用xib创建的文件。
  • .plist:一些属性列表文件。
  • Frameworks:Framework 是一种打包方式,将库的二进制文件,头文件和有关的资源文件打包到一起,方便管理和分发。
  • 一些.png、.jpg、.mp3、.mp4等形式的图片和音视频资源。

二、资源瘦身优化

资源瘦身主要是去掉无用资源压缩资源,资源包括图片音视频文件配置文件等,其中图片资源应该是用的最多的。无用资源是指资源在工程文件里,但没有被代码引用。

2.1 无用资源删除

相关业务或模块移除后,对应的图片资源没有删除,造成安装包里面积累很多无用图片,清理的办法也比较简单,就是根据图片的名字在Xcode里全局搜索,如果没有搜到可能就是没有用到的图片,但是并不完全肯定,也有代码里有可能是通过字符串拼接的方式使用了图片。

查找并删除这些无用的图片资源流程是这样的

  1. 查找:使用find命令获取选定的目录下的所有指定类型的资源文件(比如png、jpg、gif等)。
  2. 匹配:使用正则匹配在代码中使用到的图片名,可以设置匹配规则,比如为了方便循环创建,这样命名的@"icon_%d"。
  3. 删除:所有的资源文件减去用到的资源文件就是无用的资源文件了,对这些无用的资源再确认一下删除就可以了。

推荐一个好用的开源工具 LSUnusedResources,使用起来很简单,搜索速度和匹配的准确性也很高。

除了图片资源外,音视频资源,像.json、plist、README.md 等这样的无用文件也可以删除掉。

2.2 资源压缩

对于有用的资源文件,可以通过无损压缩减少占用空间。尽量使用8-bit的PNG图片,比32-bit的图片能减少4倍的压缩率。由于8-bit的图片支持最多256种不同的颜色,所以8-bit的图片一般只应该用于一小部分的颜色图片。例如灰度图片最好使用8-bit。

2.3 图片管理方式

工程中的图片资源主要有两个方式管理,一种是在项目中添加文件夹存放,另一种是放在Assets.xcassets管理。推荐使用Assets.xcassets管理,因为它会把里边的所有 png 格式的图片打包成一个Assets.car文件,压缩比率比文件夹管理图片要高,而且可以根据不同的设备,不同的分辨率设置相应的图片。

2.4 动态下载资源

有些非必要的文件资源可以放在服务器,结合本地缓存策略,比如主题、皮肤、音乐这样的资源。

三、可执行文件优化

App 安装包主要是由资源文件和可执行文件(Mach-O)组成的,可执行文件大小是由代码量决定的。通常情况下,对可执行文件进行瘦身,就是找到并删除无用代码的过程。方法和图片资源清理类似:先找出方法和类的全集,再找到使用过的方法和类,取二者的差集就得到无用代码,人工二次确认后删除。

3.1 找到方法和类的全集:Link Map 文件分析

Xcode build产生的Link Map文件能比较直观的反映出程序各部分的文件大小情况,对于减少包体积很有帮助。

获取 LinkMap :将 Build Setting 里的 Write Link Map File 设置为 Yes,然后指定 Path to Link Map File 的路径就可以得到每次编译后的 LinkMap 文件了。我们只修改一下生成的 Link Map文件的路径就可以了,后缀名不要修改。

iOS 性能优化(二)安装包瘦身_第2张图片

LinkMap 文件分为三部分:Object files、Section 和 Symbols。

  • Object files:代码工程中所有文件编译后的目标文件.o;
    iOS 性能优化(二)安装包瘦身_第3张图片
  • Section:描述了代码段在生成的 Mach-O 里的偏移位置和大小,包括代码段(__TEXT)和数据段(__DATA)的分布情况;
    iOS 性能优化(二)安装包瘦身_第4张图片
  • Symbols:符号相关信息,会列出每个方法、类、block,以及它们的大小,第一列Address 是在文件中的偏移位置,第二列Size 是大小,第三列File 是对应上面Object files 中的文件编号,第四列Name 是文件名。可以看到黄色框框部分跟上图Object files 是对应的。
    iOS 性能优化(二)安装包瘦身_第5张图片

通过对 LinkMap 的分析,我们不但可以统计出所有的方法和类,还能够清晰地看到代码所占包大小的具体分布,从而有针对性地对代码进行优化。对Symbols的分析还可以通过方法的二进制重排来提升冷启动速度(本篇不做过多介绍)。

3.2 找到已使用的方法和类: Mach-O 文件

Mach-O是Mach Object的缩写,是Mac/iOS上用于存储程序、库的标准格式。常见的Mach-O文件比如iOS开发好的代码打包好后就是Mach-O格式的文件。​​​Xcode编译完工程会生成一个可执行程序,查找方式也简单,首先在Xcode的Preferences里找到这个路径:

iOS 性能优化(二)安装包瘦身_第6张图片

在这个文件夹下找到对应的工程文件名/Build/Products/Debug,进入这个目录下,就可以找到我们的可执行文件了。

iOS 性能优化(二)安装包瘦身_第7张图片

iOS 的方法都会通过 objc_msgSend 来调用。而objc_msgSend 在 Mach-O 文件里是通过 __objc_selrefs 这个 section 来获取 selector 这个参数的。所以,__objc_selrefs 里是被调用了的方法,__objc_classrefs 里是被调用过的类,__objc_superrefs 是调用过 super 的类。通过 __objc_classrefs 和 __objc_superrefs,我们就可以找出使用过的类和子类。可以通过MachOView来查看 Mach-O 文件里的信息。

对比Link Map文件就可以找出没有用到的类和方法了,但是Objective-C 是动态语言,方法可以在运行时动态调用,通过这种方法找到的无用代码还需人工确认才可以删除。

3.3 使用AppCode

如果不想这么麻烦地去分析对比,推荐一个好用的工具 AppCode,代码量不是很大时,AppCode通过静态分析可以快速帮我们找出没有用到的文件和方法,使用方式是在 AppCode 里选择 Code->Inspect Code 就可以进行静态分析。

分析结果也是清晰明了,包括:

Not implemented methods:没有实现的方法;

Key value coding:KVC相关,比如使用KVC访问了@private修饰的成员变量;

Unused class:没有用到的类;

Unused import statement:无用类引入声明;

Unused instance variable :无用的实例变量;

Unused method:没有用到的方法;

Unused property :没有用到的属性;

Unused parameter :无用参数;

Unused local variable :无用的局部变量;

Unused value :无用的值;

Unused macro :无用的宏;

Unused global declaration :无用全局声明。

iOS 性能优化(二)安装包瘦身_第8张图片

但是检测结果并不是完全可靠,只是为我们优化代码提供参考方向,最好还是人工确认一下,不要完全相信工具。

四、编译选项优化

Xcode 支持编译器层面的一些优化优化选项,可以让我们在更快的编译速度、更小的二进制和更快的执行速度之间自由选择想要的优化程度。

  1. Strip Linked Product、Make Strings Read-Only、Symbols Hidden by Default设置为YES,目前Xcode已经默认打开的,老项目注意检查;
  2. 去掉异常支持,Enable C++ Exceptions、Enable Objective-C Exceptions设置为NO,Other C Flags添加-fno-exceptions;
  3. Strip Debug Symbols During Copy设置为YES,这个是将那些拷贝进项目包的三方库、资源或者 Extension 的  Debug Symbol 去除掉。这个选项没有前置条件,只需在Release模式下开启,否则就不能对三方库进行断点调试和符号化了;
  4. Build Settings -> Optimization Level有几个编译优化选项,release版应该选择Fastest, Smalllest,这个选项会开启那些不增加代码大小的全部优化,并让可执行文件尽可能小;
  5. Enable BitCode设置为YES;

总结

业务的不断堆积迭代,总会产生一些无用的资源,所以安装包瘦身要定期清理这些无用文件和代码。除了自己写的代码外对用到的三方库也可以做检查优化,比如有的库还支持Mac的i386和x86_64架构处理器,这部分代码就可以根据实际情况删除;对比SDK和三方库的导入对ipa大小的影响,使用满足需求的较小库;项目中重复方法抽离出来等,这些优化可能对安装包的大小影响很小,但是积少成多,形成对ipa大小敏感的习惯也能帮助我们写出效率更高的代码。对安装包瘦身的探索还有很长的路走,本文也只是列举了一些常用的瘦身方案,对于庞大的项目,操作起来也是如履薄冰,还好在没有影响业务和正常功能使用的情况下,我们的ipa减少了大约15MB,优化之路还在继续,以后还会补充更多的方案。

你可能感兴趣的:(iOS开发,ios)