¿Qué es Android Lint y cómo te ayuda a escribir código compatible?

¿Qué es Android Lint y cómo te ayuda a escribir código compatible?


Cuando el desarrollador no es lo suficientemente cuidadoso, las cosas pueden salir muy mal. Por ejemplo, las omisiones clásicas del desarrollador son el uso de una nueva versión de la API que no es compatible con el código anterior, la ejecución de acciones que requieren permisos especiales del usuario y lagunas en la localización de la aplicación. Y estos son solo algunos de ellos.


Además, Java y Kotlin, como cualquier otro lenguaje de programación, tienen sus propias construcciones que pueden conducir a un bajo rendimiento.


Hola pelusa


Utilizamos una herramienta llamada Lint (o Linter) para evitar tales problemas. Lint es una herramienta de análisis de código estático que ayuda a los desarrolladores a detectar posibles problemas antes de que el código se compile. Lint realiza múltiples comprobaciones del código fuente, que pueden detectar problemas como variables no utilizadas o argumentos de funciones, simplificación de condiciones, alcance incorrecto, variables o funciones indefinidas, código mal optimizado, etc. Cuando hablamos del desarrollo de Android, hay cientos de cheques Lint listos para usar .


Pero a veces necesitamos encontrar problemas específicos en nuestro código que no estén cubiertos por estas verificaciones existentes.


Hola cheques personalizados Lint


Antes de comenzar a codificar, definamos nuestro objetivo y veamos cómo implementarlo paso a paso con la API de Lint. El objetivo es crear una verificación para detectar una llamada de método incorrecta para un objeto. La idea de esta prueba es determinar si el método de instalación del oyente en el componente Ver es tal que interrumpirá varios clics consecutivos en el componente para que podamos evitar abrir la misma Actividad o acceder a la red varias veces.


Las comprobaciones de usuario de Lint se escriben como parte del módulo estándar Java (o Kotlin). La forma más fácil de comenzar es crear un proyecto simple basado en Gradle (no tiene que ser un proyecto de Android).


Luego agregue las dependencias Lint. En el archivo build.gradle de su módulo, agregue:


 compileOnly "com.android.tools.lint:lint-api:$lintVersion" compileOnly "com.android.tools.lint:lint-checks:$lintVersion" 

Ahora hay un truco que aprendí al investigar este tema. lintVersion debe ser gradlePluginVersion + 23.0.0 . gradlePluginVersion es una variable definida en el archivo build.gradle a nivel de proyecto. Y en este momento, la última versión estable es 3.3.0. Esto significa que lintVersion debería ser 26.3.0.


Cada verificación de pelusa consta de 4 partes:


  • El problema es el problema en nuestro código que estamos tratando de prevenir. Cuando falla la comprobación de pelusa, esto se informa al desarrollador.
  • Detector es una herramienta de búsqueda de problemas que proporciona la API de Lint.
  • Una implementación es un área donde puede surgir un problema (archivo fuente, archivo XML, código compilado, etc.).
  • Un registro es un registro de verificación de pelusa personalizado que se utilizará con un registro existente que contiene verificaciones predefinidas.

Implementación


Comencemos creando una implementación para nuestra validación personalizada. Cada implementación consta de una clase que implementa un detector y un alcance.


 val correctClickListenerImplementation = Implementation(CorrectClickListenerDetector::class.java, Scope.JAVA_FILE_SCOPE) 

Recuerde que Scope.JAVA_FILE_SCOPE también funcionará para las clases de Kotlin.


El problema


El siguiente paso es usar esta implementación para determinar el problema. Cada problema consta de varias partes:


  • ID es un identificador único.
  • Descripción : una declaración breve (5-6 palabras) del problema.
  • Explicación Una explicación completa de un problema con una sugerencia sobre cómo solucionarlo.
  • Categoría : la categoría del problema (rendimiento, traducción, seguridad, etc.).
  • Prioridad : la importancia del problema, en el rango de 1 a 10, donde 10 es el más alto. Esto se usará para ordenar los problemas en el informe creado cuando se lanzó Lint.
  • Gravedad: la gravedad del problema (fatal, error, advertencia, información o ignorar).
  • Una implementación es una implementación que se utilizará para detectar este problema.

 val ISSUE_CLICK_LISTENER = Issue.create( id = "UnsafeClickListener", briefDescription = "Unsafe click listener", explanation = """" This check ensures you call click listener that is throttled instead of a normal one which does not prevent double clicks. """.trimIndent(), category = Category.CORRECTNESS, priority = 6, severity = Severity.WARNING, implementation = correctClickListenerImplementation ) 

