Personnalisez lint sur Android Studio : Écriture et intégration de règles personnalisées

Comment créer vos propres règles lint sur Android Studio

Farouk Sabiou
AndroidMood
7 min readJan 24, 2024

--

Source: Pexels

Aujourd’hui, nous allons traiter du linting en nous penchant sur sa pertinence dans le contexte du développement d’applications Android. De plus, nous vous guiderons à travers le processus de création de règles de linting personnalisées afin de les aligner sur vos conventions internes.

Commençons par établir les définitions de quelques termes clés :

Linting

Le linting est le processus automatisé qui consiste à examiner votre code source à la recherche d’erreurs potentielles, qu’elles soient d’ordre programmatique ou stylistique. Cette opération s’accomplit à l’aide d’un outil spécifique appelé linter.

Issue

Dans ce contexte, une “Issue” représente le problème que vous souhaitez repérer dans le code et présenter à l’utilisateur avec un message d’assistance pour le résoudre. Chaque Issue est associée à une description, une catégorie, une priorité, un niveau de sévérité, etc.

Detector

Le “Detector”, comme son nom l’indique, est l’élément chargé d’analyser le code, de repérer les erreurs (issues) et de les signaler. Il est crucial de noter qu’un détecteur peut rapporter une ou plusieurs issues. En d’autres termes, vous avez la possibilité de spécifier autant d’issues que nécessaire au sein d’un détecteur.

Issue Registry

L’ “Issue Registry”, quant à lui, est le registre où toutes les issues à vérifier sont répertoriées afin d’être examinées par Lint lors de l’analyse.

Linting et Android

Android Studio met à disposition un outil d’analyse de code appelé Lint, conçu pour détecter et résoudre les problèmes potentiels liés aux conventions et à la qualité structurelle de votre code, le tout sans nécessité d’exécuter l’application.

Par exemple, lorsqu’une taille de texte est définie en pixels indépendants de la densité (dp) sur Android, un avertissement apparaît sous forme de tooltip, affichant le message “should use sp instead of dp for text sizes” pour rappeler l’utilisation des pixels indépendants de l’échelle (sp). Cet avertissement fait partie des Issues lint prédéfinies dans Android Studio. Voir DP_ISSUE

Android Studio intègre par défaut plus de 400 issues prédéfinis.

Règle lint prédéfinie sur Android Studio

Implémenter un détecteur personnalisé sur Android Studio

Malgré les 400 vérificateurs prédéfinis, il se peut que vous ne trouviez pas exactement ce que vous recherchez, et que vous ayez besoin d’une personnalisation plus poussée pour aligner lint avec votre design system ou faire respecter vos conventions internes au sein de toute l’équipe.

Dans cet exemple, nous allons explorer la manière de faire de la bibliothèque AestheticDialogs l’outil principal pour la gestion de nos toasts et boîtes de dialogue au sein de notre application. Nous cherchons à imposer son utilisation de manière cohérente avec nos conventions internes, en décourageant l’utilisation du Toast natif fourni par Android. Cet article détaillera la création d’un vérificateur Lint personnalisé qui analysera notre codebase pour repérer toute utilisation de toast qui ne provient pas de la librairie AestheticDialogs.

Configuration

Cet article démontre comment créer un vérificateur lint personnalisé dans un projet Android existant. Nous supposons que vous avez déjà mis en place votre projet avant de suivre les étapes décrites ci-dessous.

Pour commencer, nous allons créer un module Java/Kotlin au sein de notre projet. Ce module, que nous nommerons “check”, renfermera nos règles lint et sera intégré dans notre module “app”.

Sur Android Studio, suivez ces étapes :
1. Cliquez sur File -> New -> New module.
2. Sélectionnez Java or Kotlin library dans la barre latérale.
3. Donnez un nom à votre module, dans notre cas, “checks”.

Création module Java/Kotlin

Après la création du module, ajoutons les dépendances nécessaires dans notre fichier checks/build.gradle:

Une règle simple pour déterminer la dernière version de lint consiste à ajouter 23 à la version majeure de votre plugin Gradle.

lintVersion = gradlePluginVersion + 23

Par exemple, si la version de votre plugin Gradle est 7.2.0-beta02, la version de lint à utiliser serait 7 + 23 = 30.

plugins {
id 'java-library'
// PLUGIN LINT AJOUTÉ
id 'com.android.lint'
id 'org.jetbrains.kotlin.jvm'
}

dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.21")
// DÉPENDANCES LINT AJOUTÉES
compileOnly "com.android.tools.lint:lint-api:31.2.1"
compileOnly "com.android.tools.lint:lint-checks:31.2.1"

testImplementation "com.android.tools.lint:lint-tests:31.2.1"
testImplementation "junit:junit:4.13.2"
testImplementation "org.assertj:assertj-core:3.10.0"
}

java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

compileKotlin {
kotlinOptions {
jvmTarget = "11"
}
}

A noter que les dépendances lint sont toujours déclarés sous compileOnly

Une fois notre module prêt avec ses dépendances lint ajoutées, nous allons créer notre détecteur (AndroidToastDetector), qui est une classe héritant de la classe abstraite Detector et implémentant l’interface UastScanner de la même classe.

