Aller au contenu
Tous les articles

Le scan de codes-barres avec ML Kit sur Android en 2026 : comment Stocky ajoute un article au garde-manger en moins d'une seconde

Un guide pratique 2026 du scan de codes-barres sur l'appareil avec ML Kit et CameraX : réglage des formats, recherche produit hors ligne, et le calcul d'usage partiel d'une app de garde-manger.

MFKAPPS 6 min de lecture

Taper un article d’épicerie dans une application est une petite taxe que l’on paie à chaque achat. Nom, marque, taille, parfois une catégorie — pour quelqu’un qui approvisionne une cuisine, ce sont trente secondes de friction multipliées par chaque produit possédé. La seule version d’une app de garde-manger qui vaille la peine doit battre ce calcul, ce qui veut dire que le code-barres doit faire presque tout le travail.

C’est la contrainte autour de laquelle Stocky est construit : pointez la caméra vers un code-barres, et le produit est dans le garde-manger une seconde plus tard — nom, taille, catégorie, données nutritionnelles, tout est rempli. Voici le pipeline derrière cette seconde, et les parties qui ont pris plus de temps à bien faire que le scan lui-même.

Le pipeline de scan : CameraX + ML Kit Barcode Scanning

L’API ML Kit Barcode Scanning est un modèle distinct de celui de Text Recognition — plus petit, plus rapide, et construit pour exactement une tâche : trouver le format et la valeur encodée d’un code-barres dans une image de caméra. La mise en place tient en une ligne Gradle et un analyzer CameraX :

// app/build.gradle.kts
dependencies {
    implementation("com.google.mlkit:barcode-scanning:17.3.0")
    implementation("androidx.camera:camera-camera2:1.4.0")
    implementation("androidx.camera:camera-lifecycle:1.4.0")
}
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.common.InputImage
import androidx.camera.core.ImageProxy

private val options = BarcodeScannerOptions.Builder()
    .setBarcodeFormats(
        Barcode.FORMAT_EAN_13,
        Barcode.FORMAT_EAN_8,
        Barcode.FORMAT_UPC_A,
        Barcode.FORMAT_UPC_E,
    )
    .build()

private val scanner = BarcodeScanning.getClient(options)

@androidx.camera.core.ExperimentalGetImage
fun analyzeFrame(image: ImageProxy, onFound: (String) -> Unit) {
    val media = image.image ?: return image.close()
    val input = InputImage.fromMediaImage(media, image.imageInfo.rotationDegrees)

    scanner.process(input)
        .addOnSuccessListener { barcodes ->
            barcodes.firstOrNull()?.rawValue?.let(onFound)
        }
        .addOnCompleteListener { image.close() }
}

L’appel setBarcodeFormats compte plus qu’il n’y paraît. Laissé par défaut, le scanner cherche aussi des QR codes, du PDF417, de l’Aztec, et une demi-douzaine d’autres formats qu’il ne verra jamais sur une boîte de tomates — chaque image paie le prix de cette recherche. Les produits de grande distribution vivent presque entièrement dans les formats EAN-13, EAN-8, UPC-A et UPC-E. Se limiter à ces quatre formats réduit le travail inutile sur chaque image et, plus utile encore, réduit les fausses détections issues de motifs parasites en arrière-plan.

D’un nombre à 13 chiffres à un produit que l’on peut afficher

Un code-barres, ce ne sont que des chiffres. Le produit réel — nom, marque, taille de l’emballage, informations nutritionnelles — doit venir d’ailleurs. Stocky le résout via Open Food Facts, la base de données produits ouverte et alimentée par la communauté, complétée par des produits turcs soumis par la communauté que le jeu de données public manque.

La recherche elle-même est un simple appel REST indexé sur le code scanné :

suspend fun lookupProduct(barcode: String): ProductInfo? {
    localCache.find(barcode)?.let { return it }

    return runCatching {
        api.getProduct(barcode).toProductInfo()
    }.getOrNull()?.also { localCache.save(barcode, it) }
}

