背景
随着APP
的功能越来越丰富,安装包的尺寸也在快速增长。像16G这种在往日非常大的存储空间,现在也越来越捉襟见肘,安装包的大小已经成为衡量APP
质量的指标之一。分析iOS的安装包文件.ipa文件我们可以看到,图片资源在安装包中还是占了比较大的比重,通过减少图片的总尺寸可以达到我们的目的。方法有两个,一是压缩单张图片的尺寸,比较著名的有imageOptim,二是减少图片的数量。实际上在我们的开发过程中,由于业务和设计的快速变化,导致工程中有许多冗余的图片资源。我们的目标就是找出并删除这些冗余的图片。为此,开发了工具UnusedImagesFinder
。
使用方法
使用方法自然是相当简单的,打开你的Terminal,执行以下命令:
1 | python unused_images_finder.py PROJECT_PATH {SOURCE_PATH} |
其中PROJECT_PATH
是你的工程文件的路径,也就是.xcodeproj
文件的路径。SOURCE_PATH
是一个可选参数,一般设置为工程的根目录,默认为.xcodeproj
文件的上级目录。检查的结果写入到当前目录下的result.txt
文件中。按照上述的步骤执行,如果在result.txt
文件中发现一堆误杀的文件,这时你就需要注意了,可能你的代码不是以常规的imageNamed:@"xxx"
的形式引用的。此时,我们需要修改我们的源文件了,打开ununsed_images_finder
找到174行,看到如下的代码:
1 | imageReferencePatterns = [re.compile(r".*imageNamed:@\"([^@\.]+)(@\dx)*(\.png|\.jpg)*\".*")] |
根据工程中引用图片的方式可以定制正则表达式,加入数组或者替换掉即可。
实现思路
大致的实现思路如下:
找出图片资源
在使用脚本中有一个参数是必填的,这个参数就是
.xcodeproj
,为什么一定要这个参数呢?因为在它的目录里有一个重要的文件project.pbxproj
,这个文件包含了工程所有的构建信息,包括图片资源和编译源文件。打开project.pbxproj
,找到Begin PBXResourcesBuildPhase section
和End PBXResourcesBuildPhase section
之间的内容,这里就是工程所引用的资源,这里有一些plist
,还有我们想要找的图片文件。通过正则匹配,我们可以拿到图片的名称。最初的版本,我就是这么写的,运行结果出来后,发现有非常多的漏查。查找后发现,工程中部分图片被放到.bundle
文件中,其中的文件并不会出现在project.pbxproj
,类似的还有image.xcasset
中的图片资源。所以在这里改变策略,遍历整个工程,找出所有图片。找出源文件
有了图片的查找经验,找资源文件就很简单了,所有被编译的资源都在
project.pbxproj
里的Begin PBXBuildFile section
和End PBXBuildFile section
之间。为什么我们不是在遍历文件时找出所有源文件呢?因为我们有许多不好的习惯,很多时候没用的源文件只是简单地被从工程引用中移除,并没有被物理删除。如果我们把这部分文件也加进来,它们引用的图片将成为漏网之鱼。扫描未引用的图片资源
有了上面两步的工作,第三步就比较简单了。遍历项目中的源文件,通过正则匹配的方式找到已引用的图片(注意,正则可能需要使用者补充,见使用方法),剩下的自然就是未被引用的资源了。
已知问题和改进
当前存在的不足如下:
- 目前不支持
Storyboard
和xib
引用如果没有直接使用文件名,无法检测出,比如
NSString *imageName = @"imageName"; UIImage *image = [UIImage imageNamed:imageName]; ... UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"xxx%d", 2]]
误杀
- Icon, Default 等文件不会直接被代码引用,查找的时候会被误杀
- 问题二的文件同样会被误杀
未来改进的方向:
- 改进上面的问题
- 脚本集成到持续集成中
- 提高检测率
最最最重要的一点,删除图片之前做好确认工作!