使用背景:由于Android版本的迭代,google在不同版本新增了不同的方法,如果使用了大于APP所规定的min API方法的时候,但是编译能过,这将会导致线上出现No Method的Crash问题,如果能在编译期就使用lint工具检测出问题就好了。由于经历了血淋淋的教训,以下给出了解决痛点的办法。
1.初识lint
lint 是google 给出的静态代码检测工具,用于分析包括内存泄漏,纠正代码规范,查找疑似BUG等。。。
windows环境下位于你的AndroidSDK安装位置下的tools目录下的lint.bat
2.在Android Studio中通过图形界面直观感受Lint
贴心的Android Studio已经为我们集成了好了lint相关的功能,下图介绍了直观感受lint对项目代码不规范处给出的建议
下图是项目中存在问题的代码,一个是app min 14的时候,用了api 16的方法,另一个则是经典的handler匿名内部类导致持有外部类引用导致内存泄漏
在android studio 中使用lint 静态代码检测工具
建议检测的范围为Module 级别(各个scope作用范围都可以试试看)
下图是lint 的分析结果
如上图所示lint 给出问题代码的定位以及修改建议。
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 其中
ContentDescription 是 issue id
Image without contentDescription 是issue id 的描述
issue id 是google对android不规范(出问题)代码的概念的定义,issue id 有它的概念大类划分叫做categories
就像看病一样,你身体擦伤需要去看外科,身体擦伤就是issue id,它属于外科 categories 这类问题
issue id 除了有categories 种类概念,它还有等级的概念,比如你身体擦伤属于小问题,估计就是个小问题 身体重度烧伤就属于大问题
google 给出了 issue id 的默认等级,在android studio 可以看见
以使用了高于min api版本的方法就属于error,查看 issue id 等级方法如下图
这里就可以将上面lint --list
命令下输出的issue id对应上了,可以发现android studio inspection面板只有issue id 对应的描述,并没有issue id 而issue id 在后面使用build.gradle中 lintOptions
闭包中的fatal
,disable
,enable
,check
方法中作为参数会用到。(图2右上角对应issue描述比lint --list描述更加详细 )
4. build.gradle中 lintOptions 中 fatal 的使用
Build Variant
为debug
时,默认debuggable
为 true ,Build Variant
为release
时,通过查看com.android.application plugin源码发现debuggable
为 true 时不会执行 一个 lintVitalDevRelease的Task,即debuggable
为false才会执行lint检测任务
虽然issue id 为 NewApi
的默认等级是 Error ,但是它并不会影响debuggable
为false的lintVitalDevRelease
任务的完整执行,也就是说最后apk还是会生成,不会在编译期间终止apk生成。
所以要自定义某个 issue id 中断编译,取消apk生成过程只需要在build.gradle中做如下配置
android {
...
lintOptions {
fatal 'NewApi'
// if true, stop the gradle build if errors are found
abortOnError true
checkReleaseBuilds true
...
复制代码
这样做之后 在Build Variant
为release
时会中断编译,取消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 '