Deux décisions ici pèsent plus lourd que le code ne le suggère :

  • Le cache d’abord, pas le réseau d’abord. Une fois qu’un code-barres a été résolu une fois — par n’importe qui, y compris un scan précédent sur le même appareil — il est dans Room, et le scan suivant est instantané et hors ligne. Pour une app de garde-manger, la même douzaine de produits (lait, œufs, la même marque de pain) est constamment rescannée ; le taux de succès du cache grimpe vite.
  • Un échec n’est pas une impasse. Les produits sans marque ou spécifiques à une région ne seront pas toujours dans Open Food Facts. Quand la recherche revient vide, Stocky bascule directement vers un court formulaire de saisie manuelle pré-rempli avec le code-barres, plutôt qu’une simple erreur. L’utilisateur termine en deux champs, et — avec son consentement — cette saisie peut renforcer le jeu de données communautaire pour la prochaine personne qui scanne ce code.

Garder « moins d’une seconde » honnête

Le modèle de scan lui-même résout un code-barres en bien moins de 100 ms sur un téléphone milieu de gamme. Presque tout le budget de latence perçue va ailleurs : le démarrage de la caméra, la fréquence d’images de l’analyzer, et éviter les détections en double.

Le détail qui compte vraiment pour la sensation : sans anti-rebond, une caméra tenue déclenche l’analyzer à chaque image — plus de vingt détections du même code-barres pendant le temps qu’il faut à une main pour se stabiliser. Déclencher une recherche, un retour haptique et une mise à jour d’interface pour chacune se ressent comme du bégaiement, pas de la rapidité.

private var lastCode: String? = null
private var lastAt = 0L

fun onBarcodeFound(code: String, now: Long) {
    if (code == lastCode && now - lastAt < 1_500) return
    lastCode = code
    lastAt = now
    handleScan(code)
}

Une fenêtre d’anti-rebond de 1,5 seconde par code suffit à condenser toute une salve de détections en un seul scan, tout en permettant à l’utilisateur de rescanner immédiatement le même article volontairement (ajouter un deuxième pot de yaourt au garde-manger, par exemple) une fois la caméra éloignée puis ramenée.

Le problème de l’usage partiel

Un article de garde-manger n’est pas un simple indicateur présent-ou-absent, et c’est la partie que le scan de codes-barres seul ne résout pas. Le modèle de données réel de Stocky suit une quantité restante pour chaque emballage : une brique de lait d’un litre n’est pas « en stock » ou « épuisée », c’est 1000 ml, puis 700 ml après le petit-déjeuner, puis 0, et elle bascule alors discrètement sur la liste de courses. Rescanner le code-barres sur le même emballage permet à l’utilisateur d’enregistrer un prélèvement partiel — « boire 300 ml » — au lieu de forcer un cycle complet « c’est fini, en ajouter un nouveau » pour quelque chose qui est encore à moitié plein au frigo.

C’est ce choix de conception, et lui seul, qui rend ensuite honnêtes les prédictions de rupture de stock : elles s’appuient sur une véritable courbe de consommation par produit, et non sur un interrupteur grossier en-stock/épuisé qui revient à zéro à chaque fois et ne dit rien sur le rythme réel.

Ce qui reste sur l’appareil, et ce qui n’y reste pas

L’image ne quitte jamais le téléphone — le modèle de codes-barres de ML Kit tourne entièrement sur l’appareil, comme son cousin de reconnaissance de texte. La seule chose qui traverse le réseau, ce sont les chiffres du code-barres eux-mêmes, envoyés pour retrouver un produit que des millions d’autres acheteurs ont déjà scanné. Aucune photo n’est capturée ni stockée, et rien concernant qui scanne n’accompagne la requête. Le contenu du garde-manger, l’historique de consommation et les dépenses restent locaux ; seule la recherche produit anonyme est partagée.

C’est une surface de confidentialité plus petite que l’OCR, et cela vaut la peine de s’en souvenir en choisissant entre des API de vision pour une fonctionnalité : si la valeur dont vous avez besoin est un identifiant fixe et structuré — un code-barres, pas une page de prose — un modèle de scan est à la fois plus rapide à intégrer et plus facile à défendre dans une politique de confidentialité qu’un reconnaisseur qui doit lire le document de quelqu’un.

Stocky est désormais disponible sur Google Play — scannez un code-barres, et le reste du suivi de cuisine suit de là. En savoir plus sur la page de l’app.