Comme indiqué précédemment, le rôle du détecteur est de parcourir le code afin de repérer l’usage du Toast par défaut et d’avertir l’utilisateur de le remplacer par les Toasts de la bibliothèque AestheticDialogs.

AndroidToastDetector.kt

Dans l’objet singleton, on trouve une constante ISSUE qui est initialisée avec les propriétés suivantes :

  • id: un nom unique permettant d’identifier l’anomalie.
  • briefDescription: Une brève description de l’anomalie, expliquant ce que signale cette ISSUE.
  • explanation: Une explication détaillée du signalement, indiquant le pourquoi et comment corriger.
  • category: La catégorie de l’ISSUE, ici Category.CUSTOM_LINT_CHECKS puisqu’il s’agit d’une règle personnalisée.
  • priority: Le niveau de priorité, une valeur comprise entre 1 et 10, avec 10 indiquant un niveau urgent/sévère. Ce paramètre doit être défini en fonction de vos conventions.
  • severity: Le niveau de sévérité par défaut, c’est ici que vous décidez si l’ISSUE doit signaler une erreur ou simplement un avertissement, conformément à vos conventions.
  • implementation: L’implémentation de l’ISSUE.

La méthode getApplicableMethodNames() est redéfinie pour renvoyer la liste des noms de méthodes que le détecteur doit analyser. Dans notre projet, chaque fois que la méthode makeText() est utilisée, le détecteur fait appel à visitMethodCall(). Si l’appel à makeText() appartient à la classe Toast du package android.widget.Toast , alors l’anomalie est signalée à l’utilisateur avec un message explicatif.

Maintenant, notre détecteur doit être enregistré dans le registre. Pour ce faire, ajoutons une nouvelle classe ToastIssueRegistry, sous-classe de la classe abstraite IssueRegistry, avec le contenu suivant :

issues renvoie la liste de tous nos détecteurs, sachant que dans ce cas particulier, nous en avons seulement un.

api: la version de l’API à utiliser pour lint. Il est important de noter que cette valeur est choisie en finction de la version de votre AGP (Android Gradle Plugin). Référez-vous toujours au fichier Api.kt afin de déterminer la version correspondante pour votre projet.

La dernière étape dans notre module “checks” consiste à enregistrer notre registre ToastIssueRegistry en ajoutant cette ligne à la fin de notre fichier build.gradle du module.


jar {
manifest {
attributes("Lint-Registry-v2": "com.sabiou.lint.checks.ToastIssueRegistry")
}
}

Enfin, dans le fichier build.gradle (app), ajoutez le module lint “checks” comme dépendance :

dependencies {
......
lintChecks project(':checks')
}

Et c’est fini! pour ffinalement voir notre règle lint à l’oeuvre, il suffit d’executer la commande gradlew lint

Règle lint personnalisée émettant désormais un avertissement ⚠️ concernant l’utilisation de la classe Toast du package android.widget.Toast.

On peut clairement observer dans notre MainActivity que l’utilisation du Toast par défaut génère un avertissement ⚠️, signalant à l’utilisateur d’utiliser un toast issu de la bibliothèque AestheticDialogs.

Maintenant, dans notre classe AndroidToastDetector, modifions la sévérité pour Severity.ERROR.

val ISSUE = Issue.create(
id = "AvoidClassicToast",
briefDescription = "This is issued to prevent usage of classic android toast widget",
explanation = "AestheticDialogs should be used to adheres to our design system guidelines.",
category = Category.CUSTOM_LINT_CHECKS,
priority = 10,
severity = Severity.ERROR,
implementation = Implementation(
AndroidToastDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)

Avec la modification de la sévérité pour Severity.ERROR, notre vérificateur va désormais renvoyer une erreur 🚫.

Règle lint personnalisée lançant une erreur ⛔ sur l’usage de la classe Toast du package android.widget.Toast

Récap:

Dans cet article, nous avons créé un module “checks” dans notre projet Android, intégrant des règles lint personnalisées. Nous avons élaboré un détecteur (AndroidToastDetector) pour repérer l’utilisation du Toast par défaut, défini une règle lint personnalisée avec des propriétés telles que la description du problème et la sévérité, et enregistré cette règle dans un registre (ToastIssueRegistry).

Ktlint, Detekt

Il existe plusieurs bibliothèques de linting pour Kotlin/Android, dont ktlint, développé et maintenu par Pinterest, ainsi que Detekt, tous deux étant des projets open source.

Lorsque Twitter a amorcé l’adoption de Compose dans son application Android, ils ont créé un ensemble de règles lint spécifiques pour aider les équipes à utiliser efficacement ce framework en interne. Ces règles lint peuvent être consultées à ici.

Liens utiles

Improve your code with lint checks

Android Lint API guide

Documentation ktlint

Documentation Detekt

#AndroidDevSummit
#KotlinConf17

Si cet article sur la création de règles lint Android vous a été utile et instructif, n’hésitez pas à le partager et suivre AndroidMood pour rester informé des dernières actualités et mises à jour.

--

--