为了账号安全,请及时绑定邮箱和手机立即绑定

加强静态代码检测级别在编译期检测存在风险的代码

标签:
Android

使用背景:由于Android版本的迭代,google在不同版本新增了不同的方法,如果使用了大于APP所规定的min API方法的时候,但是编译能过,这将会导致线上出现No Method的Crash问题,如果能在编译期就使用lint工具检测出问题就好了。由于经历了血淋淋的教训,以下给出了解决痛点的办法。

1.初识lint

lint 是google 给出的静态代码检测工具,用于分析包括内存泄漏,纠正代码规范,查找疑似BUG等。。。<br>
windows环境下位于你的AndroidSDK安装位置下的tools目录下的lint.bat<br>

2.在Android Studio中通过图形界面直观感受Lint

贴心的Android Studio已经为我们集成了好了lint相关的功能,下图介绍了直观感受lint对项目代码不规范处给出的建议<br>
下图是项目中存在问题的代码,一个是app min 14的时候,用了api 16的方法,另一个则是经典的handler匿名内部类导致持有外部类引用导致内存泄漏<br>

QQ图片20170123191535.png

在android studio 中使用lint 静态代码检测工具<br>
QQ图片20170123191130.png

建议检测的范围为Module 级别(各个scope作用范围都可以试试看)<br>
QQ图片20170123191851.png

下图是lint 的分析结果<br>

QQ图片20170123192913.png

如上图所示lint 给出问题代码的定位以及修改建议。<br>

3.lint 检测项 issue id 和 对应描述
lint --list

Valid issue categories:        ``issue id 种类``                                         
Correctness                                                                         
Correctness:Messages                                                                
Security                                                                            
Performance                                                                         
Usability:Typography                                                                
Usability:Icons                                                                     
Usability                                                                           
Accessibility                                                                       
Internationalization                                                                
Internationalization:Bidirectional Text                                             

Valid issue id's:         ``issue id 以及其描述``                                            
"ContentDescription": Image without contentDescription                        
"AddJavascriptInterface": addJavascriptInterface Called                             
"ShortAlarm": Short or Frequent Alarm                                               
还有很多由于慕课网手机2W字字数限制贴不全了                              

例如:"ContentDescription": Image without contentDescription 其中
<br>ContentDescription 是 issue id
<br>Image without contentDescription 是issue id 的描述

issue id 是google对android不规范(出问题)代码的概念的定义,issue id 有它的概念大类划分叫做categories<br>
就像看病一样,你身体擦伤需要去看外科,身体擦伤就是issue id,它属于外科 categories 这类问题<br>
issue id 除了有categories 种类概念,它还有等级的概念,比如你身体擦伤属于小问题,估计就是个小问题
身体重度烧伤就属于大问题<br>
google 给出了 issue id 的默认等级,在android studio 可以看见<br>

以使用了高于min api版本的方法就属于error,查看 issue id 等级方法如下图<br>

图1.png

图2.png

这里就可以将上面lint --list命令下输出的issue id对应上了,可以发现android studio inspection面板只有issue id 对应的描述,并没有issue id 而issue id 在后面使用build.gradle中 lintOptions闭包中的fatal ,disable,enable,check方法中作为参数会用到。(图2右上角对应issue描述比lint --list描述更加详细 )<br>

4. build.gradle中 lintOptions 中 fatal 的使用

Build Variantdebug时,默认debuggable 为 true ,Build Variantrelease时,通过查看com.android.application plugin源码发现debuggable为 true 时不会执行 一个 lintVitalDevRelease的Task,即debuggable为false才会执行lint检测任务<br>
虽然issue id 为 NewApi 的默认等级是 Error ,但是它并不会影响debuggable为false的lintVitalDevRelease任务的完整执行,也就是说最后apk还是会生成,不会在编译期间终止apk生成。<br>
所以要自定义某个 issue id 中断编译,取消apk生成过程只需要在build.gradle中做如下配置<br>

