基於SwiftSyntax寫一個命令行工具檢測Xcode項目中不用的圖片資源

其實已經有一個不錯的用Swift寫的命令行工具檢測不用的圖片資源了,就是喵神的FengNiao,至於爲何要再寫一個呢,主要是爲了學習SwiftSyntax,前段時間我寫了篇文章簡單的介紹了SwiftSyntax,文章在這裏SwiftSyntax詳解,對SwiftSyntax不熟悉的能夠先看看。node

項目在這裏UnusedResources,下面來簡單介紹一下原理。python

1. 找到項目中全部的圖片資源

我這裏找的圖片資源有如下幾種:git

let imageExtensions: [String] = ["png", "jpg", "gif", "pdf"]
複製代碼

這裏不得不提如下Homebrew的做者mxcl開源的庫Path,這個庫真的很好用。咱們先定義一個方法來來查找所需擴展名的文件github

func recursiveFiles(withExtensions exts: [String], at path: Path) throws -> [Path] {
    if path.isFile {
        if exts.contains(path.extension) {
            return [path]
        }
        return []
    } else if path.isDirectory {
        var files: [Path] = []
        for entry in try path.ls() {
            let list = try recursiveFiles(withExtensions: exts, at: entry.path)
            files.append(contentsOf: list)
        }
        return files
    }
    return []
}

複製代碼

找到全部的圖片資源就只要下面簡單的一段代碼就能夠了json

var images: [Path] = try recursiveFiles(withExtensions: imageExtensions, at: path)

複製代碼

2. 查看項目中源代碼文件

找到源代碼文件swift

var files: [Path] = try recursiveFiles(withExtensions: ["swift", "h", "m", "mm"], at: path)

複製代碼

這裏就須要用到SwiftSyntax,咱們定義一個StringVisitor遍歷語法樹,提取字符串並判斷是否和圖片名稱同樣,同樣就說明圖片被使用了。bash

咱們一個簡單的swift代碼的語法樹,能夠用xcrun swiftc -frontend -emit-syntax ./Cat.swift | python -m json.tool命令查看源代碼語法樹結構,可是仍是比較複雜,包含import庫的部分,因此我選擇用Swift AST Explorer,這個是基於SwiftSyntax實現,語法樹更簡潔。 app

屏幕快照 2019-11-06 下午6.44.40.png

咱們只要拿到StringSegmentSyntax的內容就行了,而後和圖片進行對比,和圖片同樣,就表示圖片被使用到了。frontend

public struct StringVisitor: SyntaxVisitor {
    
    public var images: [Path] = []
        
    public init(_ images: [Path]) {
        self.images = images
    }
    
    // Ignore string interpolated literal because it's too complex to compare public mutating func visit(_ node: StringLiteralExprSyntax) -> SyntaxVisitorContinueKind { guard node.segments.count == 1 else { return .skipChildren } return .visitChildren } public mutating func visit(_ node: StringSegmentSyntax) -> SyntaxVisitorContinueKind { let text = node.content.text .trimmingCharacters(in: .whitespacesAndNewlines) guard !text.isEmpty else { return .skipChildren } images = images.filter { $0.basename(dropExtension: true) != text } return .skipChildren } } 複製代碼

OC和Swift的語法書稍微有點不同,因此咱們能夠獲得全部的TokenSyntax,而後找到類型是stringLiteral的,這裏我處理比較簡單,直接判斷stringLiteral是否包含圖片名稱,若是包含就表示圖片被使用了。工具

屏幕快照 2019-11-06 下午6.39.09.png

因此咱們再給StringVisitor添加一個方法

// for Objective-C
    public mutating func visit(_ token: TokenSyntax) -> SyntaxVisitorContinueKind {
        switch token.tokenKind {
        case .stringLiteral(let text):
            images = images.filter { !text.contains($0.basename(dropExtension: true)) }
        default:
            break
        }
        
        return .visitChildren
    }
複製代碼

3. 查看XML文件

let xmlExtensions: [String] = ["xib", "storyboard"]
var xmlFiles: [Path] = try recursiveFiles(withExtensions: xmlExtensions, at: path)

複製代碼

這裏須要用到XMLParser找到attributeDict中key爲「image」的value,若是和圖片名稱同樣就表示圖片被使用了。

4. Makefile

使用Makefile來build項目,自動將生成的unused-resources拷貝到/usr/local/bin中。

5. 總結

水文一篇,最近在研究編譯相關的知識,進展十分緩慢,心累。

相關文章
相關標籤/搜索