在這篇文章中,我會介紹幾種不同的方式,讓你通過自動化工具提高你的Android代碼質量,包括?Checkstyle,?Findbugs,PMD, 當然,還有我們最熟悉的Android Lint。 為了讓你的代碼保持縝密的語法,同時避免一些糟糕的實現和錯誤,使用自動化的方式測試你的代碼十分有用,尤其是當你和隊友一起工作時。我會細心地解釋如何直接通過你的Gradle構建腳本使用這些工具,和怎么方便地配置它們。
Fork這個例子
我強烈建議你fork此項目,因為我將介紹的所有例子均來自于它。同時,你也能自己測試這些質量控制工具。
關于Gradle任務
理解任務在Gradle中的概念是理解這篇文章的基礎(廣義上,也是學會撰寫Gradle腳本的基礎)。我強烈建議你先閱讀一下Gradle文檔中關于任務的部分(這個和這個)。 文檔中包含許多例子,非常容易理解。好了,那現在我就假設你已經fork了我的倉庫,將項目導入了你的Android Studio,同時也已經熟悉了Gradle的任務。如果沒有也不必擔心,我會盡我所能解釋得通俗易懂。
Demo項目的層次結構
你能將gradle
腳本分離在很多文件中,目前我分了3個gradle
文件:
- 一個在根目錄,這個文件是關于項目的一些配置(比如使用的maven倉庫和使用的Gradle版本);
- 一個在子文件夾
app
中,這是一個典型的構建Android應用的Gradle文件。 - 一個在子文件夾
config
中,這個才是我們所關注的,我用它來為我的項目集成并配置所有的質量控制工具。
Checkstyle
簡介
Checkstyle是一個幫助程序員堅持規范化編寫Java代碼的開發工具.它自動檢查Java代碼,將程序員從這項乏味(但重要)的工作中解放出來.
正如Checkstyle的開發者所說,這個工具幫助你在一個項目中,精確并靈活地定義和保持編碼規范。當你運行Checkstyle時,它會分析你的Java代碼,根據你的配置找出所有錯誤并提示你。
通過Gradle配置
以下代碼展示了在你項目中使用Checkstyle
的基本配置(作為一個Gradle
任務):
task checkstyle(type: Checkstyle) {configFile file("${project.rootDir}/config/quality/checkstyle/checkstyle.xml") // Where my checkstyle config is...configProperties.checkstyleSuppressionsPath = file("${project.rootDir}/config/quality/checkstyle/suppressions.xml").absolutePath // Where is my suppressions file for checkstyle is...source 'src'include '**/*.java'exclude '**/gen/**'classpath = files()
}
配置完后,這個任務就會根據checkstyle.xml
和suppressions.xml
兩個文件來分析你的代碼。只需要在Gradle
面板中啟動這個任務,Android Studio就會自動執行此任務。
運行Checkstyle
后,你會得到一份報告,上面紀錄了在你項目中找到的所有問題。而且它非常易于理解。
如果你想更個性化地配置Checkstyle
,請參考這篇文檔。
Checkstyle使用技巧
Checkstyle
會探測到大量問題,尤其當你使用了很多規則--比如你想要一個精確的語法。雖然我通過Gradle
腳本來使用Checkstyle
(比如在我push代碼之前),但我建議你同時使用Checkstyle
的IntellJ/Android Studio插件(你能直接通過工具欄File/Settings/Plugins安裝它們。譯者注:mac版是Android Studio/Preferences/Plugins)。這種方式也是根據你之前為Gradle指定的那兩個配置文件在你的項目中應用Checkstyle
。這樣的好處是能直接在Android Studio中查看結果。更實用的是,結果可以直接鏈接到錯誤所在代碼(Gradle
的那種方式仍然很重要,因為你能通過Jenkins
這樣的自動化構建系統來使用它)。
FindBugs
簡介
Findbugs
?需要簡介嗎?它的名字已經說明了一切。
Findbugs 通過靜態分析來檢查Java字節碼中的錯誤模式。
Findbugs
?基本上只需要項目的字節碼文件來做分析,因此它十分易用。它會檢測出諸如錯誤使用布爾運算符這樣常見的錯誤。同時,它還能檢測出一些由于誤解語言特性所導致的錯誤,比如Java中方法參數的重新賦值(實際上是無效的,因為Java中方法的參數是值傳遞)。
通過Gradle配置
以下代碼展示了在你項目中使用Findbugs
的基本配置(作為一個Gradle
任務):
task findbugs(type: FindBugs) {ignoreFailures = falseeffort = "max"reportLevel = "high"excludeFilter = new File("${project.rootDir}/config/quality/findbugs/findbugs-filter.xml")classes = files("${project.rootDir}/app/build/classes")source 'src'include '**/*.java'exclude '**/gen/**'reports {xml.enabled = falsehtml.enabled = truexml {destination "$project.buildDir/reports/findbugs/findbugs.xml"}html {destination "$project.buildDir/reports/findbugs/findbugs.html"}}classpath = files()
}
這和Checkstyle
的任務很像。Findbugs
支持HTML
和XML
格式的報告,我選擇了HTML
,因為其可讀性更強。除此以外,你只需要標記一下報告的路徑來快速讀取它。如果Findbugs中的錯誤被檢測到,任務會失敗(仍然產生報告)。執行Findbugs
的方式和Checkstyle
完全一樣(只是名字變成了"Findbugs")。
Findbugs使用技巧
由于Android項目與Java項目有輕微不同,我強烈建議大家使用findbugs-filter
。例子點這里(示例項目的其中之一)。它一般會忽略掉R文件和清單文件。另外,由于Findbugs
是分析你的字節碼,你至少需要編譯一次項目來測試它。
PMD
簡介
這個工具十分有趣:PMD
并沒有一個真正的名字。在官方網站上你會發現一些有趣的命名建議:
- Pretty Much Done
- Project Meets Deadline
實際上,PMD
是一個非常強大的工具。它的工作方式有點像Findbugs
,但它直接檢查源碼而非字節碼(另外,PMD支持大量語言)。目標也和Findbugs
高度相似--通過靜態分析找出能導致bug的模式。那么為什么我們還要同時使用Findbugs
和PMD
呢?好吧,盡管Findbugs
和PMD
的目標一致,但它們的檢查方法并不同。因此PMD
有時可以找到Findbugs
找不到的bug,反過來也一樣。
通過Gradle配置
以下代碼展示了在你項目中使用PMD
的基本配置(作為一個Gradle
任務):
task pmd(type: Pmd) {ruleSetFiles = files("${project.rootDir}/config/quality/pmd/pmd-ruleset.xml")ignoreFailures = falseruleSets = []source 'src'include '**/*.java'exclude '**/gen/**'reports {xml.enabled = falsehtml.enabled = truexml {destination "$project.buildDir/reports/pmd/pmd.xml"}html {destination "$project.buildDir/reports/pmd/pmd.html"}}
}
PMD
的結果同樣與Findbugs
有許多相同之處。PMD
的報告同樣支持HTML
和XML
,因此我再次選擇了HTML
的格式。我強烈建議使用你自己的自定義規則集文件,就像我在例子中做的這樣(參照這個文件)。當然,你還需要看一下自定義規則集的文檔。我這么建議是因為PMD
相比Findbugs
而言更具爭議。比如,如果你沒有折疊if條件語句或寫了一個空的if條件語句,它一般就會警告你。我認為應該由你或你的同事為你們的項目來定義這些規則是否正確。像我自己就喜歡不折疊if條件語句,因為這樣更具可讀性。執行PMD
的方式和Checkstyle
完全一樣(只是名字變成了"PMD")。
PMD使用技巧
由于我推薦你不要使用默認的規則集,你需要加上這行代碼(上面已經加上了)
ruleSets = []
不加的話,由于默認值是基本的規則集,那些默認的規則集會始終伴隨你自定義的規則集一起執行。這樣即使你在自定義的規則集中指明不使用基礎規則集中的規則,它們仍然會被考慮在內。
Android Lint
簡介
Android lint 工具是一個靜態代碼分析工具。它通過你Android項目的源碼檢測出潛在的錯誤,并為項目在正確性,安全性,性能,可用性, 易用性和國際化等方面提供最佳的改進方案。
正如其官網所說,Android Lint
是一款專注于Android的靜態分析工具。它非常強大,能給出大量建議來提高你代碼的質量。
通過Gradle配置
android {lintOptions {abortOnError truelintConfig file("${project.rootDir}/config/quality/lint/lint.xml")// if true, generate an HTML report (with issue explanations, sourcecode, etc)htmlReport true// optional path to report (default will be lint-results.html in the builddir)htmlOutput file("$project.buildDir/reports/lint/lint.html")
}
我推薦你使用一個單獨的文件來定義哪些規則應該使用。這個網站定義了所有來自最新ADT版本的規則。除了"ignore"中"severity"級別的規則外,我的demo中的Lint
文件包含了所有規則:
- IconDensities:這個規則確保你為每一種分辨率都設置了對應的圖片資源(除ldpi外)。
- IconDipSize:這個規則確保你正確地定義了資源的每種尺寸。(換句話說,檢查你是否為不同分辨率定義了完全相同的圖片,而沒有重新設置圖片大小)。
所以你能直接復用這份lint
文件并激活所有你想要的規則。執行Android Lint
任務的方式和Checkstyle
完全一樣(只是名字變成了"lint")。
Android Lint使用技巧
Android Lint
沒有什么特殊的使用技巧,你只需要記住,Android Lint
總是會測試除"ignore"中"severity"級別的規則外的所有規則。所以如果隨著ADT的新版本出現了新的規則,它們會被檢查,而不會被忽略。
通過一個任務管理以上所有工具
現在你已經掌握了為你項目使用4個質量控制工具的關鍵。但如果你能同時使用4個工具就更好了。你能在你的Gradle任務之間添加依賴,比如當你執行一個任務時,另外一個會在第一個任務完成后執行。一般在Gradle中,你通過"check"任務為你的質量工具添加依賴:
check.dependsOn 'checkstyle', 'findbugs', 'pmd', 'lint'
現在,當你執行"check"任務,Checkstyle
,?Findbugs
,?PMD
, 和Android Lint
?都會被執行。這是一個非常好的方式來在你commit/push/請求合并之前檢查代碼質量。
你能在這個Gradle文件中獲得所有這些任務的示例。你能在demo源碼的config/quality
文件夾中找到所有關于質量控制的配置和gradle文件。
總結
正如這篇文章介紹的,Android的質量控制工具配合Gradle
使用非常簡單。質量控制工具不僅僅能檢查你電腦中的本地項目,還能檢查一些自動化構建平臺上的代碼,比如Jenkins/Hudson等。這使你能將質量控制的工作依附于自動構建系統,實現自動化。執行所有測試的命令與執行Jenkins和Hudson相同,最簡單的命令是:
gradle check
請自由評論這篇文章,或者咨詢任何與Android代碼質量相關的問題!
快去實踐吧!