android {
...
  lintOptions {
        fatal 'NewApi'
        // if true, stop the gradle build if errors are found
        abortOnError true
        checkReleaseBuilds true
...

这样做之后 在Build Variantrelease时会中断编译,取消apk生成过程,控制台输出如下

19:12:01: Executing external task 'assembleRelease'...
Parallel execution with configuration on demand is an incubating feature.
Incremental java compilation is an incubating feature.
:app:preBuild UP-TO-DATE
:app:preReleaseBuild UP-TO-DATE
:app:checkReleaseManifest
:app:preDebugBuild UP-TO-DATE
:app:prepareComAndroidSupportAnimatedVectorDrawable2510Library UP-TO-DATE
:app:prepareComAndroidSupportAppcompatV72510Library UP-TO-DATE
:app:prepareComAndroidSupportSupportCompat2510Library UP-TO-DATE
:app:prepareComAndroidSupportSupportCoreUi2510Library UP-TO-DATE
:app:prepareComAndroidSupportSupportCoreUtils2510Library UP-TO-DATE
:app:prepareComAndroidSupportSupportFragment2510Library UP-TO-DATE
:app:prepareComAndroidSupportSupportMediaCompat2510Library UP-TO-DATE
:app:prepareComAndroidSupportSupportV42510Library UP-TO-DATE
:app:prepareComAndroidSupportSupportVectorDrawable2510Library UP-TO-DATE
:app:prepareReleaseDependencies
:app:compileReleaseAidl UP-TO-DATE
:app:compileReleaseRenderscript UP-TO-DATE
:app:generateReleaseBuildConfig UP-TO-DATE
:app:generateReleaseResValues UP-TO-DATE
:app:generateReleaseResources UP-TO-DATE
:app:mergeReleaseResources UP-TO-DATE
:app:processReleaseManifest UP-TO-DATE
:app:processReleaseResources UP-TO-DATE
:app:generateReleaseSources UP-TO-DATE
:app:incrementalReleaseJavaCompilationSafeguard UP-TO-DATE
:app:compileReleaseJavaWithJavac UP-TO-DATE
:app:compileReleaseNdk UP-TO-DATE
:app:compileReleaseSources UP-TO-DATE
:app:lintVitalRelease
D:\Application\Android\AndroidWorkSpace\ListViewDemo\app\src\main\java\com\example\hasee\listviewdemo\MainActivity.java:68: Error: Call requires API level 16 (current min is 14): android.widget.TextView#getLineSpacingExtra [NewApi]
            mMytext1.getLineSpacingExtra();
                     ~~~~~~~~~~~~~~~~~~~

   Explanation for issues of type "NewApi":
   This check scans through all the Android API calls in the application and
   warns about any calls that are not available on all versions targeted by
   this application (according to its minimum SDK attribute in the manifest).

   If you really want to use this API and don't need to support older devices
   just set the minSdkVersion in your build.gradle or AndroidManifest.xml
   files.

   If your code is deliberately accessing newer APIs, and you have ensured
   (e.g. with conditional execution) that this code will only ever be called
   on a supported platform, then you can annotate your class or method with
   the @TargetApi annotation specifying the local minimum SDK to apply, such
   as @TargetApi(11), such that this check considers 11 rather than your
   manifest file's minimum SDK as the required API level.

   If you are deliberately setting android: attributes in style definitions,
   make sure you place this in a values-vNN folder in order to avoid running
   into runtime conflicts on certain devices where manufacturers have added
   custom attributes whose ids conflict with the new ones on later platforms.

   Similarly, you can use tools:targetApi="11" in an XML file to indicate that
   the element will only be inflated in an adequate context.

1 errors, 0 warnings
:app:lintVitalRelease FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:lintVitalRelease'.
> Lint found fatal errors while assembling a release target.

To proceed, either fix the issues identified by lint, or modify your build script as follows:
...
android {
    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }
}
...

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 3.418 secs
Lint found fatal errors while assembling a release target.

To proceed, either fix the issues identified by lint, or modify your build script as follows:
...
android {
    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
    }
}
...
19:12:06: External task execution finished 'assembleRelease'.

想要定义别的 issue id 能中断编译阻止apk生成只需要在build.gradle 的lintOptions改变 fatal '你想要改的issue id '

点击查看更多内容
4人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
1万
获赞与收藏
137

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消