随着项目开发的不断迭代,工程越来越大,ipa安装包也越来越大,这非常不利于App的推广工作。
我们的项目比较老,大概有6年的历史了,团队维护人员的不断更替,给项目留下了很多诟病,ipa过大就是其中之一,曾经达到了110多M。由于我们的App由三个团队共同开发,我们为了App的瘦身工作也忙活了好一阵子,非常不容易。
编译选项优化
- BuildSettings->Optimization Level,Xcode默认设置为“Fastest ,Smallest”,保持默认即可。
- Build Settings-> Linking->Dead Code Stripping 设置成 YES
- Deployment Postprocessing 设置成YES
- Strip Linked Product 设置成YES
- 工程的Enable C++ Exceptions和Enable Objective-C Exceptions选项都设置为NO。手动管理异常。
- symbols hidden by default选项设置为YES。
- 所有没有使用C++动态特性的lib库(搜索工程没有使用dynamic_cast关键字) Enable C++ Runtime Types 选项设置为NO。
资源文件的瘦身工作
我们都知道,ipa是由 资源文件
和 可执行文件
构成。资源文件包括 图片
、 音频
、 视频
、 字体
、 plist
、 text
、 md
、 cmake
、 License
等等的非代码文件。
图片资源压缩
首先,我们要排除那些我们不需要的资源文件,最简单的方式就是全局去搜这个资源的文件名称。由于资源文件是ipa size中占比较大的,所以我们应当考虑这个资源(比如字体,视频等)是否真的有必要加入到工程中。(或者可以考虑网络下载的方式?)
工程中最多的资源文件可能就是图片了,我们可以把打好的ipa包解开,按文件大小排个序,看看哪些资源文件是占用较大的,如果工程历史比较久远,那么一定存在着很多没有使用的图片却引在了工程中,如何把这些图片筛选出来,是个问题。
可以使用脚本来查,但是缺点也很明显,慢,不准确。也可以使用LSUnusedResources.app来查找,他的速度很快,但是缺点也很明显。比如我们有一组图片,所以我们使用图片名称字符串的时候采用的是图片名称的拼接,这种情况LSUnusedResources.app是检测不到的。对于检索出来的结果,还需要我们仔细甄别。
下载: LSUnusedResources.app.zip
其次,我们要做的就是必要资源的压缩工作了。一般情况下我们都会使用PNG格式的图片,相比于JPG来说,它支持完整的透明通道。一般会提供@2x和@3x的图片,如果对视觉要求不是特别高的话,可以只提供@2x的图片,但是在5.5-inch的屏幕上会放大1.5倍。我们一般是在 tinypng.com 压缩PNG图片,压缩效率还是挺高的,通常会降低一个数量级,但是每次只能压缩20张图片。不过也可以使用 TinyPNG Mac客户端 来压缩图片,需要注册一个API Key。
使用Icon Font
每个iconfont只是一小段文本,size要比图片形式的icon小一个数量级,我们可以像使用字体一样来使用图片。
生成iconfont需要 矢量图
。一些网站提供生成iconfont的服务,比如icomoon和Fontello。阿里巴巴矢量图标库和easyicon提供大量优秀的矢量图。
icomoon和Fontello均可以通过导入SVG图标或者选择网站自身提供的图标来生成iconfont。值得一提的是,icomoon还可以生成PNG,PDF,CSH等格式。
在生成的文件夹中,可以找到扩展名为 .ttf
的字体集文件。
FontAwesomeKit
using-icon-font-in-ios
使用WebP
WebP是Google推的方案,无损压缩后的WebP比PNG少了45%的size,即使PNG经过其他工具压缩之后,WebP还是可以减少28%的size。SDWebImage实现了加载WebP格式图片的功能,但是没有做缓存功能,可能需要我们自己来实现了。
使用PDF矢量图
Xcode6以后支持了矢量图,但是PDF矢量图貌似并不能达到瘦身的目的,使用矢量图编译打包后在ipa内是一个car文件,可以用工具解压出里面的恩图片,会发现PDF转成了 @1x、@2x、@3x 3套图片。不过iOS9以后苹果提供了App Thinning
方案(App Slicing、on-demand resources、Bitcode)。
图片资源优化
- 不透明的大图片压缩成JPG格式
- 大背景图如果一定要是PNG格式,可以把它保存为WebP格式,不过要注意有没有太大失真情况
- 如果可以,尽量使用网络加载图片
- 类似皮肤功能,使用网络下载皮肤包
- 避免使用大量图片的组合帧动画
- 如果图片不是很复杂,使用代码绘制
- 加入到
Assets.xcassets
中,只支持PNG格式的图片,图片只支持[UIImage imageNamed]
的方式实例化,但是不能从Bundle
中加载
可执行文件的瘦身
首先我们通过LinkMap
来查看编译后,我们各个类库的空间占用情况。我们先在Build setting中把LinkMap
的开关打开
正如上图所示,只需要把Write Link Map File
设置为YES
,就可以了。其存储目录为/Users/用户名/Library/Developer/Xcode/DerivedData/项目名称/Build/Intermediates/项目名称.build/Debug-iphonesimulator/项目名称.build/项目名称-LinkMap-normal-x86_64.txt
然后可以使用一个js脚本来把LinkMap
中的内容做个排序:
node linkmap.js filepath -hl
filepath
即LinkMap.txt的path
根据这个排序列表,我们可以有针对性的去优化占用较大的类库,如果不是必要的类或者第三方库,要么寻找轻量级替代方案,要么就删了吧。
查找工程中未使用的类
这里有一个脚本工具
python py文件目录 Xcode工程文件根目录
会将结果以.txt
的方式存储在Xcode工程文件目录中,但是需要注意的是,由于.a
以及FrameWork
的存在,还有注释
等客观因素存在,扫描出来的结果仅供参考,还需要仔细甄别。
精益求精
- 删除代码中的无用的函数,空函数,默认方法,重复代码
- 如果不需要系统生成getter和setter方法,尽量不使用@property
- 使用C函数进行一些类封装
- 插件化:Lua、JSPatch等等
- 使用MRC
- 减少类名方法名长度
- 删除冗余字符串
查看ipa在Appstore中的大小
我们做了一圈优化之后,打出的ipa包也比之前小了不少,但是我们怎么看到在Appstore中实际减少到了多少呢?
我们可以先把ipa包提交到Appstore,并不需要提交审核
- 登录
iTunes Connect
- 选择
我的App
- 进入
活动
- 选择
所有构建版本
- 选择刚刚上传的构建版本
- 点击
App Store 文件大小
这样就看到了我们App在各个机型上的空间占用情况,这个还是非常准确的。
总结
安装包瘦身的工作到此也告一段落了,由于我们是多个团队共同开发,所以瘦身工作并不是我们一方的事情,需要多方面共同努力,包括产品,设计师等。减肥之后,更重要的是维持一个良好的身材,为此我们也定了一些规则,与设计师之间的出图规则,与产品之间的一些功能调整的规则,以及规定兄弟团队给我们提供.a
或者FrameWork
的大小限制等等。同时我们本身也要提高代码的整洁程度,这样关于安装包的大小控制,就有了一个良性的发展。