iOS安装包瘦身小记

闲散心如月,风光好自知css

原文连接html

1、安装包组成分析

一、组成状况

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

  • 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 包组成一致
二、组成分析
  • 通常来讲,可执行文件、图片资源(asset.car)和动态库的占比最大,若是是Swift和OC混编,可执行文件比纯OC大不少
  • 从优化的效果上看,优化图片资源的ROI比较大,若是是首次优化,建议从图片资源的优化开始。
  • 项目中使用Swift,会增长安装包大小,由于FrameWork中会加入为了支持 Swift 的动态库集合,若是纯Swift项目,不会引入这些东西。

2、资源文件优化

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

一、优化手段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实现图片资源的瘦身web

  • 在项目中引入图片时候,直接在 Assets.xcassets中添加就能够(资源文件用Asset Catalog管理),这样能使用到App Slicing功能,这样当用户从App Store上下载App时,能够只下载适用于其设备的App架构版本和所需资源,从而减小App所占的空间。
  • 在实践中发现,有的新同窗在Assets.xcassets中引入@1x的图片,iPhone手机目前须要的@2x和@3x图片,因此@1x的图片显然是不须要的。
  • 在实践中还发现,有的图片资源游离在Assets.xcassets以外,这些能够考虑是否能够放入Assets.xcassets中(大部分状况下是能够放入的)
二、优化手段2:Xcode编译项
  • 由于绝大部分引入的图片是PNG格式,Xcode 提供的给咱们两个编译选项来帮助压缩 PNG 资源:后端

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

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

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

三、优化手段3:清理无用的资源
  • 及时清理不使用的图片资源。使用相似LSUnusedResources 清理旧的图片文件。
  • LSUnusedResources的思路是,先获取图片文件(imageset, jpg, png, gif)集合A,而后搜索代码文件中全部字符串名称获得B,而后从A集合中排除集合B就获得未使用的图片资源。
四、优化手段4:图片文件去重
  • 遍历图片文件,计算每一个文件的MD5值,而后以MD5值为key,文件路径存入key对应的数组;
  • 遍历字典values,将value的数组大小大于1的路径输出,这样就找到重复图片的路径了。
五、优化手段5:更适合的图片格式
  • iconfont代替项目中纯色小图标,也省去不少@2x和@3x的图片切图。
  • PNG切图的替换方案,如PDF矢量图来代替大部分简单的png切图;而后在代码中本身解码并展现出来,一套PDF矢量图能够等效大部分2x和3x的png图片;
  • 网络图片选择压缩比更好的图片格式,如webp

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

3、可执行文件优化

一、优化手段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:去除符号信息
  • 可执行文件中的符号:程序中的全部的变量、类、函数、枚举、变量和地址映射关系,以及一些在调试的时候使用到的用于定位代码在源码中的位置的调试符号,符号和断点定位以及堆栈符号化有很重要的关系。

  • 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 标准库是会打进目标文件的。

三、优化手段3:BitCode
  • Bitcode能够做为中间产物一块儿提交AppStore。包含Bitcode配置的程序将会在AppStore上被编译和连接。Bitcode容许苹果在后期从新优化咱们程序的二进制文件,而不须要咱们从新提交一个新的版本到AppStore上。

  • 开启 BitCode 以后编译器后端(Backend)的工做都由 Apple 接管了。因此假如之后苹果推出了新的 CPU 架构或者之后 LLVM 推出了一系列优化,咱们也再也不须要为其发布新的安装包了。

  • 工程开启 BitCode 以后必需要求全部打进 Bundle 的 Binary 都须要支持 BitCode,也就是说咱们依赖的静态库和动态库都是含有 BitCode 的,否则就会打包失败。对于 Cocoapods 等源码管理工具来管理的依赖库来讲操做会比较简单,咱们只须要开启 Pods 工程中的 BitCode 就行。可是对于一些三方的闭源库,咱们就无能为力了。

  • 开启 BitCode 以后,因为最终的可执行文件是 Apple 自动生成的,同时产生新的符号表文件,因此咱们使用本来打包生成的 dSYM 符号化文件是没法完成符号化的。因此咱们须要在上传至 App Store 时须要勾选 Include app symbols for your application to receive symboilcated crash logs from Apple:勾选以后 Apple 会给咱们生成 dSYM,而后就能够在 Xcode -> Organizer 或者 iTunes Connect 中下载对应的 dSYM 来进行符号化了。

四、优化手段4:清除无用代码
  • Dead Code Stripping:Xcode 默认会开启此选项,C/C++/Swift 等静态语言编译器会在 link 的时候移除未使用的代码,可是对于 Objective-C 等动态语言是无效的。由于 Objective-C 是创建在运行时上面的,底层暴露给编译器的都是 Runtime 源码编译结果,全部的部分应该都是会被判别为有效代码。

  • 扫描查找无用代码:基本思路都是查找已经使用的方法/类和全部的类/方法,而后从全部的类/方法当中剔除已经使用的方法/类剩下的基本都是无用的类/方法,可是因为 Objective-C 是动态语言,可使用字符串来调用类和方法,因此检查结果通常都不是特别准确,须要二次确认。目前市面上的扫描的思路大体能够分为 3 种:

    • 基于 Clang 扫描
    • 基于可执行文件扫描
    • 基于源码扫描
  • 及时下线不须要的功能,如完成使命的ABTest代码、被产品抛弃的功能代码等。

  • 移除不须要的系统库和第三方库。

五、优化手段5:代码重构
  • 功能合并:类似功能的代码,只需维护一份就能够了。如定制通用UI组件,你们能够有相似需求,能够给通用UI组件的开发提,不必本身单独实现。

End

一、优化以后
  • 保持良好的开发习惯。及时清理无用代码和无效库

  • 持续关注安装包大小的变化,

  • 按期Review安装包大小变化

  • 建议预警机制,监控每一个版本的体积大小,体积图片忽然变大,要去找缘由。

二、参考资料

iOS App 瘦身实践总结

iOS 安装包瘦身(上篇)

iOS 安装包瘦身(下篇)

相关文章
相关标签/搜索