在今天的教程中,我们将学习如何使用一些Java静态代码分析工具来确保项目中的高质量Android代码。 我们将介绍Checkstyle,FindBugs,PMD和Android Studio Lint,它们都是免费和开源的!
什么是静态代码分析工具?
这些工具可以解析和分析源代码,而无需实际执行。 目的是发现潜在的漏洞,例如错误和安全漏洞。 流行的免费静态代码分析器(例如FindBugs)根据代码应遵循的一组规则检查您的代码-如果代码不遵循这些规则,则表明可能有问题。 可以将静态代码分析工具视为在最终编译为系统语言之前运行的其他编译器。
除了在构建过程中进行代码审查和单元测试外,许多软件公司还要求项目通过静态代码分析测试。 即使是开源项目的维护者,在构建过程中通常也包含一个或多个静态代码分析步骤。 因此,学习静态分析是编写高质量代码的重要一步。 请注意,静态代码分析(也称为“白盒”测试)不应被视为源代码的单元测试的替代。
在本教程中,我们将学习一些可用于Android和Java的流行静态分析工具。 但是首先,让我们看看使用静态分析的一些好处。
好处
- 帮助检测甚至单元或手动测试都可能遗漏的潜在错误。
- 定义特定于项目的规则。 例如,静态分析作为构建链的一部分,可以帮助新手快速掌握其新团队的代码标准。
- 帮助您提高对新语言的了解。
- 扫描整个项目,包括您可能从未读过的文件。
建立
我们将在本教程中学习的所有代码分析工具都可以作为Gradle插件使用,因此我们可以为每个工具创建单独的Gradle任务。 让我们使用一个包含所有内容的Gradle文件。 但是在此之前,让我们创建一个文件夹,其中将包含用于静态代码分析的所有文件。
打开Android Studio并在app模块内部(在Project视图中),创建一个新文件夹,并将其命名为code_quality_tools 。 此文件夹将包含用于代码分析工具的XML文件,并且还将具有Gradle文件quality.gradle ,它将运行我们的静态分析任务。
最后,访问app模块文件夹中的build.gradle ,并在文件末尾添加以下行:
apply from: '/code_quality_tools/quality.gradle'
在这里,我们的质量。 gradle Gradle脚本正在引用其本地文件位置。
Checkstyle
给定您在XML文件中指定的规则以强制执行项目的编码标准, Checkstyle通过分析源代码并将其与已知的编码标准或约定进行比较来强制执行这些规则。
Checkstyle是社区积极维护的开源工具 。 这意味着您可以创建自己的自定义检查或修改现有检查以适合您的需求。 例如,Checkstyle可以检查类中的常量名称(最终名称,静态名称或两者)。 如果您的常量名称不遵循大写规则,且单词之间用下划线分隔,则该问题将在最终报告中加以标记。
// 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进行验证的规则或检查。 一条规则是避免星际导入(ImpactStarImport) , 顾名思义 ,它检查源代码是否包含诸如java.util.*
的导入语句。 (相反,您应该显式指定要导入的包,例如java.util.Observable
。)
有些规则具有属性,可以像对ParameterNumber一样进行设置-这限制了方法或构造函数的参数数量。 默认情况下,属性max
为7,但我们改为将其更改为6。 看看Checkstyle网站上的其他一些检查 。
要运行此检查,我们需要创建一个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插件 。 我们给了它一个描述,并将其添加到一个已经预定义的Gradle组中,称为Verification。
我们关注的Checkstyle Gradle 任务的关键属性是:
- configFile :要使用的Checkstyle配置文件。
- IgnoreFailures :如果出现警告,是否允许继续构建。
- include :一组包含模式。
- exclude :一组排除模式。 在这种情况下,我们不扫描生成的类。
最后,您可以通过访问Android Studio上的Gradle工具窗口,打开验证组,然后单击checkstyle运行任务来运行Gradle脚本。
另一种方法是使用命令行:
gradle checkstyle
任务完成运行后,将生成报告,该报告可在应用程序模块>构建>报告> checkstyle中获得 。 您可以打开checkstyle.html查看报告。
Checkstyle插件可免费用于Android Studio或IntelliJ IDEA。 它提供对Java文件的实时扫描。
PMD
PMD是另一个用于分析源代码的开源代码分析工具。 它会发现常见的缺陷,例如未使用的变量,空的catch块,不必要的对象创建等。 PMD有许多规则集可供选择。 作为“ 设计规则”集中的一部分的规则的示例为:
-
SimplifyBooleanExpressions
:避免在布尔表达式中进行不必要的比较,使复杂的代码复杂化。 一个例子:
public class Bar {
// can be simplified to
// bar = isFoo();
private boolean bar = (isFoo() == true);
public isFoo() { return false;}
}
PMD是使用pmd .xml文件配置的。 在其中,我们将包含一些配置规则,例如适用于Android , Naming和Design的规则 。
<?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 :此任务的来源。
- reports :此任务要生成的报告。
最后,您可以通过访问Gradle工具窗口,打开验证组文件夹,然后单击pmd运行任务来运行Gradle脚本。 或者,您可以通过命令行运行它:
gradle pmd
执行任务后,还将生成报告,可通过应用程序模块>构建>报告> pmd获得该报告 。 还有一个可用于IntelliJ或Android Studio的PMD插件 ,供您下载和集成(如果需要)。
查找错误
FindBugs是另一个免费的静态分析工具,它通过根据已知的错误模式列表检查字节码,分析类以寻找潜在问题。 他们之中有一些是:
- 类定义hashCode()而不是equals() :类实现hashCode()方法但不实现equals()-因此,两个实例可能相等,但没有相同的哈希码。 这属于不良行为类别。
- int值与long常量的错误比较 :代码正在将int值与long常量进行比较,该long常量超出可以表示为int值的值的范围。 这种比较是空洞的,可能会产生意想不到的结果。 这属于正确性类别。
- TestCase没有测试 :class是一个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>
最后,我们将findbugs任务包含在quality.gradle中 :
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
:分析努力水平。 指定的值应该是min
,default
或max
。 请注意,更高的级别会提高精度,并以运行时间和内存消耗为代价来发现更多错误。 -
reportLevel
:报告错误的优先级阈值。 如果设置为低,将报告所有错误。 如果设置为中(默认),则报告中和高优先级错误。 如果设置为高,则仅报告高优先级的错误。 -
excludeFilter
:一个过滤器的文件名,它指定了我们已经创建的要报告的错误。
然后,您可以通过以下方式运行Gradle脚本:访问Gradle工具窗口,打开验证组文件夹,然后单击findbugs以运行任务。 或从命令行启动它:
gradle findbugs
任务完成执行后,还将生成报告。 这将在应用程序模块>构建>报告> findbugs中可用。 FindBugs插件是另一个免费提供的插件,可以下载并与IntelliJ IDEA或Android Studio集成。
Android Lint
Lint是另一种代码分析工具,但默认情况下该工具随附于Android Studio。 它检查您的Android项目源文件是否存在潜在的错误,以及是否正确,安全,性能,可用性,可访问性和国际化方面的优化。
要配置Lint,您必须在模块级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,方法是单击“ 分析”菜单,选择“ 检查代码...” (检查范围是整个项目),然后单击“ 确定”按钮继续。
您还可以通过访问Gradle工具窗口,打开验证组,然后单击lint来运行Lint。 最后,您可以通过命令行运行它。
在Windows上:
gradlew lint
在Linux或Mac上:
./gradlew lint
任务完成执行后,还将生成报告,该报告可从应用程序模块>构建>输出> lint-results.html获得 。
奖励:严格模式
StrictMode是一种开发人员工具,可帮助防止您的项目开发人员在主线程上执行任何意外的Flash I / O或网络I / O,因为这可能导致应用程序运行缓慢或反应迟钝。 它还有助于防止显示ANR(应用无响应)对话框。 纠正StrictMode问题后,您的应用程序将变得更加敏感,用户将享受更流畅的体验。 StrictMode使用两组策略来执行其规则:
- VM策略 :防止不良的编码习惯,例如不关闭
SQLiteCursor
对象或创建的任何Closeable
对象。 - 线程 策略 :查找在主应用程序线程而不是后台线程上执行的诸如闪存I / O和网络I / O之类的操作。
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());
}
上面的代码可以在您的应用程序,活动或其他应用程序组件的onCreate()
方法中。
可以在本文的GitHub存储库中找到实现上述所有功能的示例Android项目,包括用于典型Android项目的工具规则集。
结论
在本教程中,您学习了如何使用静态代码分析工具确保高质量的Android代码:它们是什么,使用它们的好处,以及如何在应用程序中使用Checkstyle,FindBugs,Lint,PMD和StrictMode。 继续尝试这些工具-您可能会发现代码中出乎意料的问题。