Recently, while practicing Ruby, I wrote a small script to scan unused images in a project.

The principle is relatively simple. First, find the folder *.xcassets in the project where the image resources are stored, get the name of the image, and then go through the project to find the files we care about according to the name. For example, in iOS, the OC code is written in the *.h,*.m,*.mm file, and the swift code is written in the *.swift file. Then compare whether the following method is used by the regular.

OC call:

[UIImage imageNamed:@"xxx"]
Copy the code

Swift call:

UIImage(named: "xxx")
Copy the code

When using the script, open the terminal directly to run the script (remember to download log_color.rb file at the same time, and put in the same directory) :

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

Run the image_use_check.rb script with the Ruby interpreter and pass in a parameter, which is the path of a project. If you’re familiar with Ruby, please ignore it.

The running results are as follows:

You can see that there are three images that are not used: PJ-1, PJ-2, and PJ-3. Let’s just take a random image and look it up in the project,

OK, you can see that this image is not used.

Here directly paste the source code for your reference:

require_relative './log_color'

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

inputs = ARGV

# Target search path
search_path = ' '

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

# Target search path
Target_search_path = search_path
# These directories do not need searching
Except_dirs = ['Pods'.'. '.'.. '.'.git'.'.DS_Store'.'xcuserdata'.'xcshareddata'.'fastlane'.'Fastlane']
Target image folder name suffix
Target_image_dir_extname = '.xcassets'
The image name used in the # project is actually the name of the imageset folder
Target_useimage_dir_extname = '.imageset'
# identifies the image suffix type
Image_extnames = ['.png'.'.jpg'.'webp'.'.jpeg']
# Search for file suffix
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

    # Check whether the target image is used throughout the project
    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
                Filter out some folders here
                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

    Whether the target image is referenced in the file at this path
    def _match(path, &block)
        if not File::readable? path
            return
        end
        # Check whether it is a swift file
        is_swift = File.extname(path) == '.swift'

        # Match judgment
        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|
        ifFile.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

# start with *.xcassets and iterate through the image
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
                Find the image and see if it was used in the project
                detector = ImageDetector.new(full_path)
                detector.beginSearch { |image_name, match_file_path|
                    # When there is a callback, a match has been made
                    # 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) + "The 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."
Copy the code