提高 Android 程式碼質量的4個工具

devtf發表於2015-07-14

在這篇文章中,我將通過不同的自動化工具如CheckStyle,FindBugs,PMD以及Android Lint來介紹(如何)提高你的安卓程式碼質量。通過自動化的方式檢查你的程式碼非常有用,尤其當你在一個團隊中工作,為了在你的程式碼中保持嚴格的語法格式以及避免很多壞習慣和錯誤。我將仔細地介紹如何在你空閒的時候直接運用這些工具通過Gradle構建指令碼以及如何配置它們。

Fork該示例

我強烈建議你拷貝下這個專案工程,儘管我將介紹的案例都是來自它。與此同時,你將能夠測試下自己對這些工具的瞭解情況。

關於Gradle任務

Gradle任務的概念(在Gradle中的含義)是理解該篇文章(以及如何以一種通用的方式寫Gradle指令碼)的基礎。我強烈建議你去看下這兩篇關於Gradle任務的文件(這篇這篇)。這個文件包含了大量的例子,因此它非常容易開始學習。現在,我假定你拷貝了我的Repo,你匯入這個工程到你的Android Studio,並且你熟悉Gradle任務。如果不是,別擔心,我將盡我最大的努力讓我的講解更有意義。

關於示例專案的層次結構

你可以將gradle指令碼檔案分割成很多檔案,我現在已經有3個gradle檔案:

  • 根資料夾中的檔案,這些檔案或多或少都是關於這個專案的配置的(用的哪個Maven Repos,用的哪個版本的Gradle)。
  • App子資料夾中的檔案,這些檔案是典型的用於建立安卓應用的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分析你的程式碼。通過Android Studio執行它僅僅需要從工具面的CheckStyle來啟動它。

啟動CheckStyle之後,你講收到一個報告用於展示在你專案中發現的每個錯誤。這是非常直接的方式。

如果你想在checkstyle上做更多的配置,可以參考這篇文件

Checkstyle的使用技巧

Checkstyle會發現大量的問題,特別是在你運用了大量的規則配置,如同你設定了一個非常精確的語法。儘管我通過Gradle使用 checkstyle,例如在我進行推送之前,我仍然推薦你為IntellJ/Android Studio使用checkstyle外掛(你可以通過Android Studio的工作皮膚檔案/設定/外掛直接安裝外掛)。這種方式下,你可以根據那些為Gradle配置的相同檔案在你的工程中使用 checkstyle,但是遠不止這些,你可以直接在Android Studio中獲取帶有超連結結果,這些結果通過超連結在你的程式碼中對應,這是非常有用的(Gradle的這種方式仍然很重要的,因為你可以使用它自動構建系統,如Jenkins)。

Findbugs

簡介

Findbugs是否需要一個簡介呢?我想它的名稱已經讓人顧名思義了。“FindBugs使用靜態分析方法為出現bug模式檢查Java位元組碼”。FindBugs基本上只需要一個程式來做分析的位元組碼,所以這是非常容易使用。它能檢測到常見的錯誤,如錯誤的布林運算子。FindBugs也能夠檢測到由於誤解語言特點的錯誤,如Java引數調整(這不是真的有可能因為它的引數是傳值)。

Gradle的形式

下面的程式碼向你展示了在你的專案中使用Findbugs的最基本的配置(以Gradle任務為例):

task findbugs(type: FindBugs) {
ignoreFailures = false
effort = "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 = false
html.enabled = true
xml {
destination "$project.buildDir/reports/findbugs/findbugs.xml"
}
html {
destination "$project.buildDir/reports/findbugs/findbugs.html"
}
}

classpath = files()
}

它是如此的像一個Checkstyle任務。儘管Findbugs支援HTML和XML兩種報告形式,我選擇HTML形式,因為這種形式更具有可讀性。而且,你只需要把報告的位置設定為書籤就可以快速訪問它的位置。這個任務也會失敗如果發現Findbgus錯誤失敗(同樣生成報告)。執行 FindBugs任務,就像執行CheckStyle任務(除了任務的名稱是“FindBugs”)。

Findbugs的使用技巧

由於Android專案是從Java專案略有不同,我強烈推薦使用FindBugs過濾器(規則配置)。你可以在這一個例子(例如專案之一)。它基本上忽略了R檔案和你的Manifest檔案。順便說一句,由於(使用)FindBugs分析你的程式碼,你至少需要編譯一次你的程式碼才能夠測試它。

PMD

簡介

這個工具有個有趣的事實:PMD不存在一個準確的名稱。(所以)在官網上你可以發現很有有趣的名稱,例如:

  • Pretty Much Done
  • Project Meets Deadline

