iOS优化IPA包体积大小

随着项目的不断迭代,我们APP的体积也越来越大,这势必造成下载的资源浪费,同时也给新用户下载带来流量的浪费,因此我们决定开始优化我们的IPA的体积,方便用户下载的同时,也剔除代码中的冗余资源和文件,方便后续的持续迭代。

一:资源部分

1.1 删除项目中无用资源

由于项目随着时间的推移,势必项目中会存在一些资源(图片,视频,音频等等)已经弃用或者被替换,但是没有及时去删除,因此我们首先删除这些无用资源。我们采用LSUnusedResources工具。


QQ20201225-171355.png

注意:必须勾选Ignore similar name 选项,去除相似命名规范的文件,防止这些文件被引用,但是在无任何检查的情况下被删除。

1.2 删除项目中1X的图片资源

iOS适配中,图片资源是展示原则:

1X 作用于3GS手机,手机的像素320*480,一个点为一个像素
2X iPhone4开始,尺寸为320x480,但是像素为640x960,即一个点为2个像素,所有需要2X的图片才可以保证页面不失真
3X iPhone6 plus开始,尺寸为414x736,像素为1242x2208,即一个点3个像素,所以需要3X的图片才能保证页面显示良好

作为iPhone4之前的手机,市场占有率基本上可以忽略不计。因此,我们完全有必要删除其中1x的图片资源。

二:压缩资源文件

2.1 压缩图片资源

使用无损压缩,例如 ImageOptimpngquant命令tinypng 等工具,如果涉及有损压缩最好要求设计介入进行资源检查。

本次使用ImageOptim对工程中几乎所有的图片做了一次压缩。在压缩过程中,我们发现,大部分图片都能被压缩到原来的70%左右,个别图片能获得更高的压缩比。但是打包测试后,发现IPA包的大小基本上没有任何变化。

最后在查阅了Xcode打包对于图片的资源的处理发现,在打包过程中,有一个步骤叫做compile asset catalog。在这个步骤中,Xcode会自行对png图片作压缩,并且会压缩成能够快速读取渲染的格式。我们的项目经过ImageOptim的压缩后,在compile asset catalog的过程中,Xcode会用自己的算法重新压缩,而这个”重新压缩“的过程,很可能把我们之前的压缩给覆盖。

经过测试,此类压缩基本上对后续的包体积无任何影响,因此查找其他的压缩方案。

2.2 采用Webp压缩图片资源

Webp 是由 Google 推出的图片格式,有损压缩模式下图片体积只有 jpeg 格式的 1/3,无损压缩也能减小 1/4,可以使用 cwebp 进行格式压缩转换,目前 SDWebImage、Kingfisher 都用支持该格式解析的拓展。进过测试发现压缩还是非常有效的。

从项目中随便取2张图片,进行压缩试验:

iOS优化IPA包体积大小

随着项目的不断迭代,我们APP的体积也越来越大,这势必造成下载的资源浪费,同时也给新用户下载带来流量的浪费,因此我们决定开始优化我们的IPA的体积,方便用户下载的同时,也剔除代码中的冗余资源和文件,方便后续的持续迭代。

一:资源部分

1.1 删除项目中无用资源

由于项目随着时间的推移,势必项目中会存在一些资源(图片,视频,音频等等)已经弃用或者被替换,但是没有及时去删除,因此我们首先删除这些无用资源。我们采用LSUnusedResources工具。

注意:必须勾选Ignore similar name 选项,去除相似命名规范的文件,防止这些文件被引用,但是在无任何检查的情况下被删除。

1.2 删除项目中1X的图片资源

iOS适配中,图片资源是展示原则:

1X 作用于3GS手机,手机的像素320*480,一个点为一个像素
2X iPhone4开始,尺寸为320x480,但是像素为640x960,即一个点为2个像素,所有需要2X的图片才可以保证页面不失真
3X iPhone6 plus开始,尺寸为414x736,像素为1242x2208,即一个点3个像素,所以需要3X的图片才能保证页面显示良好

作为iPhone4之前的手机,市场占有率基本上可以忽略不计。因此,我们完全有必要删除其中1x的图片资源。

二:压缩资源文件

2.1 压缩图片资源

使用无损压缩,例如 ImageOptimpngquant命令tinypng 等工具,如果涉及有损压缩最好要求设计介入进行资源检查。

