Tarjeta Presente
Device Connect (POS Caja)
Android
30 min
integración desde archivo aar copiar dist/sdconn release aar al directorio libs/ del módulo de la aplicación agregar la dependencia en build gradle kts dependencies { implementation(files("libs/sdconn release aar")) // dependencias transitivas (requeridas) implementation("com github mik3y\ usb serial for android 3 8 1") implementation("com squareup okhttp3\ okhttp 4 12 0") implementation("org jetbrains kotlinx\ kotlinx serialization json 1 7 3") implementation("org jetbrains kotlinx\ kotlinx coroutines android 1 9 0") implementation("androidx security\ security crypto 1 1 0 alpha06") } agregar el repositorio de jitpack en settings gradle kts (necesario para usb serial for android) dependencyresolutionmanagement { repositories { google() mavencentral() maven { url = uri("https //jitpack io") } } } desde módulo local si se prefiere incluir el sdk como módulo del proyecto copiar la carpeta sdconn/ al proyecto agregar en settings gradle kts include("\ sdconn") agregar la dependencia dependencies { implementation(project("\ sdconn")) } permisos el sdk declara estos permisos en su manifiesto (se fusionan automáticamente) \<uses permission android\ name="android permission internet" /> \<uses feature android\ name="android hardware usb host" android\ required="false" /> internet — necesario para comunicarse con el dispositivo por http y con la api de mobbex usb host — necesario solo para conexión serial declarado como required="false" para que la app funcione en dispositivos sin usb host (usando solo http) permisos usb cuando se conecta un dispositivo usb, android muestra un diálogo pidiendo permiso al usuario si se desea aceptar automáticamente, agregar un intent filter en la activity principal \<activity android\ name=" mainactivity"> \<intent filter> \<action android\ name="android hardware usb action usb device attached" /> \</intent filter> \<meta data android\ name="android hardware usb action usb device attached" android\ resource="@xml/device filter" /> \</activity> con res/xml/device filter xml \<?xml version="1 0" encoding="utf 8"?> \<resources> \<usb device /> \</resources> inicialización import com mobbex sdconn sdconn import com mobbex sdconn model sdconnconfig // con valores por defecto val sdconn = sdconn(context) // con configuración personalizada val sdconn = sdconn(context, sdconnconfig( serialbaudrate = 115200, mobbexapibase = "https //api mobbex com", debug = true )) se recomienda crear una única instancia de sdconn a nivel de application o usando inyección de dependencias configurar credenciales las credenciales son la clave api y el token de acceso de mobbex son necesarias para que el sdk pueda crear operaciones de pago sdconn setcredentials( apikey = "clave api mobbex", accesstoken = "token de acceso mobbex" ) las credenciales se almacenan cifradas con encryptedsharedpreferences (aes 256) persisten entre sesiones de la aplicación verificar si están configuradas if (sdconn credentialsconfigured) { // listo para operar } borrar credenciales sdconn clearcredentials() conectar un dispositivo opción 1 serial (usb) try { sdconn connectserial() // conectado — el estado cambia a connected(mode="serial", detail="portname") } catch (e sdconnexception) { // no se encontró dispositivo usb serial } el sdk busca todos los drivers usb serial disponibles abre cada puerto y envía un mensaje hello el primer dispositivo que responda queda conectado si ninguno responde, lanza sdconnexception opción 2 red (http) la conexión http requiere un proceso de emparejamiento con pin // 1 solicitar emparejamiento — el dispositivo muestra un pin de 6 dígitos sdconn requestpairing(ip = "192 168 1 50", port = 5000) // 2 el usuario lee el pin de la pantalla del dispositivo // 3 confirmar con el pin val device = sdconn confirmpairing( ip = "192 168 1 50", port = 5000, pin = "847293" ) // conectado — el dispositivo queda en modo pinpad // se guarda un token de confianza para futuras reconexiones conexión http directa (sin emparejamiento) si solo se necesita conectar sin el flujo de pairing (por ejemplo, para pruebas) sdconn connecthttp(ip = "192 168 1 50", port = 5000) reconexión automática una vez emparejado un dispositivo, se puede reconectar sin pin if (sdconn hassaveddevice()) { try { val device = sdconn reconnect() // reconectado a ${device name} en ${device ip} ${device port} } catch (e sdconnexception) { // dispositivo no alcanzable o token rechazado } } observar el estado de conexión lifecyclescope launch { sdconn connectionstate collect { state > when (state) { is connectionstate disconnected > showdisconnected() is connectionstate searching > showsearching() is connectionstate connected > showconnected(state mode, state detail) is connectionstate error > showerror(state message) } } } leer una tarjeta la operación de lectura ejecuta internamente obtiene información del dispositivo (serial number, modelo) obtiene la ubicación gps del dispositivo crea una operación en la api de mobbex envía el token al dispositivo para que lea la tarjeta devuelve los datos de la tarjeta import com mobbex sdconn model readrequest val result = sdconn read(readrequest( total = 15 00, currency = "ars", hideamount = false, test = false // true para operaciones de prueba )) if (result result) { val sourcedata = result sourcedata // datos de la tarjeta leída pin, emvdata, cryptogram, ksn, track2 } else { val error = result error // "timeout", "cancelled", "not in pinpad mode", etc } cancelar lectura sdconn cancelread() mostrar resultado en pantalla después de procesar el pago en el servidor, mostrar el resultado en la pantalla del dispositivo import com mobbex sdconn model displayrequest // pago aprobado sdconn display(displayrequest( status = "success", title = "pago aprobado", total = 15 00, currency = "ars", text = "id 123456", timeout = 10 )) // pago rechazado sdconn display(displayrequest( status = "error", title = "rechazado", timeout = 5 )) // ocultar pantalla antes del timeout sdconn dismissdisplay() valores de status por nombre true 330,331left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type por código numérico true 330,331left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type desconectar // desconectar sin borrar datos guardados sdconn disconnect() // desconectar y borrar dispositivo + token de confianza sdconn forgetdevice() cambiar modo del dispositivo sdconn setmode("pinpad") true 330,331left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type información del dispositivo val info = sdconn getdeviceinfo() // info type, info serialnumber, info deviceextras val location = sdconn getdevicelocation() // location latitude, location longitude, location accuracy la información del dispositivo se cachea tras la primera consulta la ubicación se consulta en tiempo real flujo completo de ejemplo class paymentactivity appcompatactivity() { private lateinit var sdconn sdconn override fun oncreate(savedinstancestate bundle?) { super oncreate(savedinstancestate) sdconn = sdconn(this, sdconnconfig(debug = true)) sdconn setcredentials("mi api key", "mi access token") lifecyclescope launch { // 1 conectar por serial try { sdconn connectserial() } catch (e exception) { showerror("no se encontró dispositivo usb") return\@launch } // 2 leer tarjeta val result = sdconn read(readrequest(total = 100 00)) if (result result) { // 3 enviar sourcedata al servidor para procesar el pago val paymentok = processpaymentonserver(result sourcedata!!) // 4 mostrar resultado en el dispositivo if (paymentok) { sdconn display(displayrequest( status = "success", title = "aprobado", total = 100 00 )) } else { sdconn display(displayrequest( status = "error", title = "rechazado" )) } } else { showerror(result error ? "error desconocido") } } } override fun ondestroy() { super ondestroy() sdconn disconnect() } } troubleshooting no se detecta el dispositivo usb verificar que el dispositivo android soporte usb host (la mayoría de tablets y pos lo soportan) verificar que el cable usb sea de datos (no solo de carga) verificar que el usuario haya aceptado el diálogo de permisos usb activar debug = true en la configuración para ver logs detallados en logcat error "device not reachable" en conexión http verificar que el dispositivo pos y el dispositivo android estén en la misma red wi fi verificar que el puerto (por defecto 5000) esté correcto probar la conexión con un navegador http //\<ip> 5000/device/hello error "mobbex credentials not configured" llamar a sdconn setcredentials(apikey, accesstoken) antes de ejecutar read() verificar que las credenciales sean válidas error "timeout" en lectura de tarjeta el dispositivo no detectó una tarjeta en 120 segundos verificar que el dispositivo esté en modo pinpad verificar que el lector de tarjetas del dispositivo funcione correctamente descarga