前言
在Android项目开发过程中,开发团队往往要花费大量的时间和精力发现并修改代码缺陷。Java静态代码分析工具能够在代码构建过程中帮助开发人员快速、有效的定位代码缺陷并及时纠正这些问题,从而极大地提高软件可靠性并节省软件开发和测试成本。本文将着重介绍findbugs、checkstyle、pmd、lint在Android Studio中的集成方法,并结合git hook检查提交的代码。
findbugs集成
在module下的build.gradle
中添加以下代码
apply plugin: 'findbugs'
findbugs {
//工具版本
toolVersion = "3.0.1"
//忽略失败,如果检测到bug,task会执行失败,这里设置true会让task继续执行
ignoreFailures = false
//分析等级:min default max
effort = "max"
//检测bug的等级:low medium high,等级越高检测越严格
reportLevel = "high"
//exclude Filter路径
excludeFilter file('../config/quality/findbugs/findbugs-filter.xml')
}
task findbugs(type: FindBugs, group: 'verification') {
description 'Run findbugs'
//检测二进制文件路径
classes = files("${project.rootDir}/${project.getName()}/build/intermediates/classes")
source 'src'
//匹配检测的文件名
include '**/*.java'
exclude '**/gen/**'
reports {
xml.enabled = false
html.enabled = true
//配置检查报告输出路径
xml {
destination "${project.rootDir}/${project.getName()}/build/reports/findbugs/findbugs.xml"
}
html {
destination "${project.rootDir}/${project.getName()}/build/reports/findbugs/findbugs.html"
}
}
classpath = files()
}
findbugs-filter的简单配置
<FindBugsFilter>
<!-- http://stackoverflow.com/questions/7568579/eclipsefindbugs-exclude-filter-files-doesnt-work -->
<Match>
<Class name="~.*\.R\$.*"/>
</Match>
<Match>
<Class name="~.*\.Manifest\$.*"/>
</Match>
<!-- All bugs in test classes, except for JUnit-specific bugs -->
<Match>
<Class name="~.*\.*Test" />
<Not>
<Bug code="IJU" />
</Not>
</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>
OK,配置完毕,运行./gradlew findbugs
检查你的代码吧,如果你是首次集成,估计会检测出一堆不符合规范的代码,打开build/reports/findbugs/findbugs.html
可查看详情,参考Bug Descriptions处理检测出来的问题,filter的详细配置可参考FindBugs Manul。
注:findbugs检查的是二进制文件,需要编译完成后运行task。clean后直接运行注定失败,不要问为什么。。。
checkstyle集成
在module下的build.gradle
中添加以下代码
apply plugin: 'checkstyle'
checkstyle {
//工具版本
toolVersion '6.5'
//配置文件路径
configFile file('../config/quality/checkstyle/checkstyle.xml')
//filter路径
configProperties.checkstyleSuppressionFilterPath = file(
"${project.rootDir}/config/quality/checkstyle/suppressions.xml")
.absolutePath
}
task checkstyle(type: Checkstyle, group: 'verification') {
//检测代码路径
source 'src/main/java'
//排除项
exclude '**/gen/**'
exclude '**/test/**'
exclude '**/androidTest/**'
exclude '**/R.java'
exclude '**/BuildConfig.java'
//判断是否是git pre-commit hook触发的checkstyle
//如果是,只检测要提交的java文件,否则检测路径下的所有java文件
//如果不需要hook pre-commit,可移除本段代码,添加include '**/*.java'即可
if (project.hasProperty('checkCommit') && project.property("checkCommit")) {
def ft = filterCommitter(getChangeFiles())
def includeList = new ArrayList<String>()
for (int i = 0; i < ft.size(); i++) {
String spliter = ft.getAt(i)
String[] spliterlist = spliter.split("/")
String fileName = spliterlist[spliterlist.length - 1]
includeList.add("**/" + fileName)
}
if (includeList.size() == 0) {
exclude '**/*.java'
} else {
include includeList
}
} else {
include '**/*.java'
}
def configProps = ['proj.module.dir': projectDir.absolutePath]
configProperties configProps
// empty classpath
classpath = files()
}
//过滤java文件
def filterCommitter(String gitstatusinfo) {
ArrayList<String> filterList = new ArrayList<String>()
String[] lines = gitstatusinfo.split("\\n")
for (String line : lines) {
if (line.contains(".java")) {
String[] spliters = line.trim().split(" ")
for (String str : spliters) {
if (str.contains(".java")) {
filterList.add(str)
}
}
}
}
return filterList
}
//获取git commit的文件列表
def getChangeFiles() {
try {
String changeInfo = 'git status -s'.execute(null, project.rootDir).text.trim()
return changeInfo == null ? "" : changeInfo
} catch (Exception e) {
return ""
}
}
//编译时先运行checkstyle,会略微降低编译速度
preBuild.dependsOn('checkstyle')
OK,checkstyle也配置完毕了,运行’./gradlew checkstyle’检查你的代码吧,又一堆不符合规范的代码迎面而来,打开build/reports/checkstyle/checkstyle.html
可查看详情。
注:checkstyle.xml
和suppressions.xml
由于篇幅原因就不贴代码了,文末给连接。
pmd集成
在module下的build.gradle
中添加以下代码
apply plugin: 'pmd'
def configDir = "${project.rootDir}/config/quality"
def reportsDir = "${project.buildDir}/reports"
task pmd(type: Pmd) {
//忽略失败,如果设置为true,检测出bug会停止task
ignoreFailures = false
//filter路径
ruleSetFiles = files("$configDir/pmd/pmd-ruleset.xml")
ruleSets = []
//检测资源路径
source 'src/main/java'
//排除项
exclude '**/gen/**'
//判断是否是git pre-commit hook触发的pmd
if (project.hasProperty('checkCommit') && project.property("checkCommit")) {
def ft = filterCommitter(getChangeFiles())
def includeList = new ArrayList<String>()
for (int i = 0; i < ft.size(); i++) {
String spliter = ft.getAt(i)
String[] spliterlist = spliter.split("/")
String fileName = spliterlist[spliterlist.length - 1]
includeList.add("**/" + fileName)
}
if (includeList.size() == 0) {
exclude '**/*.java'
} else {
include includeList
}
} else {
include '**/*.java'
}
reports {
xml.enabled = false
html.enabled = true
xml {
destination "$reportsDir/pmd/pmd.xml"
}
html {
destination "$reportsDir/pmd/pmd.html"
}
}
}
OK,pmd也集成完毕啦,运行./gradlew pmd
检查你的代码吧,又一堆不合规范的警告铺面而来~打开build/reports/pmd/pmd.html
可查看详情,点击每一个错误警告可跳转对应的说明,按照说明修改即可,如果想忽略某个错误警告,可参照pmd-ruleset.xml
配置。
注:pmd.html
同样在文末给出。
lint集成
在module下的build.gradle
中添加以下代码
android {
lintOptions {
abortOnError false //检查到错误时是否停止task
xmlReport false
htmlReport true
//配置文件路径
lintConfig file("$configDir/lint/lint.xml")
//检测结果输出路径
htmlOutput file("$reportsDir/lint/lint-result.html")
xmlOutput file("$reportsDir/lint/lint-result.xml")
}
}
OK,lint集成完毕,运行./gradlew lint
检测代码吧。。。。。打开build/reports/lint/lint.html
可查看详情。
同时运行
在module下的build.gradle
中添加以下代码
check.dependsOn 'checkstyle', 'findbugs', 'pmd', 'lint'
运行命令./gradlew check
简单的集成方式
说了这么多,肯定不会让你一个个的去集成,简单的方法肯定是有的啦,参考QualitySample
- 下载QualitySample.zip,将
config/
拷贝到项目根目录 - 在
build.gradle
中添加apply from: '../config/quality.gradle'
- 运行
./config/install.sh
(添加git hooks) - 没有第四步
至此,findbugs checkstyle pmd lint已经全部配置完毕,修改代码通过git提交时会先运行checkstyle和pmd检查提交的代码是否符合规范,只有符合规范才能通过完成提交。
总结
本文主要讲述findbugs、checkstyle、pmd、lint在android studio中的配置,提供了快速配置四种静态代码检查工具的方法,具体Filter的配置请参考文中给出的官方链接,不同项目不同团队对于代码的风格不尽相同,但是对于代码中存在的缺陷、性能问题、隐藏bug都是零容忍的,所以说Java静态代码检测工具尤为重要。