Android Lint & Checkstyle

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的详细信息):

    image.png

    如上图:

    RtlEnabled:issued id,同时还显示了RtlEnabled的Priority,Severity,Category。

    • 配置lint:
    1. 如果在Android的项目中可以直接运行./gradlew lint或者./gradlew xxxProject:lint即可运行相关的project,运行完成之后也会生成具体的report:

      image.png

这里暂以html打开就能看到一个Overview,显示有哪些错误,其中Security是lint其中一个category,同时lint还默认disable一些checks,如果还需disable更多的话,可以在lintOptions里配置对应的issueId为ignore或者添加lint.xml进行配置:

  1. 有些项目会根据实际情况会对默认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:

    Writing custom lint rules

    使用lint改进你的代码

    DSL object for configuration lint options

  • Checkstyle 可以检测项目中的code style,保证团队成员开发的code风格一致,如:line length不能超过100(可设置),方法,变量,类的命名等。

    Checkstyle是一个开源的工具,github地址, 它提供了很多的module来进行配置,类似于Android lint的issues,查看具体的checks

    配置checkstyle

    1. 在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:

      image.png
  1. 接着看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>
    
  2. 那我们 来看看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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352