iOS安装包瘦身小记

​ 将IPA包修改后缀名为ZIP,解压缩后,获取payload中的App文件,查看App文件的内容,你会发现该文件主要包含以下内容

  • Exectutable : 可执行文件
  • Resources :资源文件
    • 图片资源: Assets.car /bundle/png/jpg 等
    • 视频/音频资源:mp4/mp3 等
    • 静态网页资源:html/css/js 等
    • 视图资源:xib/storyboard 等
    • 其他:文本/字体/证书 等
  • Framework
    • SwiftSupport: libSwiftxxx 等一系列 Swift 库
    • 其他依赖库:Embeded Framework
  • Pulgins :Application Extensions
    • appex:其组成大致与 ipa 包组成一致

2、组成分析

  • 一般来说,可执行文件、图片资源(asset.car)和动态库的占比最大,如果是Swift和OC混编,可执行文件比纯OC大很多
  • 从优化的效果上看,优化图片资源的ROI比较大,如果是首次优化,建议从图片资源的优化开始。
  • 项目中使用Swift,会增加安装包大小,因为FrameWork中会加入为了支持 Swift 的动态库集合,如果纯Swift项目,不会引入这些东西。

二、资源文件优化

​ 理论上,资源文件包括:图片**、 视频 、**音频和字体等;实际上,视频和音频文件一般不会集成到安装包中,在安装包中的资源文件主要是图片。

1、优化手段1:App Slicing

  • iOS 9之后提供了App Thinning三件套: App SlicingOn Demand ResoucesBitcode
App Thinning 理想 现实
App Slicing 将App Bundle资源根据不同的设备特性分为不同的版本。对于图片资源,会根据设备所需图片分辨率不同分发给对应设备所需对应的图片资源。 主要是图片资源的Slicing,我们有自己的方案,没有采用
On Demand Resources App的资源只有要使用时才下载,如果其他资源需要空间这些资源可以被移除 更适合游戏类App,项目没有使用
Bitcode Bitcode可以作为中间产物一起提交AppStore。包含Bitcode配置的程序将会在AppStore上被编译和链接。Bitcode允许苹果在后期重新优化我们程序的二进制文件,而不需要我们重新提交一个新的版本到AppStore上 使用BitCode的要求所有代码都支持BitCode,改动项目较大,没有使用

说明:可以充分利用App Slicing实现图片资源的瘦身

  • 在项目中引入图片时候,直接在 Assets.xcassets 中添加就可以(资源文件用 Asset Catalog 管理),这样能使用到 App Slicing 功能,这样当用户从App Store上下载App时,可以只下载适用于其设备的App架构版本和所需资源,从而减少App所占的空间。
  • 在实践中发现,有的新同学在 Assets.xcassets 中引入@1x的图片,iPhone手机目前需要的@2x和@3x图片,所以@1x的图片显然是不需要的。
  • 在实践中还发现,有的图片资源游离在Assets.xcassets之外,这些可以考虑是否可以放入 Assets.xcassets 中(大部分情况下是可以放入的)

2、优化手段2:Xcode编译项

  • 因为绝大部分引入的图片是PNG格式,Xcode 提供的给我们两个编译选项来帮助压缩 PNG 资源:

  • Compress PNG Files:设置为YES,打包的时候自动对图片进行无损压缩,使用的工具为pngcrush,压缩比还是相当高的,比较流行的压缩软件ImageOptim 也是使用 pngcrush 进行压缩 PNG 的。

  • Remove Text Medadata From PNG Files:设置为YES,能帮助我们移除 PNG 资源的文本字符,比如图像名称、作者、版权、创作时间、注释等信息。

  • 引入项目的PNG资源自动被 Xcode 进行压缩了,但是如果是使用Bundle管理的资源,不会被Xcode压缩,可以使用tinypng压缩。

3、优化手段3:清理无用的资源

  • 及时清理不使用的图片资源 。使用类似 LSUnusedResources 清理旧的图片文件。
  • LSUnusedResources的思路是,先获取图片文件(imageset, jpg, png, gif)集合A,然后搜索代码文件中所有字符串名称得到B,然后从A集合中排除集合B就得到未使用的图片资源。

4、优化手段4:图片文件去重

  • 遍历图片文件,计算每个文件的MD5值,然后以MD5值为key,文件路径存入key对应的数组;
  • 遍历字典values,将value的数组大小大于1的路径输出,这样就找到重复图片的路径了。

