Practice makes perfect and shortage in one, success depends on forethought and destroyed by.

Why customize Lint?

In some special cases where system-defined Lint doesn’t meet our requirements, we need to define our own rules and then use The Android Lint tool to help us automatically find problems.

How to customize Lint

Primarily use LinkedIn to generate solutions: Put the JARS into an AAR. Android projects then rely on this AAR for custom Lint checking (only for the current project).

Field experience

(1) Practical operation environment

  • Optional, use your own environment and code as well.
  • The SamplePop environment is as follows:

Android Studio 4.0 Gradle Version 6.1.1 Android API Version 30

(2) Project creation and configuration

Create a Java project and configure Gradle.

apply plugin: 'java-library' dependencies { implementation fileTree(dir: 'libs', include: [' *. Jar ']) implementation 'com. Android. Tools. Lint: lint - API: 26.0.0' implementation 'com. Android. Tools. Lint: lint - checks: 26.0.0'}Copy the code
  • Lint-api: the official API(which will change from version to version 24,25,26,27)
  • Lint-checks: checks that already exist.

Problems I encountered in practical operation:

  • When I configure the Gradle file, I want to use the latest version, so I add the version number 27. In the compiled JAR package into~/.android/lint/After that, the Detector scanner written by yourself does not take effect. The system says you cannot find the corresponding Detector scannerSourceCodeScannerClass (this depends on which Lint-API your Detector is implementing).
  • I thought it might not correspond to the version of lint installed on my system, so I checked the version of Lint installed on my system (version 26.0.0, my Gradle configuration is 27.0.0). Modify gradle version, check again, success!

(3) Create Detector

Detector is responsible for scanning the code, finding problems and reporting them. LogUtil: LogUtil: LogUtil: LogUtil: LogUtil: LogUtil: LogUtil: LogUtil: LogUtil: LogUtil

public class KJYRLogUtilDetector extends Detector implements Detector.UastScanner { public static final Issue ISSUE = Issue.create("KJYRLogUtilCase", "Tech ape man - Avoid using Log"," Use LogUtil, LogUtil Log on the system class encapsulation "logically, the Category, SECURITY, 5, Severity, WARNING, new Implementation (KJYRLogUtilDetector. Class, Scope.JAVA_FILE_SCOPE)); public List<String> getApplicableMethodNames() { return Arrays.asList("d", "e", "i", "v", "w"); } @Override public void visitMethod(JavaContext context, UCallExpression node, PsiMethod method) { JavaEvaluator evaluator = context.getEvaluator(); If (evaluator. IsMemberInClass (method, "android. Util. Log")) {String message = "kejiyuanren: please use LogUtil wrapper class"; context.report(ISSUE, node, context.getLocation(node), message); }}}Copy the code

Detailed instructions:

  • getApplicableMethodNames: returns a collection of method names to listen on
  • context.report(ISSUE, node, context.getLocation(node), message): Report check results (Alerts that are suppressed (suppressLint) or ignored (Tools: Ignore) are automatically processed in report)
  • Issue: created by the static factory method, discovered and reported by Detector.

Issue field description:

  • Id: unique value that should briefly describe the current problem. This is the ID used for masking with Java annotations or XML attributes.
  • Summary: A short summary, usually 5-6 characters, describing the problem rather than the fix.
  • Explanation: Indicates a complete explanation of the problem and repair suggestions.
  • Category: problem category. See the detailed section below.
  • Priority: indicates the priority. A number from 1 to 10, with 10 being the most important/serious.
  • Severity: Severity level: Fatal, Error, Warning, Informational, Ignore.
  • Implementation: Provides a mapping between Issue and Detector, which is the current Detector. Scope is used to describe the set of files that the Detector needs to consider when analyzing, including: Resource files or directories, Java files, and Class files.

Create IssueRegistry

Provides a list of issues that need to be detected

public class KJYRIssueRegistry extends IssueRegistry { @Override public List<Issue> getIssues() { return Arrays.asList( KJYRLogUtilDetector.ISSUE, KJYRSetTextDetector.SET_TEXT_I18N // HandlerDetector.ISSUE ); }}Copy the code

(5) Generation of JAR package

We package the written scanner as a JAR

jar {
    manifest {
        attributes("Lint-Registry": "com.kejiyuanren.lint_jar.KJYRIssueRegistry")
    }
}
Copy the code

(6) Use of JAR packages

The final JAR package is intended to be scanned by the system Lint, and the most obvious difference between the following two scenarios is the scope of influence.

(6.1) Google solution

$mkdir ~/. Android /lint/ $cp lint_jar.jar ~/. Android /lint/Copy the code

Disadvantages: For all projects, will affect Lint checking for other projects on the same machine. /gradlew Lint may be affected even if it is copied when the project is triggered and is used by other processes or threads after deletion./gradlew Lint may still be affected.

(6.2) LinkedIn solution

LinkedIn offers another idea: put the JAR in an AAR. This way we can customize Lint for the project, and lint.jar is only valid for the current project.

Lint_jar project: build.gradle

Jar {manifest {attributes(" lint-registry ": "Com.kejiyuanren.lint_jar.KJYRIssueRegistry")}} // Declare dependencies {lintJarOutput} lintJarOutput files(jar) }Copy the code

Lint_aar project: build.gradle

Configurations {jar package configurations {lintJarImport}} ":lint_jar", configuration: "lintJarOutput")} // Copy the jar to the lint.jar task copyLintJar(type: Copy) { from (configurations.lintJarImport) { rename { String fileName -> 'lint.jar' } } into 'build/intermediates/lint /} / / insert copyLintJar until compileLint project execution afterEvaluate {def compileLintTask = project.tasks.find { it.name == 'compileLint' } compileLintTask.dependsOn(copyLintJar) }Copy the code

Lint project: build.gradle

Dependencies {// add lint aar implementation Project (' lint_aar')}Copy the code

(7) Lint checks results

(8) Summary of practice

  • Lint version matching problem. If you encounter a custom Version of Lint that does not take effect, please keep your version of Lint consistent with the system version
  • Read more about the existing Detector in Lint-Checks, learn more from the source code, more systematic
  • If you are interested in a custom Lint development plugin, please refer to the following:Android custom Lint practice
  • If you are interested in debug Lint code, refer to the following at the end of the article:Good articles

Xiaobian extension links

  • SamplePop code download
  • Android Performance Optimization family Bucket

Refer to the link

  • This is the first article that should be read
  • Android custom Lint practice
  • LinkedIn scheme
  • Android custom Lint rules
  • Good articles
  • How Android Lint works

New clear wilderness, no atmosphere fouling

❤ ❤ than heart