事實上,PMD是一個工作有點類似Findbugs的強大工具,但是(PMD)直接檢查原始碼而不是檢查位元組碼(順便說句,PMD適用很多語言)。 (PMD和Findbugs)的核心目標是相同的,通過靜態分析方法找出哪些模式引起的bug。因此為什麼同時使用Findbugs和PMD呢?好吧!儘管Findbugs和PMD擁有相同的目標,(但是)他們的檢查方法是不同的。所以PMD有時檢查出的bug但是Findbugs卻檢查不出來,反之亦然。

Gradle的形式

下面的程式碼向你展示了在你的專案中使用PMD的最基本的配置(以Gradle任務為例):

task pmd(type: Pmd) {
ruleSetFiles = files("${project.rootDir}/config/quality/pmd/pmd-ruleset.xml")
ignoreFailures = false
ruleSets = []

source 'src'
include '**/*.java'
exclude '**/gen/**'

reports {
xml.enabled = false
html.enabled = true
xml {
destination "$project.buildDir/reports/pmd/pmd.xml"
}
html {
destination "$project.buildDir/reports/pmd/pmd.html"
}
}
}

就PMD來說,它幾乎與Findbugs相同。PMD支援HTML和XML兩種報告形式,所以我再次選擇HTML形式。我強烈建議你使用自己的通用配置集檔案,正如同我在這個例子(check this file)中一樣。所以,你當然應該去看下這些通用配置集檔案。我建議你,因為PMD可比FindBugs更有爭議的很多,例如:如果你不宣告”if statement”或”if statement”為空,它基本上會給你警告資訊。如果這些規則是正確的,或這對於您的專案(來說是正確的),我真的認可你和你隊友的工作。我不希望程式因為”if statement”崩潰,我認為這樣程式的可讀性很差。執行PMD任務,就像是(執行)CheckStyle任務(除了任務的名稱是“PMD”)。

PMD的使用技巧

我建議你不要使用預設的規則配置集,你需要新增這行程式碼(已經加上):

ruleSets = []

否則,因為預設值是這些基本的規則配置集,基本的規則配置集會和你定義的規則集一起執行。所以,如果你的自定義規則集不在那些基本配置集中,他們仍然會執行。

Android Lint

簡介

“Android lint工具是一個靜態程式碼分析工具,它能檢查安卓專案原始檔的潛在缺陷和優化改進的正確性,安全性,效能,可用性,可訪問性和國際化。”

正如官方網站所說,Android Lint是另一種靜態分析工具,專門為Android服務。它是非常強大的,能給你大量的建議以提高你的程式碼質量。

Gradle的形式

android {
lintOptions {
abortOnError true

lintConfig 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版本定義了全部的配置。我的演示專案中的lint檔案包含所有這些規則(ADT 21),包含等級為”ignore”的”severity”:

  • IconDensities:這個規則配置確保你定義每個影像資源中的(解析度)密度(除了ldpi)。
  • IconDipSize:這個規則配置確保你為每個dip定義合適的資源(換句話來說,如果你沒有為每個density設定相同的圖片資源,則不需要重新設定圖片大小)。

所以你可以重用這個lint檔案並啟用你想要的所有規則。執行Android Lint任務,就像執行CheckStyle任務(除了任務的名稱是”lint”)。

Android Lint的使用技巧

對於Android Lint沒有什麼特別的技巧,只需要牢記Android Lint會測試所有配置規則,除了那些等級為“ignore”的“severity”的配置。因此如果釋出了新版本ADT下的新配置規則,他們將被檢查,而不是忽視。

例項演示

現在,你有所有的方法為您的專案使用這四個工具。顯然,如果我們能同時使用這四個工具會更好。你可以新增你的gradle任務之間的依賴,比如當你執行一個任務,其他任務則是第一個完成後執行。通常在Gradle中,通過讓工具具有“check”任務來達到工具之間的相互關係:

check.dependsOn ‘checkstyle’, ‘findbugs’, ‘pmd’, ‘lint’現在,當執行“check” 任務的時候,Checkstyle, Findbugs, PMD, and Android Lint將會同時執行。在你執行/ commiting / pushing / ask merge request 之前進行質量檢查是一個很棒的方式。

你可以在這個Gradle檔案中找到所有任務的一個完整例子。你可以把所有的質量配置檔案和Gradle檔案從你看到的演示例項中分開,這些演示的例項把一起都放在“config/quality” 資料夾下。

總結

在這篇文章中,利用Gradle對Android使用程式碼質量檢查工具是非常容易。比使用質量工具區域性檢查您的專案在您自己的計算機上,這些工具可以用於自動構建如Jenkins/Hudson這樣的平臺,讓你自動進行質量檢查,同時自動建立過程。執行所有我從CLI展現的測試,如同在 Jenkins/Hudson上執行,簡單地執行:

gradle check請隨時對這篇文章發表評論,或者問任何有關Android的問題。

相關文章