网络知识 娱乐 Flutter项目中无用图片的检测及清理

Flutter项目中无用图片的检测及清理

一、背景

随着项目规模或者迭代周期的增加,项目中会保留部分已经不在使用的图片,这些资源的存在,会增加包体积。
在优化app大小时,常采用的手段之一就是对不在使用的图片进行清理。

二、原理

在flutter中使用asset中的图片的时候,都是根据图片路径加载图片,如:Image.asset(“assets/account/watsapp.png”),
根据图片的这样使用方式,我们就可以使用图片的名字或者图片的相对路径(assets/account/watsapp.png),在dart文件中搜索,如果在dart文件中我们找到该匹配的字符串,我们就认为该图片已经存在。
也存在误判的情况,我们在异常说明这部分中解释说明,也欢迎大家补充

三、实现方法

使用Python,获取项目中所有添加的图片绝对路径,并用存储到List中,然后读取dart文件,看在dart文件中是否存在与图片名称(watsapp.png)或者图片相对路径(assets/account/watsapp.png)相同的字符串,如果找到匹配的字符串,就认为图片在项目中使用,然后将图片地址从集合中移除,分析完所有dart文件,最后还在集合中的图片就可以认为是项目中已经不在使用的图片。

以下是使用Python3实现的完整代码:

#!/user/local/bin/python3
#将本文件放在Flutter项目的根目录

from genericpath import isdir
import imghdr
from operator import delitem
import os
from re import search
import re
import string
from sys import path
import sys
from tokenize import String
from typing import List

print("---Analyze unused Assets----")
#项目目录
projectAbsRootPath = sys.path[0]
#图片所在的资源目录路径
assetPath="/assets"
#项目中dart代码所在目录
libPath = projectAbsRootPath+ "/lib"
assetAbPath = projectAbsRootPath+assetPath

print("projectRootPath:" + projectAbsRootPath +  "   assets:" +assetAbPath + "     lib:" + libPath)
print("----------开始查找图片--------------")
#遍历目录,将图片存储到list中的方法
def searchImage(filePath:String):
    list = []
    isDir = os.path.isdir(filePath)
    if isDir:
        for f in os.listdir(filePath):
            if f.startswith("."):
                print(filePath+"/"+f)
            else:
                tList = searchImage(filePath+"/"+f)
                list.extend(tList)
    else:
        if imghdr.what(filePath) in {"jpg","bmp","jpeg","rgb","tif","png"}:
            list.append(filePath)
    return list

#项目中使用的图片资源路径集合
imageList = searchImage(assetAbPath)

print("-------------遍历dart文件,分析未使用的图片---------")
def matchAndDelImage(contentStr:String,list:List):
    #遍历拷贝的list,操作原始的list,list[:]是对原始的一个拷贝
    for imgPath in list[:]:
        #以文件名匹配图片的使用
        # pList = imgPath.split("/")
        # imgName = pList[-1]
        #以使用的文件路径匹配图片
        index = imgPath.find(assetPath)
        imgName = imgPath[index+1:]

        match = re.search(imgName,contentStr)
        if match:
            list.remove(imgPath)
            # print("used-->" + imgPath)

#
def searchImageInDart(filePath:String,list:List):
    if os.path.isdir(filePath):
        for f in os.listdir(filePath):
            searchImageInDart(filePath+"/"+f,list)
    else:
        with open(filePath,"r") as f:
            contentStr = f.read()
            f.close()
            if len(contentStr) != 0:
                matchAndDelImage(contentStr,list)

#      
searchImageInDart(libPath,imageList)

print("------在dart文件中未找到被使用的图片如下-----size:" + str(len(imageList)))
for img in imageList:
    print("may be unused-->" + img)
    # os.remove(img)
print("-------------------分析完成-------------------------------")

说明:
1、Flutter项目中存放图片的目录可以自己指定,本示例存放图片的目录是:projectroot/assets

projectroot
	- assets
		- images
			- splash
			- user
		- fonts
	- lib

在这里插入图片描述

2、在matchAndDelImage()方法中实现了根据图片名字或者路径匹配图片的处理。

蓝色框中是根据图片文件名字匹配。
红色框中是获取图片相对路径,根据相对路径匹配。
在这里插入图片描述
3、图片删除默认没有开启,但是会把没有使用的图片路径打印出来。
如果需要删除图片,取消对os.remove(img)的注释即可。
在这里插入图片描述

四、异常说明

1、图片实际被使用,但是被认为未使用
(a)图片名或者路径以拼接的方式使用
如:

  String getImageByScore(int? score) {
    String name = '';
    switch (score) {
      case 2:
        name = 'images/excellent';
        break;
    }
    if (Application.isPreferZh) {
      name = name + '_cn';
    }
    return name + '.png';
  }

使用以上检测方法,excellent.png和excellent_cn.png这两张图片就不能被检测出已经使用。【修改为使用图片完整名字或路径即可解决】

2、图片实际未被使用,但是被认为已使用。
(a)项目中存在abc.png 和bc.png两种图片,只使用了abc.png这张图片,bc.png也会被误检测出被使用。【使用图片相对路径可避免该问题】
(b)项目中有a.png图片,但是在代码中有创建一个名字为a.png的图片逻辑。
(c)项目中存在a.png,但是在代码中存在a.png这样的字符串或者非加载图片的命名。

五、其他实现方式

1、将图片生成静态引用
图片静态引用