本次使用ImageOptim对工程中几乎所有的图片做了一次压缩。在压缩过程中,我们发现,大部分图片都能被压缩到原来的70%左右,个别图片能获得更高的压缩比。但是打包测试后,发现IPA包的大小基本上没有任何变化。

最后在查阅了Xcode打包对于图片的资源的处理发现,在打包过程中,有一个步骤叫做compile asset catalog。在这个步骤中,Xcode会自行对png图片作压缩,并且会压缩成能够快速读取渲染的格式。我们的项目经过ImageOptim的压缩后,在compile asset catalog的过程中,Xcode会用自己的算法重新压缩,而这个”重新压缩“的过程,很可能把我们之前的压缩给覆盖。

经过测试,此类压缩基本上对后续的包体积无任何影响,因此查找其他的压缩方案。

2.2 采用Webp压缩图片资源

Webp 是由 Google 推出的图片格式,有损压缩模式下图片体积只有 jpeg 格式的 1/3,无损压缩也能减小 1/4,可以使用 cwebp 进行格式压缩转换,目前 SDWebImage、Kingfisher 都用支持该格式解析的拓展。进过测试发现压缩还是非常有效的。

从项目中随便取2张图片,进行压缩试验:

cwebp -lossless baby_info@3x.png -o ~/Desktop/new.webp
Saving file '/Users/wyz/Desktop/new.webp'
File:      baby_info@3x.png 3KB
Dimension: 51 x 51
Output:    2000 bytes (6.15 bpp)
Lossless-ARGB compressed size: 2000 bytes
  * Header size: 193 bytes, image data size: 1781
  * Precision Bits: histogram=3 transform=3 cache=9
  
cwebp -lossless baby_info@2x.png -o ~/Desktop/new2.webp
Saving file '/Users/wyz/Desktop/new2.webp'
File:      baby_info@2x.png 2KB
Dimension: 34 x 34
Output:    986 bytes (6.82 bpp)
Lossless-ARGB compressed size: 986 bytes
  * Header size: 547 bytes, image data size: 414
  * Lossless features used: PALETTE
  * Precision Bits: histogram=5 transform=5 cache=0
  * Palette size:   235

有了这个工具,确实可以大大的压缩项目中的图片资源。我们从上面的代码中看到,3K的图片可以压缩成2K,2K的最后也可以压缩不到1K,确实效率很高。项目中展示压缩过得图片,基本上看不出有任何变化,证明此压缩方案可行。

尝试删除项目中asset catalog除了启动图和icon的图标外的其他图片,经过压缩从10M左右减少到7M左右,所以看起来效果还是不错的,但是项目中图片访问只能通过bundle中来获取,这个和从asset catalog中读取图片的效率就有待商榷,毕竟asset catalog是Apple推荐的图片资源管理模式。

尝试打包在6和plus上安装时发现,安装包大小竟然一样的大小,并且在6上面的大小和优化之前基本上没有什么变化,甚至比之前的还大,显然这不是我们想要的效果。

最后查看App Store的APP在下载过程中发现,Apple会在设备下载APP是,会根据设备类型,下载IPA中不同的资源,即asset catalog中的图片资源,设备支出2X的图片,它也只会选择asset catalog中所有的2X的图片进行下载,所以我们废弃asset catalog使用后,所有的图片都进行了下载,比之前的包大也就说的过去了,因此看起来这种方法也不可取。

但是作为图片压缩一种相当不错的方式,我们完全可以用在网络图片的下载中使用。

2.3 单色图标使用tint color

Apple在iOS7推出的功能,我们可以读取一个图标,然后给它赋予一个color值,在手机屏幕上它就能显示出相应的效果。tint color适用于对单色图标进行着色,相比于其他精简图标的解决方案,tint color方便、可靠、拥有原生支持。

因此,花费一些时间排查一下简单的相同样式图片,采用tint color的方式来填充颜色,从而起到优化IPA包的效果。

2.4 资源考云端下载

Apple从iOS 9开始引入了On Demand Resource功能,即一部分图片可以被放置在苹果的服务器上,不随着app的下载而下载,直到用户真正进入到某个页面时才下载这些资源文件。

但是考虑到项目最低支持的版本,此方法只能放弃。

三:删除重复文件

我们采用fdupes工具。它是通过对比文件的MD5签名,以及逐字节比较文件来识别重复内容,fdupes有各种选项,可以实现对文件的列出、删除、替换为文件副本的硬链接等操作。
文件对比:大小对比 > 部分 MD5 签名对比 > 完整 MD5 签名对比 > 逐字节对比

