使用靜態分析工具SAT來確保高品質的安卓代碼
Chinese (Traditional) (中文(繁體)) translation by zheban (you can also view the original English article)
在今天的教程中,我們將學習如何使用一些靜態代碼分析工具來確保項目中高品質的Android代碼。我們將研究Checkstyle,FindBugs,PMD和Android Studio Lint,它們都是免費和開源的!
什麼是靜態代碼分析工具?
靜態代碼分析工具是解析和分析代碼而不實際執行代碼的工具。它的目的是找出潛在的漏洞,例如錯誤和安全性漏洞。 一個受歡迎的免費靜態代碼分析器(如FindBugs)可以根據你代碼應遵循的一組規則來檢查你的代碼 - 如果代碼不遵循這些規則,那麼可能是某些地方出錯了。 可以將靜態代碼分析工具看作在最終編譯成系統語言之前運行的附加編譯器。
除了在構建過程中進行代碼審查和單元測試以為,許多軟體公司都要求專案通過靜態代碼分析測試。 甚至開源項目的維護者通常也會在構建過程中引入靜態代碼分析。所以學習靜態分析是編寫高品質代碼的重要一步。 請注意,靜態代碼分析(也稱為“白盒”)測試不應代替原始程式碼的單元測試。
在本教程中,我們將學習一些可用於Android和Java的流行靜態分析工具。但我們先來看看使用靜態分析的好處。
好處
- 即使單元測試或手動測試可能錯過的潛在錯誤,靜態代碼分析也能説明檢測到。
- 定義與專案相關的特定規則。例如,作為構建鏈中一部分的靜態分析可以説明新手加快新團隊的代碼標準化。
- 説明你提高對新語言的瞭解。
- 掃描整個專案,包括您可能沒有閱讀過的檔。
設置
我們將在本教程中學到的所有代碼分析工具都可以作為Gradle外掛程式,所以我們可以為每個外掛程式創建單獨的Gradle任務。 我們使用包含靜態分析工具的單一Gradle檔。但在此之前,讓我們創建一個資料夾,裡面包含我們所有的靜態代碼分析檔。
打開Android Studio和app module(在Project視圖中),創建一個新資料夾,將其命名為code_quality_tools。該資料夾將包含用於代碼分析工具的XML檔和一個Gradle檔quality.gradle,後者將運行我們的靜態分析任務。



最後,打開app module資料夾中的build.gradle,並將此行添加在文件末尾:
apply from: '/code_quality_tools/quality.gradle'
在這裡,我們的quality.gradle Gradle腳本正在應用於其本地檔位置的引用。
Checkstyle
在XML檔中指定規則以強制執行專案的編碼標準,Checkstyle通過分析原始程式碼來執行這些規則,並將其與已知的編碼標準或約定進行比較。
Checkstyle是一個由社區積極維護的開源工具。這意味著您可以通過創建自己的自訂檢查或修改現有的檢查以滿足您的需要。 例如,Checkstyle可以對類中的常量名稱(final,static或both)進行檢查。 如果您的常數名稱不符合大寫字母被底線分隔的的規則,問題就會被標記出來。
// incorrect private final static String myConstant = "myConstant"; // correct private final static String MY_CONSTANT = "myConstant";
集成Checkstyle
我將展示如何將Checkstyle集成到我們的Android Studio專案中,並演示一個具體的例子。
首先,我們需要創建我們的編碼規則。在checkstyle.xml中,我們創建了一些檢查代碼的Checkstyle配置規則。
<?xml version="1.0"?><!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.2//EN" "http://www.puppycrawl.com/dtds/configuration_1_2.dtd"> <module name="Checker"> <module name="FileTabCharacter"/> <module name="TreeWalker"> <!-- Checks for Naming Conventions --> <!-- See http://checkstyle.sourceforge.net/config_naming.html --> <module name="MethodName"/> <module name="ConstantName"/> <!-- Checks for Imports --> <!-- See http://checkstyle.sourceforge.net/config_imports.html--> <module name="AvoidStarImport"/> <module name="UnusedImports"/> <!-- Checks for Size --> <!-- See http://checkstyle.sourceforge.net/config_sizes --> <module name="ParameterNumber"> <property name="max" value="6"/> </module> <!-- other rules ignored for brevity --> </module>
在上面的代碼中,我們引入了希望Checkstyle檢查原始程式碼的規則。 一個規則是AvoidStarImport,望文生義,這個規則用來檢查您的原始程式碼是否包含像java.util.*
的import語句。 (相反,您應該明確指定要導入的包,例如java.util.Observable
。)
一些規則是有屬性的,這些屬性可以設置,就像設置ParameterNumber一樣,這限制了一個方法或構造函數的參數數量。 預設情況下,屬性max
為7,但我們修改為6。看看 other checks on the Checkstyle website。
要運行此檢查,我們需要創建一個Gradle任務。所以訪問quality.gradle檔並創建一個名為checkstyle的任務:
apply plugin: 'checkstyle' task checkstyle(type: Checkstyle) { description 'Check code standard' group 'verification' configFile file('./code_quality_tools/checkstyle.xml') source 'src' include '**/*.java' exclude '**/gen/**' classpath = files() ignoreFailures = false }
注意,在上面的代碼中,我們首先用了Checkstyle Gradle外掛程式。然後我們給它一個描述,並將其添加到已經預定義的叫verification的Gradle組。
我們關心的Checkstyle Gradle任務的關鍵屬性是:
- configFile:要使用的Checkstyle設定檔。
- IgnoreFailures:如果有警告,是否允許繼續操作
- include:引入的模式集合
- exclude:排除的屬性集合。在這種情況下,我們不掃描產生的類。
最後,您可以通過訪問Android Studio上的Gradle工具視窗來運行Gradle腳本,然後打開verification組,然後按一下checkstyle來運行任務。



