- Что такое Android Lint и как он помогает писать поддерживаемый код
- Привет, Lint
- Привет, пользовательские проверки Lint
- Реализация
- Проблема
- Детектор
- Реестр
- Использование
- Стоит ли оно того?
- Actions-workflow changed behavior (Lint results) #2997
- Comments
- hb0 commented Mar 22, 2021 •
- Formatting Code Analysis Rule with Android Lint (part 1/2)
- For Kotlin and Java at once
- Motivation
- What is the best tool for this problem
- Why Java is still important at all
- How to write custom lint rules
- Android lint value must be 0 range
Что такое Android Lint и как он помогает писать поддерживаемый код
Когда разработчик недостаточно осторожен, дела могут пойти весьма плохо. Например, классические упущения разработчика — использование новой версии API, которая не совместима со старым кодом, выполнение действий, которые требуют специальных пользовательских разрешений, пробелы в локализации приложения. И это только некоторые из них.
Кроме того, в Java и Kotlin, как и в любых других языках программирования, есть свои собственные конструкции, которые могут привести к снижению производительности.
Привет, Lint
Мы используем инструмент под названием Lint (или Linter) для избежания таких проблем. Lint — это инструмент для статического анализа кода, который помогает разработчикам изловить потенциальные проблемы ещё до того, как код скомпилируется. Lint выполняет многократные проверки исходного кода, которые могут обнаружить такие проблемы, как неиспользуемые переменные или аргументы функций, упрощение условий, неправильные области видимости, неопределённые переменные или функции, плохо оптимизированный код и т.д. Когда мы говорим о разработке для Android, существуют сотни проверок Lint, доступных «из коробки».
Но иногда нам нужно найти конкретные проблемы в нашем коде, которые не охватываются этими существующими проверками.
Привет, пользовательские проверки Lint
Прежде чем мы начнем кодить, давайте определим нашу цель и посмотрим, как реализовать её шаг за шагом с помощью Lint API. Цель состоит в том, чтобы создать проверку для обнаружения неправильного вызова метода для объекта. Идея этой проверки состоит в том, чтобы определить, является ли метод установки слушателя на View-компонент таким, который будет прерывать несколько последовательных кликов по компоненту, чтобы мы могли избежать открытия одной и той же Activity или обращения к сети несколько раз.
Пользовательские проверки Lint написаны как часть стандартного модуля Java (или Kotlin). Самый простой способ начать — создать простой проект на основе Gradle (это не обязательно должен быть проект Android).
Затем добавим зависимости Lint. В файле build.gradle вашего модуля добавьте:
Теперь есть хитрость, о которой я узнал, исследуя эту тему. lintVersion должен быть gradlePluginVersion + 23.0.0 . gradlePluginVersion — это переменная, определённая в файле build.gradle на уровне проекта. И на данный момент последняя стабильная версия — 3.3.0. Это означает, что lintVersion должен быть 26.3.0.
Каждая проверка Линт состоит из 4 частей:
- Проблема — проблема в нашем коде, которую мы пытаемся предотвратить. Когда проверка Lint завершается неудачей, то об этом сообщается разработчику.
- Детектор — инструмент для поиска проблемы, который предоставляет API Lint.
- Реализация — область, в которой может возникнуть проблема (исходный файл, файл XML, скомпилированный код и т.д.).
- Реестр — настраиваемый реестр проверок Lint, который будет использоваться вместе с существующим реестром, содержащим предопределённые проверки.
Реализация
Давайте начнём с создания реализации для нашей пользовательской проверки. Каждая реализация состоит из класса, который реализует детектор и область действия.
Помните, что Scope.JAVA_FILE_SCOPE также будет работать для классов Kotlin.
Проблема
Следующим шагом является использование этой реализации для определения проблемы. Каждая проблема состоит из нескольких частей:
- ID — уникальный идентификатор.
- Описание — краткое (5-6 слов) изложение проблемы.
- Объяснение — полное объяснение проблемы с предложением, как это исправить.
- Категория — категория проблемы (производительность, перевод, безопасность и т.д.).
- Приоритет — важность проблемы, в диапазоне от 1 до 10, где 10 является самым высоким. Это будет использоваться для сортировки проблем в отчёте, созданном при запуске Lint.
- Серьёзность — серьёзность проблемы (фатальная, ошибка, предупреждение, информация или игнорирование).
- Реализация — реализация, которая будет использоваться для обнаружения этой проблемы.
Детектор
Lint API предлагает интерфейсы для каждой области, которую вы можете определить в реализации. Каждый из этих интерфейсов предоставляет методы, которые вы можете переопределить и получить доступ к интересующим вас частям кода.
- UastScanner — файлы Java или Kotlin (UAST — Unified Abstract Syntax Tree (рус. унифицированное абстрактное синтаксическое дерево)).
- ClassScanner — скомпилированные файлы (байт-код).
- BinaryResourceScanner — двоичные ресурсы, такие как растровые изображения или файлы res/raw .
- ResourceFolderScanner — папки ресурсов (не конкретные файлы в них).
- XmlScanner — XML-файлы.
- GradleScanner — Gradle-файлы.
- OtherFileScanner — всё остальное.
Кроме того, класс Detector является базовым классом, который имеет пустые реализации всех методов, предоставляемых каждым из вышеперечисленных интерфейсов, поэтому вам не нужно реализовывать полный интерфейс в случае, если вам нужен только один метод.
Теперь мы готовы реализовать детектор, который будет проверять правильный вызов метода для объекта.
Реестр
Последнее, что нам нужно сделать, это добавить проблемы в наш реестр и сообщить Lint, что существует специальный реестр проблем, который он должен использовать наряду со стандартным.
В build.gradle уровня модуля:
где co.infinum.lint — это пакет класса MyIssueRegistry . Теперь вы можете запустить задачу jar , используя скрипт gradlew , и библиотека должна появиться в каталоге build/libs .
Здесь есть ещё один пример пользовательской проверки Lint, где вы можете увидеть, как обрабатывать XML-файлы.
Использование
Ваша новая проверка Lint готова к использованию в проекте. Если эту проверку можно применить ко всем проектам, вы можете поместить её в папку
/.android/lint (вы можете создать её, если она ещё не существует).
Кроме того, вы можете вынести свою проверку в отдельный модуль в своём проекте и включить этот модуль как любую другую зависимость, используя метод lintChecks .
Стоит ли оно того?
Lint — действительно хороший инструмент, который следует использовать каждому разработчику. Возможность обнаружить потенциальные проблемы с вашим кодом на раннем этапе очень полезна. Хотя настраиваемые проверки писать не так просто, в основном из-за сложности API, они определённо стоят того и могут сэкономить много времени и усилий в будущем.
Источник
Actions-workflow changed behavior (Lint results) #2997
Comments
hb0 commented Mar 22, 2021 •
Description
We have a Gtihub Action Workflow which runs ./gradlew build executing :lint .
The result of that Lint execution did change without us changing anything.
There seems to be an issue with the CI environment.
In other CI environments (e.g. Bitrise) or a local Ubuntu 20.04 environment the Lint result is still as it was 2 months ago.
If we run the same workflow on commits which succeeded before, the Lint execution now fails on the same commits on Github.
I know you changed the default environment from 18.04 to Ubuntu 20.04, so I checked it with the current 18.04 version which produces the same unexpected behavior. Thus, I did not post this problem here.
Area for Triage:
Question, Bug, or Feature?:
Bug
Virtual environments affected
Image version
ubuntu-18.04_20210309.1
ubuntu-20-04_20210315.1
Expected behavior
The ./gradlew :lint execution should:
- behave the same as before / same as on other environments
- (If a bug fix lead to this, I need to know how to reproduce this «new» behavior locally)
Actual behavior
Github CI is showing errors which cannot be reproduced anywhere else and which did not appear on the same commit and workflow 2 months ago:
Here the same Build on Bitrise CI which still behaves as Github did 2 months ago:
https://app.bitrise.io/build/54082a61f67372d6
The text was updated successfully, but these errors were encountered:
Источник
Formatting Code Analysis Rule with Android Lint (part 1/2)
For Kotlin and Java at once
In this first part of the article, primarily, I want to show that it’s worth the time to write a custom code analysis rule to enforce code conventions. Secondly, I want to demonstrate that in addition to Checkstyle and ktlint, Android Lint should also be considered when creating a formatting-related code analysis rule, despite that not being its basic purpose. I’ll explain its main advantage in my case against the other tools, and describe the inner workings that provide this benefit. For inspiration, I’ll also show the steps I took to make my formatting rule work with Android Lint.
Motivation
I get frustrated when I get formatting-related comments on my merge requests or when I have to add such comments to others’. Sometimes, we have to change branches in order to fix a single formatting error in our MR, which is quite demotivating. That’s why I started thinking about ways we could automate fixing this minor (yet important) problem, so we could focus on more complex issues during code reviews.
We use several lint tools, such as ktlint or Checkstyle, for enforcing global formatting conventions (variable order, line length, etc.), but these don’t include certain company-wide rules by default. For those cases, the above-mentioned tools support adding custom rules as well. I decided to write one for the most common formatting mistakes we make:
We always require double line breaks before and after “block statements”, which can be if, switch ( when in Kotlin), for, try, or while blocks, unless they are exactly at the beginning or the end of a method or another block. We believe this makes our code more readable, that’s why we always leave a comment during code review if someone violates this rule (and if we happen to notice it).
What is the best tool for this problem
We can say that ktlint for Kotlin and Checkstyle for Java are the main formatting code analysis tools, but now I’ll pick another tool yet: Android Lint (not only for Android projects), because it also supports writing custom rules that can be applied to Kotlin and Java at the same time. It seems a more logical choice, because we use both languages in our Android projects, and I wanted neither to write the same rule twice nor maintain them concurrently. Not to mention the integration of the rule, which would also need to be done two times.
Why Java is still important at all
As an Android developer, I have to write code in both Java and Kotlin. However, we can say that it’s not worth the time to focus on Java anymore, because as Kotlin is coming up, we use it more and more instead of Java in our codebase. On the other hand, I believe the transition isn’t happening that quickly in big projects already in production. So, as we want to see nicely formatted code in Java as well, it’s important to have this rule for both languages.
How to write custom lint rules
There are many tutorials and articles about writing custom code analysis rules, so I won’t detail it too much in this post. But if you’re interested, here are a couple of links I can recommend for the different tools: To Checkstyle, the official doc, to ktlint and Android Lint, Niklas Baudy’s great medium articles.
Источник
Android lint value must be 0 range
Custom Lint Rules
The lint source code contains a lot of documentation on how to write custom checks; this git repository contains a snapshot of this documentation which you can read here:
The Android lint tool is a static code analysis tool that checks your project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization. Lint comes with around 400 built-in checks, but it can be extended with additional custom checks. This sample project shows how those sample checks can be built and packaged.
Note that while Android Lint has the name «Android» in it, it is no longer an Android-specific static analysis tool; it’s a general static analysis tool, and inside Google for example it is run to analyze server-side Java and Kotlin code.
NOTE: The lint API is not a final API; if you rely on this be prepared to adjust your code for the next tools release.
The Android Lint API allows users to create custom lint checks. For example, if you are the author of an Android library project, and your library project has certain usage requirements, you can write additional lint rules to check that your library is used correctly, and then you can distribute those extra lint rules for users of the library. Similarly, you may have company-local rules you’d like to enforce.
This sample demonstrates how to create a custom lint checks and corresponding tests for those rules.
Sample Lint Checks
This project shows how Android Studio as well as the Android Gradle plugin handles packaging of lint rules.
Lint Check Jar Library
First, there’s the lint check implementation itself. That’s done in the «checks» project, which just applies the Gradle «java» or «kotlin» plugins, and that project produces a jar. Note that the dependencies for the lint check project (other than its testing dependencies) must all be «compileOnly»:
Lint Check AAR Library
Next, there’s a separate Android library project, called «library». This library doesn’t have any code on its own (though it could). However, in its build.gradle, it specifies this:
This tells the Gradle plugin to take the output from the «checks» project and package that as a «lint.jar» payload inside this library’s AAR file. When that’s done, any other projects that depends on this library will automatically be using the lint checks.
Note that you don’t have to go through the extra «library indirection» if you have a lint check that you only want to apply to one or more app modules. You can simply include the lintChecks dependency as shown above there as well, and then lint will include these rules when analyzing the project.
The lint version of the libraries (specified in this project as the lintVersion variable in build.gradle) should be the same version that is used by the Gradle plugin.
If the Gradle plugin version is X.Y.Z, then the Lint library version is X+23.Y.Z.
For example, for AGP 7.0.0-alpha08, the lint API versions are 30.0.0-alpha08.
Run the :app:lint target to have first the custom lint checks in checks/ compiled, then wrapped into the library, and finally run lint on a sample app module which has violations of the check enforced by sample check in this project:
Explanation for issues of type «SampleId»: This check highlights string literals in code which mentions the word lint. Blah blah blah. Another paragraph here. Vendor: Android Open Source Project Contact: https://github.com/googlesamples/android-custom-lint-rules Feedback: https://github.com/googlesamples/android-custom-lint-rules/issues 0 errors, 1 warnings BUILD SUCCESSFUL in 1s «>
When building your own rules, you will likely want to know which dependencies you should bring into your own project. The below descriptions of the dependencies included within this project serve to help you make that decision:
- com.android.tools.lint:lint-api: The most important one; it contains things like LintClient , the Detector base class, the Issue class, and everything else that Lint checks rely on in the Lint framework.
- com.android.tools.lint:lint-checks: Contains the built-in checks that are developed internally. Also contains utilities that are sometimes useful for other lint checks, such as the VersionChecks class (which figures out whether a given UAST element is known to only be called at a given API level, either by surrounding if >= SDK-version checks or if early returns in the method).
- com.android.tools.lint:lint-tests: Contains useful utilities for writing unit tests for Lint checks, including the LintDetectorTest base class.
- com.android.tools.lint:lint: Lint checks don’t need to depend on this. It’s a separate artifact used by tools that want to integrate lint with the command line, such as the Gradle integration of lint. This is where things like terminal output, HTML reporting, command line parsing etc is handled.
The APIs in all but the lint-api artifact are more likely to change incompatibly than the lint-api artifact.
- The «lint-dev» Google group: https://groups.google.com/forum/#!forum/lint-dev
- Stack Overflow: http://stackoverflow.com/questions/tagged/android
Patches are encouraged, and may be submitted by forking this project and submitting a pull request through GitHub.
Licensed under the Apache 2.0 license. See the LICENSE file for details.
How to make contributions?
Please read and follow the steps in the CONTRIBUTING
Источник