一.LintTask
apply plugin: 'com.android.library'
apply plugin: 'com.android.application'
当我们在gradle中,apply一个library或者application的plugin时,对应的其实是一个LibraryPlugin或AppPlugin对象,他们都继承自BasePlugin,在BasePlugin的apply()方法中,会调用createTasks()方法:
private void createTasks() {
//...
project.afterEvaluate(
project -> {
sourceSetManager.runBuildableArtifactsActions();
threadRecorder.record(
ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
project.getPath(),
null,
() -> createAndroidTasks());
});
}
在gradle都执行完(afterEvaluate)后,调用createAndroidTasks方法,最终会调用到VariantManager的createTasksForVariantScope抽象方法,为每一个variant创建Tasks:
for (final VariantScope variantScope : variantScopes) {
createTasksForVariantData(variantScope);
}
无论TaskManager是LibraryTaskManager还是ApplicationTaskManager类型,都会在该方法中调用createLintTasks方法,创建Lint的Task:
public void createLintTasks(final VariantScope scope) {
//...
taskFactory.register(new LintPerVariantTask.CreationAction(scope, variantScopes));
}
LintPerVariantTask.CreationAction:
public static class CreationAction extends BaseCreationAction<LintPerVariantTask> {
//...
@Override
@NonNull
public String getName() {
//generate task name->lintMusicallyI18nDebug
return scope.getTaskName("lint");
}
@Override
@NonNull
public Class<LintPerVariantTask> getType() {
//create new instance by reflect
return LintPerVariantTask.class;
}
@Override
public void configure(@NonNull LintPerVariantTask lint) {
//...
}
- create时,通过getType()返回的Class对象,反射创建Task对象,添加到TaskManager里
- Task的name,由scope产生,lint拼接scope的variant name,如lintMusicallyI18nDebug
- 最后调用CreationAction的configure方法进行Task的配置
二.LintOptions配置
lint相关的配置,我们需要配置在gradle中,通过extension的形式定义:
android {
lintOptions {
//checked rules
check 'HardcodedText'
//results
xmlReport true
xmlOutput file("lint-results.xml")
}
}
1.创建
同样是BasePlugin的apply()方法中,进行了Extension的初始化:
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,
project.getPath(),
null,
this::configureExtension);
private void configureExtension() {
extension =
createExtension(
project,
...);
globalScope.setExtension(extension);
}
- 首先调用了抽象方法configureExtension(),每种Plugin进行自己的Extension初始化
- 把生成的Extension对象放入globalScope中
LibrayPlugin的configureExtension():
protected BaseExtension createExtension(@NonNull Project project, ...) {
return project.getExtensions()
.create(
"android",
getExtensionClass(),
...);
}
其中,"android"作为Extension的名字,然后getExtensionClass()返回的Class对象,会通过反射方式创建一个实例,作为Extension对象,LibraryPlugin的该方法,返回的是LibraryExtension.class,在LibraryExtension初始化时,会创建一个LintOptions对象:
lintOptions = objectFactory.newInstance(LintOptions.class);
2.配置
在gradle解析时,会将我们配置的lintOptions选项,配置到LintOptions对象中:
public void lintOptions(Action<LintOptions> action) {
action.execute(lintOptions);
}
3.获取
在CreationAction的configure方法配置Task时,从globalScope中的Extension,取出LintOptions,设置给Task:
public void configure(@NonNull T lintTask) {
lintTask.lintOptions = globalScope.getExtension().getLintOptions();
//...
}
三.Lint执行触发
ReflectiveLintRunner
LintPerVariantTask作为一个Task,执行时会调用标有@TaskAction注解的方法:
@TaskAction
public void lint() {
//LintPerVariantTaskDescriptor是Task的一些参数,包括LintOptions可以从中获取
runLint(new LintPerVariantTaskDescriptor());
}
protected void runLint(LintBaseTaskDescriptor descriptor) {
FileCollection lintClassPath = getLintClassPath();
if (lintClassPath != null) {
new ReflectiveLintRunner().runLint(getProject().getGradle(),
descriptor, lintClassPath.getFiles());
}
}
- getLintClassPath:Lint相关依赖,在BasePlugin的apply()时进行初始化
public static void createLintClasspathConfiguration(@NonNull Project project) {
Configuration config = project.getConfigurations().create(LintBaseTask.LINT_CLASS_PATH);
//...
project.getDependencies().add(config.getName(), "com.android.tools.lint:lint-gradle:" +
Version.ANDROID_TOOLS_BASE_VERSION);
}
lint相关的依赖:com.android.tools.lint:lint-gradle:26.2.1
执行时,调用ReflectiveLintRunner的runLint()方法:
fun runLint(gradle: Gradle, request: LintExecutionRequest, lintClassPath: Set<File>) {
try {
val loader = getLintClassLoader(gradle, lintClassPath)
val cls = loader.loadClass("com.android.tools.lint.gradle.LintGradleExecution")
val constructor = cls.getConstructor(LintExecutionRequest::class.java)
val driver = constructor.newInstance(request)
val analyzeMethod = driver.javaClass.getDeclaredMethod("analyze")
analyzeMethod.invoke(driver)
} catch (e: InvocationTargetException) {
if (e.targetException is GradleException) {
// Build error from lint -- pass it on
throw e.targetException
}
throw wrapExceptionAsString(e)
} catch (t: Throwable) {
// Reflection problem
throw wrapExceptionAsString(t)
}
}
这里需要说明:
- ReflectiveLintRunner、LintExecutionRequest这些类是属于lint-gradle-api这个依赖的
- 具体的实现类如LintGradleExecution,属于lint-gradle这个依赖
- gradle插件直接依赖了lint-gradle-api,没有直接依赖lint-gradle,所以需要通过反射方式调用LintGradleExecution
LintGradleExecution
public void analyze() throws IOException {
if (toolingRegistry != null) {
//...
String variantName = descriptor.getVariantName();
if (variantName != null) {
for (Variant variant : modelProject.getVariants()) {
if (variant.getName().equals(variantName)) {
lintSingleVariant(variant);
return;
}
}
}...
}...
}
public void lintSingleVariant(@NonNull Variant variant) {
//...
runLint(variant, variantInputs, true, true, true);
}
private Pair<List<Warning>, LintBaseline> runLint(
@Nullable Variant variant,
@NonNull VariantInputs variantInputs,
boolean report,
boolean isAndroid,
boolean allowFix) {
//创建Android的默认ISSUES
IssueRegistry registry = createIssueRegistry(isAndroid);
//创建Lint里需要的配置model
LintCliFlags flags = new LintCliFlags();
//创建Lint执行器的对象
LintGradleClient client =
new LintGradleClient(
descriptor.getGradlePluginVersion(),
registry,
flags,
...);
//...
LintOptions lintOptions = descriptor.getLintOptions();
boolean fix = false;
if (lintOptions != null) {
//同步LintOptions到LintCliFlags中
syncOptions(
lintOptions,
client,
flags,
...);
}...
//...
try {
//执行Lint检测
warnings = client.run(registry);
} catch (IOException e) {
//...
}
//如果检测有问题且配置中允许report,则抛出GradleException终止命令的执行
if (report && client.haveErrors() && flags.isSetExitCode()) {
abort(client, warnings.getFirst(), isAndroid);
}
return warnings;
}
- 创建Android默认的规则ISSUE(如对TextView、R.id的检测),这里的ISSUES是每个lint规则需要定义的一个对象,将规则实现时会细说
private static BuiltinIssueRegistry createIssueRegistry(boolean isAndroid) {
if (isAndroid) {
return new BuiltinIssueRegistry();
}...
}
//BuiltinIssueRegistry
static {
List<Issue> issues = new ArrayList<>(INITIAL_CAPACITY);
issues.add(MissingIdDetector.ISSUE);
issues.add(TextViewDetector.ISSUE);
//...
}
- LintCliFlags为lint执行器的配置项,只需要将LintOptions的配置项设置进来即可
- LintGradleClient为lint检测的执行器,继承自LintCliClient,run方法为执行lint检测的入口
- 检测结束后,如果有检测出来的error以及需要report,进行abort,实质就是抛出一个GradleException
LintGradleClient(extends LintCliClient)
public int run(@NonNull IssueRegistry registry, @NonNull List<File> files) throws IOException {
//...
//创建LintRequest,获取Project
LintRequest lintRequest = createLintRequest(files);
//创建LintDriver---Lint检测解析器
driver = createDriver(registry, lintRequest);
//...
//执行真正的Lint分析
driver.analyze();
//输出结果,html、xml
for (Reporter reporter : flags