另外一種方法是使用命令列:
gradle checkstyle
任務運行完成後會生成一份報告,在app module > build > reports > checkstyle查看該報告。 您可以打開checkstyle.html查看報告具體內容。



Checkstyle外掛程式在Android Studio或IntelliJ IDEA中是免費的。 它提供對Java檔的即時掃描。
PMD
PMD是另一個開原始程式碼分析工具,主要用於分析原始程式碼。 它可以發現常見的缺陷,比如未使用的變數,空的catch塊,不必要的物件創建等等。 PMD有許多可以選擇的規則集。 Design Rules 集合中的一個例子是:
-
SimplifyBooleanExpressions
:避免在布林運算式中進行不必要的比較,這會使簡單的代碼複雜化。 比如:
public class Bar { // can be simplified to // bar = isFoo(); private boolean bar = (isFoo() == true); public isFoo() { return false;} }
PMD配置了pmd.xml文件。在那個檔裡面,我們將引入一些配置規則,例如Android,命名和設計。
<?xml version="1.0"?> <ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Android Application Rules" xmlns="http://pmd.sf.net/ruleset/1.0.0" xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd" xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"> <description>Custom ruleset for Android application</description> <exclude-pattern>.*/R.java</exclude-pattern> <exclude-pattern>.*/gen/.*</exclude-pattern> <!-- Android ---> <!-- http://pmd.sourceforge.net/pmd-4.3.0/rules/android.html --> <rule ref="rulesets/java/android.xml"/> <!-- Design --> <!-- http://pmd.sourceforge.net/pmd-4.3.0/rules/design.html --> <rule ref="rulesets/java/design.xml"> <exclude name="UncommentedEmptyMethod"/> </rule> <!-- Naming --> <!-- http://pmd.sourceforge.net/pmd-4.3.0/rules/naming.html --> <rule ref="rulesets/java/naming.xml/ShortClassName"> <properties> <property name="minimum" value="3"/> </properties> </rule> <!-- other rules ignored for brevity --> </ruleset>
就像Checkstyle一樣,我們還需要創建一個PMD Gradle任務,以便在quality.gradle檔中執行檢查。
apply plugin: 'pmd' task pmd(type: Pmd) { description 'Run PMD' group 'verification' ruleSetFiles = files("./code_quality_tools/pmd.xml") source 'src' include '**/*.java' exclude '**/gen/**' reports { xml.enabled = false html.enabled = true } ignoreFailures = false }
我們創建的任務的關鍵屬性是:
- ruleSetFiles:要使用的自訂規則集檔。
- source:任務來源。
- 報告:任務生成的報告。
最後,您可以通過打開Gradle工具視窗運行Gradle腳本,打開驗證組資料夾,然後按一下pmd來運行該任務來。或者您可以通過如下命令列運行它:
gradle pmd
任務執行完後生成的報告在app module > build > reports > pmd。還有一個適用於IntelliJ或Android Studio的PMD外掛程式可供您下載並集成(如果需要)。
FindBugs
FindBugs是另一個免費的靜態分析工具,它通過將您的位元組碼與已知的錯誤模式清單匹配來查找潛在問題。其中一些是:
- 類定義了hashCode()方法,但沒有定義equals()方法:一個類實現了hashCode()方法,而沒有實現equals()方法 - 因此兩個沒有相同的雜湊碼實例也可能相等。這屬於不良做法。
- int值與長整型常數的比較:將int值與長整型常數比較,而長整型常數超出了int值的表示範圍。 這種比較可能會產生意想不到的結果。不過這屬於正常範疇。
- TestCase沒有測試:JUnit
TestCase
沒有實現任何測試方法。這種模式也是正確的。
FindBugs是一個開源項目,因此您可以查看,貢獻或監控GitHub上原始程式碼的進度。
在findbugs-exclude.xml檔中,我們希望阻止FindBugs在我們的專案中掃描一些類(使用規則運算式),例如自動生成的資源類和自動生成的清單類。 此外,如果您使用Dagger,我們希望FindBugs不檢查生成的Dagger類。我們也可以告訴FindBugs忽略一些規則。
<FindBugsFilter> <!-- Do not check auto-generated resources classes --> <Match> <Class name="~.*R\$.*"/> </Match> <!-- Do not check auto-generated manifest classes --> <Match> <Class name="~.*Manifest\$.*"/> </Match> <!-- Do not check auto-generated classes (Dagger puts $ into class names) --> <Match> <Class name="~.*Dagger*.*"/> </Match> <!-- http://findbugs.sourceforge.net/bugDescriptions.html#ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD--> <Match> <Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" /> </Match> </FindBugsFilter>
最後,在quality.gradle中引入findbugs任務。
apply plugin: 'findbugs' task findbugs(type: FindBugs) { description 'Run findbugs' group 'verification' classes = files("$project.buildDir/intermediates/classes") source 'src' classpath = files() effort 'max' reportLevel = "high" excludeFilter file('./code_quality_tools/findbugs-exclude.xml') reports { xml.enabled = false html.enabled = true } ignoreFailures = false }
在上面的第一行,我們把FindBugs作為Gradle外掛程式使用,然後創建一個名為findbugs
的任務。我們真正關心的findbugs
任務的關鍵屬性是:
-
classes
:要分析的類。
-
effort
:分析effort水準。指定值應為min
,default
或max
其中之一。級別越高精度越高,發現的錯誤越多,不過代價是需要執行時間和消耗記憶體。 -
reportLevel
:報告錯誤的優先順序閾值。如果reportLevel設置為低,則會報告所有錯誤。如果設置為中等(默認),會報告中、高優先順序錯誤。如果設置為高,則僅報告高優先順序的錯誤 -
excludeFilter
:排除指定錯誤的篩檢程式名。
然後,您可以通過訪問Gradle工具視窗運行Gradle腳本,打開verification組資料夾,然後按一下findbugs來運行該任務。或者從命令列啟動它:
gradle findbugs
當任務執行完成時,生成的報告在app module> build> reports> findbugs中找到。 FindBugs外掛程式免費,可在與IntelliJ IDEA或Android Studio下載和集成。
Android Lint
Lint是另一個代碼分析工具,Android Studio默認自帶。它檢查您的Android專案原始檔案是否有潛在的錯誤和優化的正確性,安全性,性能,可用性,可訪問性和國際化。
要配置Lint,您必須在module級的build.gradle文件中引入lintOptions {}
塊:
lintOptions { abortOnError false quiet true lintConfig file('./code_quality_tools/lint.xml') }
我們關心的關鍵Lint選項是:
-
abortOnError
:如果發現錯誤,lint是否應該設置進程的退出代碼。 -
quiet
:是否關閉分析進度報告。 -
lintConfig
:要使用的默認設定檔。
您的lint.xml檔可以包含您希望Lint忽略或修改的主題,例如下面的示例:
<?xml version="1.0" encoding="UTF-8"?> <lint> <!-- Disable the given check in this project --> <issue id="IconMissingDensityFolder" severity="ignore" /> <!-- Change the severity of hardcoded strings to "error" --> <issue id="HardcodedText" severity="error" /> </lint>
Android Studio手動運行Lint的步驟,按一下Analyze功能表,選擇Inspect Code....(檢查範圍是整個專案),然後按一下確定按鈕繼續。






您還可以通過打開Gradle工具視窗,打開verification組,然後按一下lint來運行Lint。最後,您可以通過命令列運行它。
在Windows系統上:
gradlew lint
在Linux或Mac系統上:
./gradlew lint
當任務運行完成後會生成一個報告,該報告可以在app module> build> outputs> lint-results.html中找到。
Bonus: StrictMode
StrictMode是開發者工具,可防止開發者在主執行緒上執行意外的快閃記憶體I / O或網路I / O,因為這可能導致應用程式緩慢或無回應。 它也有助於防止出現ANR(App Not Responding)對話方塊。 使用StrictMode後,您的APP將變得更加絲滑,用戶將享受更流暢的體驗。 StrictMode使用兩群組原則來執行其規則:
if (BuildConfig.DEBUG) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() // or .detectAll() for all detectable problems .penaltyLog() // Log detected violations to the system log. .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .penaltyDeath() // Crashes the whole process on violation. .build()); }
上面的代碼可以在你的Application,Activity或其他Activity元件的onCreate()
方法中。
您可以在Envato Tuts +上瞭解更多關於StrictMode
的資訊。
在文章GitHub repo中,可以找到上面所有的代碼示例,包括Android代碼專案工具的規則集。
結語
在本教程中,你學到了如何使用靜態代碼分析工具確保高品質的Android代碼:它們是什麼,使用它們的好處,以及如何在應用程式中使用Checkstyle,FindBugs,Lint,PMD和StrictMode。 繼續使用這些工具 - 你可能會發現一些您從未意識到的代碼問題。
與此同時,請查看其他關於Android應用程式開發的教程!