Saltar al contenido
Todas las entradas

Escaneo de códigos de barras con ML Kit en Android en 2026: cómo Stocky añade un artículo a la despensa en menos de un segundo

Una guía práctica 2026 del escaneo de códigos de barras en el dispositivo con ML Kit y CameraX: ajuste de formatos, búsqueda de producto sin conexión, y las matemáticas del uso parcial.

MFKAPPS 6 min de lectura

Escribir un artículo de compra en una app es un pequeño impuesto que se paga cada vez que se compra. Nombre, marca, tamaño, quizá una categoría — para alguien que abastece una cocina, son treinta segundos de fricción multiplicados por cada producto que tiene. La única versión de una app de despensa que merece la pena usarse tiene que vencer esa matemática, lo que significa que el código de barras tiene que hacer casi todo el trabajo.

Esa es la restricción sobre la que está construido Stocky: apunta la cámara a un código de barras y el producto está en la despensa un segundo después — nombre, tamaño, categoría, datos nutricionales, todo relleno. Aquí está el proceso detrás de ese segundo, y las partes que tardaron más en quedar bien que el propio escaneo.

El proceso de escaneo: CameraX + ML Kit Barcode Scanning

La API de Barcode Scanning de ML Kit es un modelo distinto al de Text Recognition — más pequeño, más rápido y construido para exactamente una tarea: encontrar el formato y el valor codificado de un código de barras dentro de un fotograma de cámara. La configuración es una línea de Gradle más un analyzer de 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() }
}

La llamada a setBarcodeFormats importa más de lo que parece. Dejado en el valor por defecto, el escáner también busca códigos QR, PDF417, Aztec y media docena de formatos más que nunca verá en una lata de tomate — cada fotograma paga el precio de esa búsqueda. Los productos de venta al público viven casi por completo en EAN-13, EAN-8, UPC-A y UPC-E. Limitarse a esos cuatro formatos reduce el trabajo desperdiciado en cada fotograma y, más útil aún, reduce las detecciones falsas positivas provocadas por patrones aleatorios del fondo.

De un número de 13 dígitos a un producto que se puede mostrar

Un código de barras son solo dígitos. El producto real — nombre, marca, tamaño del paquete, información nutricional — tiene que venir de otro sitio. Stocky lo resuelve contra Open Food Facts, la base de datos de productos abierta y alimentada por la comunidad, junto con productos turcos añadidos por la comunidad que el conjunto de datos público no cubre.

La búsqueda en sí es una simple llamada REST indexada por el código escaneado:

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

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

Dos decisiones aquí pesan más de lo que el código sugiere:

  • Primero la caché, no primero la red. Una vez que un código de barras se ha resuelto una vez — por cualquiera, incluido un escaneo anterior en el mismo dispositivo — ya está en Room, y el siguiente escaneo es instantáneo y sin conexión. En una app de despensa, la misma docena de productos (leche, huevos, la misma marca de pan) se vuelve a escanear constantemente; la tasa de aciertos de la caché sube rápido.
  • Un fallo no es un callejón sin salida. Los productos sin marca o específicos de una región no siempre estarán en Open Food Facts. Cuando la búsqueda vuelve vacía, Stocky pasa directamente a un formulario corto de entrada manual, precargado con el código de barras, en lugar de un simple error. El usuario termina con dos campos, y — con su consentimiento — esa entrada puede reforzar el conjunto de datos comunitario para la siguiente persona que escanee ese código.

Mantener honesto “menos de un segundo”

El propio modelo de escaneo resuelve un código de barras en bastante menos de 100 ms en un teléfono de gama media. Casi todo el presupuesto de latencia percibida se va en todo lo que lo rodea: el calentamiento de la cámara, la tasa de fotogramas del analyzer y evitar detecciones duplicadas.

El detalle que realmente importa para la sensación: sin un debounce, una cámara sostenida dispara el analyzer en cada fotograma — más de veinte detecciones del mismo código de barras en el tiempo que tarda una mano en estabilizarse. Disparar una búsqueda, una vibración háptica y una actualización de interfaz por cada una se siente como bloqueos, no como velocidad.

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)
}

Una ventana de debounce de 1,5 segundos por código basta para colapsar toda una ráfaga de detecciones en un solo escaneo, permitiendo al mismo tiempo que el usuario vuelva a escanear el mismo artículo a propósito de inmediato (añadir un segundo yogur a la despensa, por ejemplo) una vez que aparta la cámara y la vuelve a acercar.

El problema del uso parcial

Un artículo de despensa no es un simple indicador de presente-o-ausente, y esa es la parte que el escaneo de códigos de barras por sí solo no resuelve. El modelo de datos real de Stocky rastrea una cantidad restante para cada paquete: un cartón de leche de un litro no está “en stock” o “agotado”, es 1000 ml, luego 700 ml después del desayuno, luego 0, y entonces pasa en silencio a la lista de la compra. Volver a escanear el código de barras del mismo paquete permite al usuario registrar un consumo parcial — “bebe 300 ml” — en lugar de forzar un ciclo completo de “se acabó, añade uno nuevo” para algo que todavía está medio lleno en la nevera.

Esa única decisión de diseño es lo que hace honestas después las predicciones de agotamiento: se construyen sobre una curva de consumo real por producto, no sobre un interruptor tosco de en-stock/agotado que vuelve a cero cada vez y no dice nada sobre el ritmo real.

Lo que se queda en el dispositivo, y lo que no

El fotograma nunca sale del teléfono — el modelo de códigos de barras de ML Kit se ejecuta por completo en el dispositivo, igual que su hermano de reconocimiento de texto. Lo único que cruza la red son los propios dígitos del código de barras, enviados para buscar un producto que millones de otros compradores ya han escaneado. No se captura ni se almacena ninguna foto, y nada sobre quién escanea acompaña la solicitud. El contenido de la despensa, el historial de consumo y los gastos permanecen locales; solo se comparte la búsqueda de producto anónima.

Esa es una superficie de privacidad más pequeña que la del OCR, y merece la pena recordarlo al elegir entre APIs de visión para una función: si el valor que necesitas es un identificador fijo y estructurado — un código de barras, no una página de prosa — un modelo de escaneo es a la vez más rápido de integrar y más fácil de defender en una política de privacidad que un reconocedor que tiene que leer el documento de alguien.

Stocky ya está disponible en Google Play — escanea un código de barras, y el resto del seguimiento de la cocina sigue a partir de ahí. Más información en la página de la app.