安装fdupes工具,然后进行测试。

// 进入项目文件下的所有资源文件夹,找出所有重复文件,导出到txt中查看
fdupes -Sr StoryToy > ~/Desktop/123/123.txt

查看项目中的重复文件
386 bytes each:
StoryToy/Bindings/addDevice/RTBindingReadyViewController.h
StoryToy/Bindings/addDevice/RTBindingChoiceListViewController.h

341 bytes each:
StoryToy/RooboMember/VipRights/View/RBVipRightSectionReusableView.h
StoryToy/CloudResource/RooboMember/VipRights/View/RBVipRightSectionReusableView.h

1869 bytes each:
StoryToy/RooboMember/VipRights/View/RBVipRightCollectionViewCell.m
StoryToy/CloudResource/RooboMember/VipRights/View/RBVipRightCollectionViewCell.m

......

可以看出我们确实查到了一些重复文件。

四:编译相关

4.1 Valid Architectures

设置生成IPA包所包含的支持架构,如果项目中还包含32位,armv7及之前的架构,但是我们项目现在已经不支持的可以考虑删除。

4.2 App Thinning

WWDC2015 发布会上首次介绍了 App Thinning,并在 iOS9 开始应用。严格来说App Thinning不会让安装包变小,但用户安装应用时,苹果会根据用户的机型自动选择合适的资源和对应CPU架构的二进制执行文件(也就是说用户本地可执行文件不会同时存在 armv7 和 arm64),减少下载流量和安装占用空间。


QQ20201226-202726@2x.png

五:Framework优化

引入三方Framework时,会包含多个指令集,我们可以手动移除不需要的指令集。或者查找只包含我们项目指令集的framework。

首先我们需要了解不同指令集对应的设备类型:

armv7 iPhone4s之前,iPad,iPad2,iPad3(The New iPad),iPad mini,iPod Touch 3G
armv7s iPhone5,iPhone5C,iPad4(iPad with Retina Display)
arm64 iPhone5s之后的机型,iPad Air,iPad mini2(iPad mini with Retina Display)等
x86_64 模拟器64位处理器,Mac应用
I386 模拟器32位处理器,Mac应用

例如我们项目中使用的音频格式转换功能中使用的libopencore-amrnb.a的静态库,他其中包含了所有的指令集,而对于大多数移动端 App,只需要 armv7,armv7s 和 arm64 指令集就足够了。

Architectures in the fat file: /Documents/work/rtoy/ios/RToyAPP/StoryToy/StoryToy/Wechat/RTPlayer/opencore-amr/lib/libopencore-amrnb.a are: i386 x86_64 armv7 armv7s arm64

因此在项目中,我们不需要x86_64,I386 我们只需要保留其他的指令集就可以了。

//查看静态库的信息
lipo -info libopencore-amrnb.a
Architectures in the fat file: libopencore-amrnb.a are: i386 x86_64 armv7 armv7s arm64
// 抽取单一指令集的静态库
lipo libopencore-amrnb.a -thin armv7 -output libopencore-amrnbArmv7
lipo libopencore-amrnb.a -thin armv7s -output libopencore-amrnbArmv7s
lipo libopencore-amrnb.a -thin arm64 -output libopencore-amrnbArm64

// 查看生成的静态库信息
ls 
libopencore-amrnb.a libopencore-amrnbArm64  libopencore-amrnbArmv7  libopencore-amrnbArmv7s libopencore-amrwb.a

lipo -info libopencore-amrnbArmv7
Non-fat file: libopencore-amrnbArmv7 is architecture: armv7

// 合成完整的静态库
lipo -create libopencore-amrnbArm64 libopencore-amrnbArmv7 libopencore-amrnbArmv7s -output nb/libopencore-amrnb.a

// 查看新生成的静态库信息
cd nb;ls
libopencore-amrnb.a
lipo -info libopencore-amrnb.a
Architectures in the fat file: libopencore-amrnb.a are: armv7 armv7s arm64

移除多余的指令集后,静态库大小从 4.8MB 降到 3.3MB,效果还是非常完美的。

六:结语

经过本次尝试,IPA包体积都有5%~20%不同程度的减小,当然优化的空间依然巨大。在实际项目瘦身过程中,上面列举的方式不一定都适用。因此对于项目瘦身,还是需要怀着一颗谨慎的心,谨慎检验每一次的尝试。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容