5、优化手段5:更适合的图片格式

  • iconfont 代替项目中纯色小图标,也省去很多@2x和@3x的图片切图。
  • PNG切图的替换方案,如 PDF矢量图来代替大部分简单的png切图 ;然后在代码中自己解码并展示出来,一套PDF矢量图可以等效大部分2x和3x的png图片;
  • 网络图片选择压缩比更好的图片格式,如webp

说明:PNG切图不可能被完全替换,在表现颜色丰富图片时候,PNG效果很不错,其他详见浅谈iOS图片优化

三、可执行文件优化

1、优化手段1:编译器优化

  • Xcode 支持编译器层面的一些优化优化选项,可以让我们介于 更快的编译速度更小的二进制大小更快的执行速度 之间自由选择想要进行的优化粒度;

  • 在Xcode中,使用 Clang 来编译Objective-C,可以在 Build Setting -> Apple Clang - Code Generation -> Optimization Level 设置,Release下为 Fastest Smallest[-Os] 。编译器会开启除了会明显增加包大小以外的所有优化选项;

  • 在Xcode中,使用 SwiftLang 来编译Swift语言,同样也是基于 LLVM 后端的。Xcode 9.3 版本之后可以在Build Setting -> Optimization Level 设置,Release下为 Optimize for Speed[-O] ,这可能会增加安装包大小

No optimization[-Onone]:不进行优化,能保证较快的编译速度。
Optimize for Speed[-O]:编译器将会对代码的执行效率进行优化,一定程度上会增加包大小。
Optimize for Size[-Osize]:编译器会尽可能减少包的大小并且最小限度影响代码的执行效率
复制代码

说明:Xcode 9.3/Swift4.1编译器不是特别稳定,特别是开启 Osize 选项之后,编译器很多情况下会莫名其妙的崩溃(Segmentation fault),目前放弃 [-Osize],选择[-O]

2、优化手段2:去除符号信息

  • 可执行文件中的符号:程序中的所有的 变量、类、函数、枚举、变量和地址映射关系 ,以及一些在调试的时候使用到的用于定位代码在源码中的位置的调试符号,符号和断点定位以及堆栈符号化有很重要的关系。

  • Strip Style表示的是我们需要去除的符号的类型的选项,可以在Build Setting -> Strip Style设置, Release下为 All Symbols ,其分为三个选择项:

All Symbols: 去除所有符号,一般是在主工程中开启。

Non-Global Symbols: 去除一些非全局的 Symbol(保留全局符号,Debug Symbols 同样会被去除),链接时会被重定向的那些符号不会被去除,此选项是静态库/动态库的建议选项。

Debug Symbols: 去除调试符号,去除之后将无法断点调试。
复制代码

说明:iOS 的调试符号是 DWARF 格式的,使用 Xcode 编译打包的时候会先通过可执行文件的 Debug Map 获取到所有对象文件的位置,然后使用 dysmutil 来将对象文件中的 DWARF 提取出来生成 dSYM 文件。

  • Strip Linked Product去除不必要的符号信息,去除了符号信息之后我们就只能使用 dSYM 来进行符号化了,所以需要将 Debug Information Format 修改为 DWARF with dSYM file。Release下为YES。

  • Strip Linked Product 选项在 Deployment Postprocessing 设置为 YES 的时候才生效,而在 Archive 的时候 Xcode 总是会把 Deployment Postprocessing 设置为 YES,Debug下,Deployment Postprocessing 设置为 NO。

  • Strip Debug Symbols During Copy将那些拷贝进项目包的三方库、资源或者 Extension 的 Debug Symbol 去除掉,在Build Settings -> Strip Debug Symbols During Copy设置,Release下设置为YES。

  • Cocoapods 管理的动态库(use_framework!)的情况就相对要特殊一点,因为 Cocoapods 中的的动态库是使用自己实现的脚本 Pods-xxx-frameworks.sh 来实现拷贝的,所以并不会走 Xcode 的流程,当然也就不受 Strip Debug Symbols During Copy 的影响。当然 Cocoapods 是源码管理的,所以只需要将源码 Target 中的 Strip Linked Product 设置为 YES 即可。

  • Strip Swift Symbols能帮助我们移除相应 Target 中的所有的 Swift 符号,这个选项也是默认打开的。Strip Swift symbols需要在打包的发布选项中勾选(默认勾选),在Swift ABI 稳定之前,Swift 标准库是会打进目标文件的。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章