使用Ruby快速搜索项目中的无用图片

1,481 阅读2分钟

最近在练习Ruby,顺手写了个小脚本,用于扫描项目中未被使用的图片。

原理比较简单,先找到项目中存放图片资源的文件夹 *.xcassets ,获取图片的名字,根据这个名字去项目中遍历查找我们所关心的文件,比如iOS中OC的代码写在*.h,*.m,*.mm文件中,swift代码写在*.swift文件中,然后通过正则比较是否使用到下面的方法即可。

OC调用:

[UIImage imageNamed:@"xxx"]

Swift调用:

UIImage(named: "xxx")

使用时,直接打开终端运行脚本(记得同时下载log_color.rb文件,并放在同一目录下):

ruby image_use_check.rb /Users/zl/Desktop/jinfeng/project/MY_SDK/FFText

上面说的是用 ruby 解释器运行 image_use_check.rb 脚本,并传入一个参数,这个参数是一个项目的路径。熟悉Ruby的同学请忽略。

运行结果如下: result

可以看到有三张图片没被使用pj-1,pj-2,pj-3。我们随便拿一张图片去项目中搜索下,

OK,可以看到确实没用到这张图片。 确实木有

这里直接贴下源码,供大家学习参考:

require_relative './log_color'

Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8

inputs = ARGV

# 目标搜索路径
search_path = ''

if inputs.count > 0 
    search_path = inputs.first
else
    search_path = Dir.pwd
end

# 目标搜索路径
Target_search_path = search_path
# 这些目录不需要搜索
Except_dirs = ['Pods', '.', '..', '.git', '.DS_Store', 'xcuserdata', 'xcshareddata', 'fastlane', 'Fastlane']
# 目标图片文件夹名字后缀
Target_image_dir_extname = '.xcassets'
# 项目中用到的图片名字其实是imageset文件夹的名字
Target_useimage_dir_extname = '.imageset'
# 识别的图片后缀类型
Image_extnames = ['.png','.jpg','webp','.jpeg']
# 搜索的文件后缀
Search_code_file_extnames = ['.h', '.m', '.mm', '.swift']



class ImageDetector
    def initialize(path)
        @filePath = path
        @imageName = File.basename(path, Target_useimage_dir_extname)
        @match = false
    end

    def image_use?
        @match
    end

    def image_name
        @imageName
    end

    # 在整个项目中查找目标图片是否被使用
    def beginSearch(path=Target_search_path, &block)
        foreachDir(path) do |entry, full_path|
            if File.file? full_path
                file_extname = File.extname(full_path)
                if Search_code_file_extnames.include? (file_extname)
                    # puts "Start search file " + color_text(entry, Color.green) + " in path #{full_path}"
                    _match(full_path) {
                        @match = true
                        if not block.nil?
                            block.call @imageName, full_path
                        end
                        break
                    }
                end
            elsif File.directory? full_path
                # 这里过滤掉一些文件夹
                if File.extname(full_path) == Target_image_dir_extname
                    next
                end
                beginSearch(full_path, &block)
            else
                puts 'Unknow entry ' + color_text(entry, Color.red) + " in path #{full_path}"
            end
        end
    end

    # 目标图片是否在这个路径的文件中被引用
    def _match(path, &block)
        if not File::readable? path
            return
        end
        # 判断是否是 swift 文件
        is_swift = File.extname(path) == '.swift'

        # 匹配判断
        def check_image_oc(str)
            reg = /UIImage[\s]*imageNamed:@"#{@imageName}"/
            reg_png = /UIImage[\s]*imageNamed:@"#{@imageName}\.png"/
            if not (str =~ reg).nil? or not (str =~ reg_png).nil?
                #  puts 'Match success ' + color_text(str, Color.red)
                 return true
            end
            return false
        end

        def check_image_swift(str)
            reg = /UIImage\(named:[\s]*"#{@imageName}"[\s]*\)/
            reg_png = /UIImage\(named:[\s]*"#{@imageName}.png"[\s]*\)/
            if not (str =~ reg).nil? or not (str =~ reg_png).nil?
                #  puts 'Match success ' + color_text(str, Color.red)
                 return true
            end
            return false
        end

        text = File.read(path)
        res = false
        if is_swift == true
            res = check_image_swift text
        else
            res = check_image_oc text
        end
        if res == true
            if not block.nil?
                block.call path
            end
        end
    end
end

def foreachDir(path, &block)
    Dir.foreach(path) do |entry|
        if File.directory?(path) and  Except_dirs.include?(entry)
            next
        end
        if not block.nil? 
            full_path = path.to_s + "/" + entry.to_s
            block.call entry, full_path
        end
    end
end

def start_search(path)
    foreachDir(path) do |entry, full_path|
        if File.directory? full_path
            if File.extname(full_path) == Target_image_dir_extname
                puts "Find *.xcassets in path=#{full_path}"
                _search_image_inxcassets(full_path)
            else
                start_search(full_path)
            end
        end
    end
end

# 以*.xcassets为开始,遍历图片
def _search_image_inxcassets(path)
    foreachDir(path) do |entry, full_path|
        if File.directory? full_path
            if File.extname(full_path) == Target_useimage_dir_extname
                # 找到图片,查看这个图片是否在项目中有被使用
                detector = ImageDetector.new(full_path)
                detector.beginSearch { |image_name, match_file_path|
                    # 当有回调时,表示匹配到了
                    # puts "Match success image named " + color_text(image_name, Color.green) + " in " + color_text(match_file_path, Color.white)
                }
                if not detector.image_use?
                    puts "Image named " + color_text(detector.image_name, Color.red) + " unused!"
                end
            else
                _search_image_inxcassets full_path
            end
        end
    end
end

puts "Begin search..."
start_search(Target_search_path)
puts "Search finished, check appeal images is really unused in project."