Verdetto
Español

Escanear desde otra app

Verdetto responde a tres intents y a un envío compartido. Nada de esto necesita un permiso, una biblioteca ni una clave. La persona conserva todas las comprobaciones de seguridad y todos los ajustes de la app; tu app recibe el texto del código en el momento en que ella lo confirma.

Los intents

AcciónFiltro en el manifiestoQué ocurreResultado
com.google.zxing.client.android.SCANSí, los intents implícitos funcionan.Abre el escáner. El primer código que la persona fija se devuelve, como lo hacía el ZXing Barcode Scanner.RESULT_OK con SCAN_RESULT y SCAN_RESULT_FORMAT
app.scanner.action.SCANSí.Abre el escáner. Iniciado para obtener un resultado (un result launcher o startActivityForResult) devuelve el código de la misma manera; iniciado sin más, solo abre la app en el escáner.RESULT_OK con los dos extras cuando se inicia para obtener un resultado
app.scanner.action.CARDSin filtro: solo un intent explícito con el paquete com.verdettoqr.scanner.Abre el editor de la tarjeta de contacto de la persona, el código que muestra para compartir sus datos. Pensado para los widgets y accesos directos de la propia app; otra app puede llamarlo, pero no devuelve nada.Ninguno
android.intent.action.SEND con image/*Sí.Decodifica una imagen: la app muestra la hoja de resultados con los códigos que contiene.Ninguno

La persona puede desactivar la devolución en Ajustes, en «Entregar resultados a otras apps» («Cuando una app pide un escaneo, el código vuelve a esa app»), que está activada por defecto. Desactivada, cualquiera de las dos acciones de escaneo abre el escáner como un inicio normal y tu launcher recibe RESULT_CANCELED cuando la persona sale. Volver atrás desde el escáner también es RESULT_CANCELED.

Hoy no se lee ningún extra de la petición: ni SCAN_MODE, SCAN_FORMATS, PROMPT_MESSAGE, SAVE_HISTORY ni ningún otro. El escáner lee todas las simbologías que conoce en cada llamada. Un código que las comprobaciones de la app señalan se devuelve de todos modos; la persona ve primero el aviso y decide.

El resultado

  • SCAN_RESULT (String): el contenido del código, exactamente los bytes que llevaba el código, decodificados como texto (UTF-8 donde la simbología lo permite, y si no, el juego de caracteres propio de la simbología).
  • SCAN_RESULT_FORMAT (String): la simbología en mayúsculas con guiones bajos, con los nombres de ZXing donde existen. Se entregan hoy: QR_CODE, MICRO_QR_CODE, RMQR_CODE, DATA_MATRIX, AZTEC, PDF417, MAXICODE, HAN_XIN, EAN_13, EAN_8, UPC_A, UPC_E, CODE_128, CODE_39, CODE_93, CODABAR, ITF, DATABAR, DATABAR_EXPANDED, DATABAR_LIMITED, DX_FILM_EDGE, y las demás simbologías que añaden los decodificadores propios de la app, con la misma grafía (el nombre que muestra la hoja de resultados, en mayúsculas, con espacios y guiones como guiones bajos).

Nada más viaja: ni imagen, ni ubicación, ni historial.

Kotlin

private val scan = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        val text = result.data?.getStringExtra("SCAN_RESULT")
        val format = result.data?.getStringExtra("SCAN_RESULT_FORMAT")
        // use text and format
    }
}

fun startScan() {
    val intent = Intent("app.scanner.action.SCAN")
    if (intent.resolveActivity(packageManager) != null) scan.launch(intent)
    else startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(GET_VERDETTO)))
}

// the store page, with the developers referrer
private const val GET_VERDETTO =
    "https://play.google.com/store/apps/details?id=com.verdettoqr.scanner&referrer=utm_source%3Ddevelopers%26utm_medium%3Ddocs%26utm_campaign%3Ddevelopers"

En Android 11 y posteriores, añade la consulta a tu manifiesto para que resolveActivity pueda ver la app:

<queries>
    <intent>
        <action android:name="app.scanner.action.SCAN" />
    </intent>
</queries>

Java

private final ActivityResultLauncher<Intent> scan = registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(), result -> {
            if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
                String text = result.getData().getStringExtra("SCAN_RESULT");
                String format = result.getData().getStringExtra("SCAN_RESULT_FORMAT");
                // use text and format
            }
        });

void startScan() {
    Intent intent = new Intent("app.scanner.action.SCAN");
    if (intent.resolveActivity(getPackageManager()) != null) scan.launch(intent);
    else startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(GET_VERDETTO)));
}

La acción de ZXing

El código escrito para el ZXing Barcode Scanner sigue funcionando: envía com.google.zxing.client.android.SCAN de la misma manera y lee los mismos dos extras. Si más de un escáner del teléfono responde, el sistema pregunta a la persona cuál usar; enviar el intent al paquete com.verdettoqr.scanner se lo ahorra.

Lo que ve la persona

El escáner se abre como siempre, con sus propias comprobaciones. Cuando un código se fija, la app lo devuelve y se cierra; nada tuyo aparece en la pantalla, y nada suyo (historial, ajustes, lista de seguridad) se toca con la llamada.

Probar en un teléfono sin la app. La página de la tienda con el referrer de desarrolladores, la misma dirección que abre el fallback de los ejemplos: Descárgala en Google Play. La fuente de esta página es el INTENT.md de la propia app; cuando los dos difieren, el repositorio de la app tiene razón y esta página va por detrás.