查找项目中未使用的资源文件

前言

一般项目进行都尾声的时候 就要开始清理项目了 一般包括

  • 不用的代码(多人维护的时候 总会有垃圾代码产生)
  • 不用的文件(大多是因为需求变更 遗留下来的代码文件)
  • 不用的资源(大多是图片资源)

前两项不谈 都是体力活(当然 流程越规范 花费的时间越少)
今天主要谈谈怎么处理图片资源

实践

资源目录结构

我一般都是采用folder references的方式来组织资源(就是蓝色的文件夹哟 不过可能很多朋友已经用上了Images.xcassets) 相比groups的方式 优点如下

  • 直接对资源文件和目录结构进行调整而不需要修改项目文件
  • 资源文件可以重名
  • 如果有不同的target 每个target维护不同的根资源文件夹就行了

其他的优缺点对比 我就不在这里赘述了 相信有经验的同学都有体会

采用folder references的时候 一般在代码中是要指明其绝对路径的

1
[self.btnCreate setImageN:@"Res/circle/nav_create.png" H:@"Res/circle/nav_create.png" D:nil S:nil];

那么 要找到未使用的资源 其实就很简单了

  1. 找到代码中所有被引用的资源
  2. 遍历资源文件夹 与上面的结果相匹配 找到未引用的资源

脚本

按照上面的逻辑 我用python写了一个简单的脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/usr/bin/python
# -*- coding: utf-8 -*

import os, sys, re, shutil

if __name__ == '__main__':

used_map = {}
resPath = "./MagnetPF/Res/" #资源目录相对路径
depDir = "deprecated" #过期目录 会将未使用文件挪入这个目录
skipDir = ["message"] #将跳过的目录

for root, dirs, files in os.walk("./"):
for file in files:
if file.endswith(".m"):

filepath = os.path.join(root, file)
f = open(filepath, "r")

for line in f:
match = re.findall(".*?@\"(Res.*?.png)\".*?", line) #匹配资源文件

if match:
for image in match:
# print image
used_map[image] = 1 #记录

skipDir.append(depDir) #过期目录也会一并跳过

for root, dirs, files in os.walk(resPath):
for file in files:

orginfile = os.path.join(root, file)

match = re.findall(".*?(Res.*?.png).*?", orginfile) #将相对路径过滤出来

if match:
matchfile = match[0].replace("@2x","").replace("@3x","") #剔除@2x@3x字样

print matchfile

if not used_map.has_key(matchfile): #检测到未使用资源

filename = orginfile.split(os.path.sep)[-1] #获取文件名
relPath = orginfile.replace(resPath,"") #获取相对路径
originDir = relPath.split(os.path.sep)[0] #获取第一层文件夹名(用于跳过筛选)
tofile = resPath + depDir + "/" + relPath #目标文件 (将会被复制到这个路径)
topath = tofile.replace(filename,"") #目标文件夹 (若没有则会创建这个文件夹)

if not originDir in skipDir:
if not os.path.exists(topath):
os.mkdir(topath)

print "from: " + orginfile
print " to: " + tofile
print ""

shutil.move(orginfile, tofile)

小结

这个代码其实还有几个问题没有解决

  1. 若含有资源文件的代码被注释 一样会被忽略而不会被移除(当然 代码清理也是应该要做的)
  2. 对于用代码拼接的资源(比如xx01.png,xx02.png)会无法识别
  3. 不适用于非folder references方式引用资源的工程

同理 我们可以写类似的代码来清理多语言文件 :)

代码其实是我上周六现学现卖边查google边写的 所以写得不好 若是大家有更好的方案 欢迎一起讨论学习