Python - One-click to find unused pictures, audio and video resources in iOS projects

Preface

In the process of iOS project development, if the iteration time of version development is relatively long, after many versions development or after many people participate in the development, there are inevitably some garbage resources in the project, which are not used but occupy the size of the api package!

Here I use Python script to find the unused pictures, audio and video resources in the project, and then delete them; in order to reduce the size of the APP package!

Code

Find all the resource files in the project and store them in your array.

def searchAllResName(file_dir):
    global _resNameMap
    fs = os.listdir(file_dir)
    for dir in fs:
        tmp_path = os.path.join(file_dir, dir)
        if not os.path.isdir(tmp_path):
            if isResource(tmp_path) == True and '/Pods/' not in tmp_path and '.appiconset' not in tmp_path and '.launchimage' not in tmp_path:
                imageName = tmp_path.split('/')[-1].split('.')[0]
                _resNameMap[imageName] = tmp_path
                conLog.info_delRes('[FindRes OK] ' + tmp_path)
 
        elif os.path.isdir(tmp_path) and tmp_path.endswith('.imageset') and '/Pods/' not in tmp_path:
            imageName = tmp_path.split('/')[-1].split('.')[0]
            _resNameMap[imageName] = tmp_path
            conLog.info_delRes('[FindRes OK] ' + tmp_path)
 
        else:
            searchAllResName(tmp_path)

Go through all the code that queries the project to find the resource files referenced in the project

# So code to query the project
def searchProjectCode(file_dir):
    global _projectPbxprojPath
    fs = os.listdir(file_dir)
    for dir in fs:
        tmp_path = os.path.join(file_dir, dir)
        if tmp_path.endswith('project.pbxproj'):
            _projectPbxprojPath = tmp_path
 
        if not os.path.isdir(tmp_path):
            if '/Pods/' not in tmp_path:
                try:
                    findResNameAtFileLine(tmp_path)
                    conLog.info_delRes('[ReadFileForRes OK] ' + tmp_path)
                except Exception as e:
                    pass
                    # conLog.error_delRes('[ReadFileForRes Fail] [' + str(e) + ']' + tmp_path)
        else:
            searchProjectCode(tmp_path)
 
# Find the resource files referenced in the project
def findResNameAtFileLine(tmp_path):
    global _resNameMap
    Ropen = open(tmp_path,'r')
    for line in Ropen:
        lineList = line.split('"')
        for item in lineList:
            # bar@2x barimg.png
            if item in _resNameMap or item.split('.')[0] in _resNameMap or item + '@1x' in _resNameMap or item + '@2x' in _resNameMap or item + '@3x' in _resNameMap:
                del _resNameMap[item]
 
    Ropen.close()

Delete the junk resource file, here the junk resource file deletion is divided into two parts: Assets.xcassets, part is directly imported into the project directory resources, if it is Assets.xcassets junk resources directly deleted, but if it is directly imported into the project directory resources, then delete PR first. Reference in oject. pbxproj and delete the local resource file.

# Delete useless resource files
def delAllRubRes():
    global _resNameMap, _hadDelMap
    # Direct deletion of resource images of. imageset type
    for resName in list(_resNameMap.keys()):
        tmp_path = _resNameMap[resName]
        if tmp_path.endswith('.imageset'):
            if os.path.exists(tmp_path) and os.path.isdir(tmp_path):
                try:
                    # Deleted elements
                    _hadDelMap[resName] = tmp_path
                    # Delete. imageset folder
                    delImagesetFolder(tmp_path)
                    # Dictionary Removal
                    del _resNameMap[resName]
                    conLog.info_delRes('[DelRubRes OK] ' + tmp_path)
                except Exception as e:
                    conLog.error_delRes('[DelRubRes Fail] [' + str(e) + ']' + tmp_path)
            else:
                conLog.error_delRes('[DelRubRes Fail] [not exists] ' + tmp_path)
 
    delResAtProjectPbxproj()
 
def delImagesetFolder(rootdir):
    filelist = []
    filelist = os.listdir(rootdir)
    for f in filelist:
        filepath = os.path.join( rootdir, f )
        if os.path.isfile(filepath):
            os.remove(filepath)
        elif os.path.isdir(filepath):
            shutil.rmtree(filepath,True)
    shutil.rmtree(rootdir,True)
        
# Images imported directly into the project need to delete references in project.pbxproj and then remove local files
def delResAtProjectPbxproj():
    global _projectPbxprojPath, _resNameMap, _hadDelMap
    if _projectPbxprojPath != None:
        # Save a resource name that needs to be deleted first
        _needDelResName = []
        file_data = ''
        Ropen = open(_projectPbxprojPath,'r')
        for line in Ropen:
            idAdd = True
            for resName in _resNameMap:
                if resName in line:
                    idAdd = False
                    if resName not in _needDelResName:
                        _needDelResName.append(resName)
 
            if idAdd == True:
                file_data += line
 
        Ropen.close()
        Wopen = open(_projectPbxprojPath,'w')
        Wopen.write(file_data)
        Wopen.close()
        # The resource files referenced in project.pbxproj have been cleaned up and the processed resource files have been removed from _resNameMap
        # And delete the local corresponding resource file
        for item in _needDelResName:
            tmp_path = _resNameMap[item]
            if os.path.exists(tmp_path) and not os.path.isdir(tmp_path):
                # Deleted elements
                _hadDelMap[item] = tmp_path
                # Delete files
                os.remove(tmp_path)
                # Dictionary Removal
                del _resNameMap[item]
                conLog.info_delRes('[DelRubRes OK] ' + tmp_path)
            else:
                pass

Total calling function

# Start cleaning up useless garbage resource files
def startCleanRubRes(file_dir, ignoreList = []):
    global _resNameMap, _hadDelMap,_isCleaing
    if _isCleaing == True:
        return
    _isCleaing = True
    initData()
    conLog.info('-' * 30 + 'Start cleaning up resource files' + '-' * 30)
    searchAllResName(file_dir)
    conLog.info_delRes('-' * 20 + 'List of all resource files' + '-' * 20)
    conLog.info_delRes(_resNameMap)
    for item in ignoreList:
        if item in list(_resNameMap.keys()):
            del _resNameMap[item]
    conLog.info_delRes('-' * 20 + 'Ignore deleted resource files' + '-' * 20)
    conLog.info_delRes(ignoreList)
    searchProjectCode(file_dir)
    conLog.info_delRes('-' * 20 + 'Resource files that need to be deleted' + '-' * 20)
    conLog.info_delRes(_resNameMap)
    delAllRubRes()
    conLog.info_delRes('-' * 20 + 'Delete a successful resource file' + '-' * 20)
    conLog.info_delRes(_hadDelMap)
    conLog.info_delRes('-' * 20 + 'Delete failed resource files' + '-' * 20)
    conLog.info_delRes(_resNameMap)
    _isCleaing = False

Software

Since some iOS programmers do not have Python foundation, we have made a graphical operation interface here. Welcome to download and use it!

Download address:

https://gitee.com/zfj1128/ZFJ...

Software screenshots:

Keywords: iOS Python

Added by oneofayykind on Mon, 12 Aug 2019 07:29:31 +0300