Android项目中配置Lint和Checkstyle
了解Android上lint,insepections以及checkstyle:Android静态代码分析
-
Android Lint,它只是检测和Android日常开发中一些问题,比如xml资源中hardcode text。
在将配置之前,首先需要澄清一点,Android的lint工具是sdk自带的,它在~/Library/Android/sdk/tools/bin目录下,可以通过lint --list查看当前lint版本所支持的所有issue列表,通过lint --show也可以查看当前lint所支持的所有issue详细描述。
Android Lint总体上还分了以下categories:
Correctness
Correctness:Messages
Correctness:Chrome OS
Security
Performance
Usability:Typography
Usability:Icons
Usability
Accessibility
Internationalization
Internationalization:Bidirectional Text随意选取其中一个详细信息(另外也可通过lint --show issueId查看具体某个issueId的详细信息):
如上图:
RtlEnabled:issued id,同时还显示了RtlEnabled的Priority,Severity,Category。
- 配置lint:
-
如果在Android的项目中可以直接运行./gradlew lint或者./gradlew xxxProject:lint即可运行相关的project,运行完成之后也会生成具体的report:
这里暂以html打开就能看到一个Overview,显示有哪些错误,其中Security是lint其中一个category,同时lint还默认disable一些checks,如果还需disable更多的话,可以在lintOptions里配置对应的issueId为ignore或者添加lint.xml进行配置:
-
有些项目会根据实际情况会对默认lint提供的issues进行一些修改,比如修改它的serverity,disable一些issues,具体怎么配置呢,其实只需要在对应project的build.gradle中添加lintOptions即可:
lintOptions { abortOnError false //当运行./gradlew lint时,出现错误不中断 check "HardcodedText" //指定要检查的issue列表 error "HardcodedText" //修改HardcodedText的优先级为error //另外也可以结合lint.xml来进行配置,也可以只用lint.xml这个看具体需要 lintConfig file("../lint.xml") //默认会加载当前路径的lint.xml,如果lint.xml没有放在当前项目目录,则需要通过lintConfig进行指定 }
lint.xml
<?xml version="1.0" encoding="UTF-8"?> <lint> <!--配置severity为ignore相当于关闭此issue--> <issue id="RestrictedApi" severity="ignore"/> <issue id="ExportedService" severity="ignore"/> </lint>
这样配置之后,在重新执行./gradlew lint,就没有相关的lint提示了,另外也可以但多运行./gradlew lintDebug或者说./gradlew lintRelease,如果只是运行lint的话,它会默认运行所有的buildType。
总体来说,lint配置还是很简单的。
useful links:
-
Checkstyle 可以检测项目中的code style,保证团队成员开发的code风格一致,如:line length不能超过100(可设置),方法,变量,类的命名等。
Checkstyle是一个开源的工具,github地址, 它提供了很多的module来进行配置,类似于Android lint的issues,查看具体的checks。
配置checkstyle
-
在build.gradle
apply plugin: 'checksytle' task checkstyle(type: Checkstyle) { configFile rootProject.file('checkstyle/checkstyle.xml') source 'src/main/java' exclude '**/gen/**' ignoreFailures false showViolations true include '**/*.java' reports { xml.enabled false html.enabled true html.stylesheet resources.text.fromFile('../checkstyle/xsl/checkstyle-custom.xsl') } classpath = files() }
先看下面的checkstyle-custom.xsl文件,这个xsl文件,可以让checksytle以不同的样式进行展现,常见的样式可以点这里,另外也可以参考这里,看下gradle checkstyle官方的文档。运行./gradlew checkstyle生成report,下面是我用上面的样式生成的report:
-
-
接着看checkstyle/checkstyle.xml的配置文件,下面是它的内容
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd"> <module name="Checker"> <module name="SuppressionFilter"> <property name="file" value="checkstyle/checkstyle-suppressions.xml"/> <property name="optional" value="false"/> </module> <!--module name="NewlineAtEndOfFile"/--> <module name="FileLength"/> <module name="FileTabCharacter"/> <!-- Trailing spaces --> <module name="RegexpSingleline"> <property name="format" value="\s+$"/> <property name="message" value="Line has trailing spaces."/> </module> <!-- Space after 'for' and 'if' --> <module name="RegexpSingleline"> <property name="format" value="^\s*(for|if)[^ ]\("/> <property name="message" value="Space needed before opening parenthesis."/> </module> <!-- For each spacing --> <module name="RegexpSingleline"> <property name="format" value="^\s*for \(.*?([^ ]:|:[^ ])"/> <property name="message" value="Space needed around ':' character."/> </module> <module name="TreeWalker"> <!--<property name="cacheFile" value="${checkstyle.cache.file}"/>--> <!-- Checks for Javadoc comments. --> <!-- See http://checkstyle.sf.net/config_javadoc.html --> <!--module name="JavadocMethod"/--> <!--module name="JavadocType"/--> <!--module name="JavadocVariable"/--> <!--module name="JavadocStyle"/--> <!-- Checks for Naming Conventions. --> <!-- See http://checkstyle.sf.net/config_naming.html --> <!--<module name="ConstantName"/>--> <module name="LocalFinalVariableName"/> <module name="LocalVariableName"/> <module name="MemberName"/> <module name="MethodName"> <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/> </module> <module name="PackageName"/> <module name="ParameterName"/> <module name="StaticVariableName"/> <module name="TypeName"/> <!-- Checks for imports --> <!-- See http://checkstyle.sf.net/config_import.html --> <module name="AvoidStarImport"/> <module name="IllegalImport"/> <module name="RedundantImport"/> <module name="UnusedImports"> <property name="processJavadoc" value="true"/> </module> <!-- Checks for Size Violations. --> <!-- See http://checkstyle.sf.net/config_sizes.html --> <module name="LineLength"> <property name="max" value="120"/> </module> <module name="MethodLength"> <property name="max" value="200"/> </module> <!--module name="ParameterNumber"/--> <!-- Checks for whitespace --> <!-- See http://checkstyle.sf.net/config_whitespace.html --> <module name="GenericWhitespace"/> <module name="EmptyForIteratorPad"/> <module name="MethodParamPad"/> <!--<module name="NoWhitespaceAfter"/>--> <module name="NoWhitespaceBefore"/> <module name="OperatorWrap"> <property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, QUESTION, SL, SR, STAR"/> <property name="option" value="nl"/> </module> <module name="ParenPad"/> <module name="TypecastParenPad"/> <module name="WhitespaceAfter"/> <module name="WhitespaceAround"/> <!-- Modifier Checks --> <!-- See http://checkstyle.sf.net/config_modifiers.html --> <module name="ModifierOrder"/> <module name="RedundantModifier"/> <!-- Checks for blocks. You know, those {}'s --> <!-- See http://checkstyle.sf.net/config_blocks.html --> <!--module name="AvoidNestedBlocks"/--> <!--module name="EmptyBlock"/--> <module name="LeftCurly"/> <!--module name="NeedBraces"/--> <module name="RightCurly"/> <!-- Checks for common coding problems --> <!-- See http://checkstyle.sf.net/config_coding.html --> <!--module name="AvoidInlineConditionals"/--> <module name="CovariantEquals"/> <module name="EmptyStatement"/> <!--<module name="EqualsAvoidNull"/>--> <module name="EqualsHashCode"/> <!--module name="HiddenField"/--> <module name="IllegalInstantiation"/> <!--<module name="InnerAssignment"/>--> <!--module name="MagicNumber"/--> <module name="MissingSwitchDefault"/> <!--<module name="RedundantThrows"/>--> <module name="SimplifyBooleanExpression"/> <module name="SimplifyBooleanReturn"/> <!-- Checks for class design --> <!-- See http://checkstyle.sf.net/config_design.html --> <!--module name="DesignForExtension"/--> <!--module name="FinalClass"/--> <!--module name="HideUtilityClassConstructor"/--> <!--module name="InterfaceIsType"/--> <!--module name="VisibilityModifier"/--> <!-- Miscellaneous other checks. --> <!-- See http://checkstyle.sf.net/config_misc.html --> <!--module name="ArrayTypeStyle"/--> <!--module name="FinalParameters"/--> <!--module name="TodoComment"/--> <module name="UpperEll"/> </module> </module>
可以看到它配置了不同的module来对我们的项目进行检测。那么如果要对某些文件的某些module进行过滤,怎么办呢?其实这上面的xml配置中已经写出来了,配置一个SuppressionFilter即可
<module name="SuppressionFilter"> <property name="file" value="checkstyle/checkstyle-suppressions.xml"/> <property name="optional" value="false"/> </module>
-
那我们 来看看checkstyle-suppressions.xml这个文件到底是怎么配置的呢?
<?xml version="1.0"?> <!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.2//EN" "http://checkstyle.sourceforge.net/dtds/suppressions_1_2.dtd"> <suppressions> <!--<suppress checks="LineLength" files="**/eventbus/events/*.java"/>--> <suppress checks="AvoidStarImport|LineLength|WhitespaceAround|MethodName|RedundantImport|LeftCurlyCheck|ParameterNameCheck" files=".*/eventbus/events/.*.java"/> <suppress checks="RegexpSingleline|LineLength|LocalFinalVariableName" files=".*/utils/extend/.*.java"/> </suppressions>
可以看到checks属性对应的就是module的名字,files就是需要过滤的文件,这样在重新运行./gradlew checkstyle。这些文件对应的modules就不会进行检测。
如果想将让checkstyle加入到git-hooks,戳这里在Git hook上配置Android Lint和Checkstyle