Detector


La API de Lint ofrece interfaces para cada área que puede definir en una implementación. Cada una de estas interfaces proporciona métodos que puede anular y acceder a partes del código que le interesan.


  • UastScanner : archivos Java o Kotlin (UAST: árbol de sintaxis abstracta unificada (árbol de sintaxis abstracta unificada rusa)).
  • ClassScanner - archivos compilados (bytecode).
  • BinaryResourceScanner : recursos binarios como mapas de bits o archivos res/raw .
  • ResourceFolderScanner : carpetas de recursos (no archivos específicos en ellas).
  • XmlScanner : archivos XML.
  • GradleScanner : archivos de Gradle.
  • OtherFileScanner : todo lo demás.

Además, la clase Detector es una clase base que tiene implementaciones vacías de todos los métodos proporcionados por cada una de las interfaces anteriores, por lo que no necesita implementar la interfaz completa en caso de que necesite un solo método.


Ahora estamos listos para implementar un detector que verificará la llamada al método correcto para el objeto.


 private const val REPORT_MESSAGE = "Use setThrottlingClickListener" /** *   ,        *     ,      . */ class CorrectClickListenerDetector : Detector(), Detector.UastScanner { /** * ,  ,      . *         , *          , *      ,   . */ override fun getApplicableUastTypes(): List<Class<out UElement>>? { return listOf<Class<out UElement>>(UCallExpression::class.java) } /** *      UAST,    , *    UAST   .    UElementHandler, *   ,     , *    ,  , , ,   .. *        ,    *    .     —  ,   *   ,    ,       . */ override fun createUastHandler(context: JavaContext): UElementHandler? { return object: UElementHandler() { override fun visitCallExpression(node: UCallExpression) { if (node.methodName != null && node.methodName?.equals("setOnClickListener", ignoreCase = true) == true) { context.report(ISSUE_CLICK_LISTENER, node, context.getLocation(node), REPORT_MESSAGE, createFix()) } } } } /** *    ,    *   IDE,      . */ private fun createFix(): LintFix { return fix().replace().text("setOnClickListener").with("setThrottlingClickListener").build() } } 

El registro


Lo último que debemos hacer es agregar problemas a nuestro registro y decirle a Lint que hay un registro de problemas especial que debe usar junto con el estándar.


 class MyIssueRegistry : IssueRegistry() { override val issues: List<Issue> = listOf(ISSUE_CLICK_LISTENER) } 

En el nivel del módulo build.gradle :


 jar { manifest { attributes("Lint-Registry-v2": "co.infinum.lint.MyIssueRegistry") } } 

donde co.infinum.lint es un paquete de la clase MyIssueRegistry . Ahora puede ejecutar la tarea jar utilizando el script gradlew , y la biblioteca debería aparecer en el directorio build/libs .


Aquí hay otro ejemplo de verificación de usuario de Lint, donde puede ver cómo procesar archivos XML.


Uso


Su nuevo cheque de pelusa está listo para usar en el proyecto. Si esta verificación se puede aplicar a todos los proyectos, puede colocarla en la carpeta ~/.android/lint (puede crearla si aún no existe).


Además, puede poner su cheque en un módulo separado en su proyecto y habilitar este módulo como cualquier otra dependencia utilizando el método lintChecks .


¿Vale la pena?


Lint es una herramienta realmente buena que todo desarrollador debería usar. Ser capaz de detectar problemas potenciales con su código temprano es muy útil. Aunque las comprobaciones personalizadas no son fáciles de escribir, principalmente debido a la complejidad de la API, definitivamente valen la pena y pueden ahorrarle mucho tiempo y esfuerzo en el futuro.

Source: https://habr.com/ru/post/456272/


All Articles