Ir al contenido

El SDK Android de Hooky

La conversación de Hooky, nativa en tu app Android: escrita con Jetpack Compose (Material 3), sin WebView, con los colores de tu web. Funciona tanto en una app Compose como en una app con vistas XML, en Kotlin o en Java.

Una pantalla de app Android con la burbuja de Hooky abajo a la derecha y un mensaje no leído. La conversación de Hooky en Android: una foto, un PDF recibido y un enlace.
La burbuja con su indicador de no leídos, y la conversación con una foto y un PDF.

Requisitos

  • Android 6.0 o posterior (minSdk 23).
  • El SDK se compila con compileSdk 36 (Android 16): compila tu app con la misma versión o una más reciente.
  • Kotlin o Java. Tu app no necesita usar Compose: el SDK lo incluye para su propia pantalla.
  • Dependencias: AndroidX (Activity, Core, Compose), las corrutinas de Kotlin y OkHttp. Ninguna biblioteca de imágenes, de JSON ni de analítica.
  • Una cuenta de Hooky y un sitio: su clave pública está en Sitios › Instalar, la misma que el data-site-key de la burbuja web.

Instalación

El SDK se sirve desde su repositorio de GitHub, como repositorio Maven (GitHub Pages). Añádelo a tu proyecto, en settings.gradle.kts:

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven("https://defdjamel.github.io/hooky-android")
    }
}

y luego la dependencia al módulo de tu app:

// app/build.gradle.kts
dependencies {
    implementation("com.heyhooky:hooky-android:1.0.0")
}

En Groovy: maven { url 'https://defdjamel.github.io/hooky-android' } y implementation 'com.heyhooky:hooky-android:1.0.0'. Las dependencias del SDK (AndroidX, Compose, OkHttp, corrutinas) vienen de google() y mavenCentral(). El código fuente tiene licencia MIT: github.com/Defdjamel/hooky-android.

Empezar en 3 líneas

// 1. Una vez, al arrancar (Application.onCreate es el mejor sitio)
Hooky.configure(context, "TU_CLAVE_PUBLICA")

// 2. La burbuja ya hecha, en una esquina de tu pantalla (Compose)
HookyBubble(Modifier.align(Alignment.BottomEnd).navigationBarsPadding().padding(20.dp))

// 3. O la conversación desde tu propio botón
Hooky.open(context)

configure carga el nombre, el color y el mensaje de bienvenida del sitio, recupera la conversación guardada y mantiene abierta la conexión en vivo mientras la app está en primer plano.

class MiApp : Application() {
    override fun onCreate() {
        super.onCreate()
        Hooky.configure(this, "TU_CLAVE_PUBLICA")
    }
}
// AndroidManifest.xml: <application android:name=".MiApp" …>

Todas las llamadas se hacen en el hilo principal y nunca lanzan un error. configure también acepta translation = false, para quitar la traducción de los mensajes del equipo (mira Traducción de los mensajes), y apiUrl, que solo sirve para hacer pruebas contra tu propio servidor.

La burbuja

Un botón con el color de tu web (64 dp), el logo de Hooky y un indicador para las respuestas aún no leídas. Al tocarlo se abre la conversación. Aparece en cuanto se carga la apariencia del sitio.

Jetpack Compose

Box(Modifier.fillMaxSize()) {
    MiPantalla()
    HookyBubble(Modifier.align(Alignment.BottomEnd).navigationBarsPadding().padding(20.dp))
}

// Con tu propia acción
HookyBubble(onClick = { mostrarAyuda = true })

Vistas XML

<FrameLayout …>
    <!-- tu pantalla -->
    <com.heyhooky.sdk.HookyBubbleView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="20dp" />
</FrameLayout>

La actividad que la muestra debe ser una AppCompatActivity o una ComponentActivity.

Abrir y cerrar la conversación

Hooky.open(context)   // a pantalla completa (una Activity), desde cualquier Context
Hooky.close()         // la cierra

La pantalla de conversación, HookyActivity, la declara el SDK: no tienes que añadir nada a tu manifiesto.

Mensajes no leídos

La burbuja ya lleva su indicador. Para tus propios botones, el número de respuestas del equipo aún no vistas se sigue en vivo; vuelve a 0 cuando se abre la conversación.

// Compose: un StateFlow<Int>
val noLeidos by Hooky.unreadCount.collectAsState()
BadgedBox(badge = { if (noLeidos > 0) Badge { Text("$noLeidos") } }) { Icon(Icons.Default.Email, null) }

// Vistas o Java: un listener (el valor actual y luego cada cambio)
val escucha: Closeable = Hooky.addUnreadCountListener { n -> badge.isVisible = n > 0 }
escucha.close()   // para detenerlo

En Java:

Hooky.configure(this, "TU_CLAVE_PUBLICA");
Closeable escucha = Hooky.addUnreadCountListener(n -> badge.setText(String.valueOf(n)));

Las respuestas llegan en vivo mientras la app está en primer plano; al volver, el SDK recupera lo que se ha perdido. La versión 1.0.0 no envía notificaciones push a tus usuarios. Hooky.isConfigured y Hooky.VERSION completan la API.

Identificar al usuario

Tu app sabe quién ha iniciado sesión: díselo a Hooky. En la ficha de la conversación, tu equipo ve el nombre, el e-mail, tu propio identificador del usuario, el dispositivo y los datos que añadas. Con un e-mail, la conversación ya no pide ni nombre ni e-mail.

// Después de iniciar sesión
Hooky.identify(
    name = "Lou",
    email = "lou@example.com",
    userId = "u_1042",                                  // tu propio identificador
    attributes = mapOf("plan" to "Pro", "carrito" to 49.9, "beta" to true),
)

// Más tarde: se combinan con los anteriores
Hooky.setAttributes(mapOf("carrito" to 12, "ultima_pantalla" to "Pago"))
Hooky.setAttributes(mapOf("beta" to null))             // null borra una clave

// Al cerrar sesión
Hooky.reset()

En Java: Hooky.identify("Lou", "lou@example.com", "u_1042");, o con un Map<String, Object> de datos como cuarto parámetro.

Cómo funciona

  • Si aún no hay conversación, todo se queda en memoria (incluso antes de configure) y se envía con el primer mensaje. Después, cada cambio se envía al momento, agrupado (un solo envío para todo lo que cambia en el mismo segundo). Sin conexión, se vuelve a enviar con el siguiente mensaje o cuando la app vuelve al primer plano.
  • name y email sustituyen a los de la conversación (null los borra en el dispositivo); userId = null lo deja como está.
  • El userId se guarda con el token de la conversación. Un userId distinto significa otra cuenta en el mismo dispositivo: la conversación se olvida, como con reset(). El nuevo usuario no ve el hilo del anterior.
  • Hooky.reset() cierra la conversación y olvida el hilo, la identidad y los datos. Llámalo al cerrar sesión.

Reglas de los datos

CampoRegla
Datos libresUn Map plano: 50 claves como máximo, 8 KB en total. Las claves nuevas sustituyen a las anteriores; las demás se mantienen.
ClaveDe 1 a 64 caracteres: letras, cifras, espacios, _, . y -. Si no, se ignora.
ValorUn texto (cortado a 500 caracteres), un número o un booleano. null borra la clave. Las listas y los maps se ignoran; los demás objetos se envían como texto.
userId200 caracteres como máximo.
name, emailEl nombre: 100 caracteres como máximo. El e-mail: una dirección válida; si no, se ignora.

Hooky recorta lo que se pasa, sin rechazar nunca el mensaje de tu usuario.

Estos datos son declarativos: la clave del sitio es pública, así que cualquiera puede usarla para enviar el nombre, el e-mail o el userId que quiera. Ayudan a tu equipo a situar a la persona, no demuestran quién es. Nunca pongas en ellos un secreto (contraseña, token, número de tarjeta) ni los uses para dar acceso o actuar sobre una cuenta: compruébalo siempre por tu lado.

Estadísticas

Cuenta lo que pasa en tu app, como Hooky.track en la web: las tarjetas aparecen en Estadísticas, junto a las del sitio. Llámalo justo después de que la acción salga bien.

Hooky.track("registro")
Hooky.track("pedido", 49.9, mapOf("plan" to "pro", "plazas" to 3, "prueba" to false))
  • El segundo parámetro, value: un importe o una cantidad, sumado en la tarjeta. Las propiedades son planas (textos, números, booleanos).
  • Llama primero a configure: antes, track no hace nada. Los fallos son silenciosos; sin conexión, el evento se pierde.
  • Las mismas reglas que en la web (nombre, 20 propiedades como máximo, límite): mira Estadísticas en la página.

Nunca envíes datos personales (e-mail, nombre, teléfono) en un evento. Cuenta acciones, no personas.

Lo que hace la conversación

  • El primer mensaje, con nombre y e-mail opcionales (o los de identify), y luego un hilo como el de la burbuja web: separadores de días, nombres del equipo, enlaces, emojis en grande, «Leído», «… está escribiendo», mensajes anteriores a petición.
  • Hasta 4 archivos adjuntos por mensaje, de 10 MB cada uno, con una barra de progreso: fotos del selector del sistema (no hay que pedir ningún permiso), de la cámara (a través de la app de cámara del teléfono) y PDF de Archivos.
  • Las fotos recibidas se abren a pantalla completa (pellizca o toca dos veces para hacer zoom); los archivos, en la app que sabe leerlos, o se comparten.
  • El borrador sobrevive al cierre de la pantalla y de la app. El teclado nunca tapa el campo de texto.
  • Errores claros: sin conexión, demasiados mensajes seguidos, archivo demasiado pesado o no aceptado.

Lo que el SDK añade a tu app

  • El permiso INTERNET, y ningún otro.
  • HookyActivity y un FileProvider (autoridad <tu.package>.hooky.fichiers, limitado a la carpeta hooky/ de la caché de tu app) para las fotos de la cámara y los archivos recibidos.
  • Unas <queries> para las apps que hacen fotos o abren PDF (Android 11 y posteriores).

Si tu app declara por su cuenta el permiso CAMERA, Android también lo exige para abrir la app de cámara: en ese caso, el SDK lo pide antes.

Traducción de los mensajes

Tu usuario y tu equipo escriben cada uno en su idioma, como con la burbuja web (mira Traducción de los mensajes).

  • Debajo de un mensaje del equipo escrito en otro idioma que el de la conversación (el del dispositivo), aparece un enlace discreto Traducir. Una vez traducido, el mensaje se muestra en el idioma del usuario, con «Traducido del inglés · Ver el original» para volver al texto original.
  • El botón de traducción de la cabecera ofrece Traducir siempre: los mensajes del equipo llegan entonces ya traducidos. La elección se guarda en el dispositivo, para cada clave de sitio.
  • Si una traducción falla, se muestra un breve error con Reintentar. Los mensajes del usuario nunca se traducen en su pantalla; tu equipo tiene su propio botón Traducir, en el panel y en la app de Hooky.
  • Solo se traduce el texto, no los archivos adjuntos. La traducción está activada por defecto; para quitarla de tu app: Hooky.configure(context, "TU_CLAVE_PUBLICA", translation = false).

Lo que envía el SDK

Lo mismo que envía la burbuja web, y nada más. Sin identificador publicitario, sin identificador de dispositivo, sin biblioteca de analítica. Para rellenar la sección Seguridad de los datos de tu ficha de Google Play:

DatoCuándoSeguridad de los datos
MensajesCuando el usuario escribeMensajes: Otros mensajes en la aplicación
Fotos y PDFCuando los adjuntaFotos y vídeos: Fotos; Archivos y documentos
Nombre y e-mailSi los da, o si los pasas a identifyInformación personal: Nombre, Dirección de correo electrónico
Tu userIdSi lo pasas a identifyInformación personal: IDs de usuario
Datos libresLo que pasas a identify y setAttributesSegún lo que pongas
Eventos trackCuando los envías, sin identificador de personaActividad en la aplicación: Otras acciones (Analítica)
Dispositivo, idioma, zona horaria, appCon la conversaciónInformación técnica para tu equipo (mira más abajo)
  • Estos datos sirven para la funcionalidad de la aplicación (la atención al cliente), y las estadísticas para tu analítica. Están cifrados en tránsito (HTTPS y WebSocket seguro). Hooky los trata por cuenta tuya: según Google Play, no es compartir datos con terceros.
  • El dispositivo es legible: «Samsung SM-S918B · Android 15» (fabricante, modelo y versión de Android). La página de la conversación es android-app://<tu.package>. Cada petición lleva X-Hooky-Client: hooky-android/1.0.0 y X-Hooky-App: <package> <versionName> (<versionCode>): tu equipo ve que la conversación viene de «Android · com.example.app 2.3.1 (231)».
  • En el dispositivo: el token de la conversación (la única clave del usuario), el userId y el borrador, por clave de sitio, en un archivo privado de tu app en noBackupFilesDir: nunca se copia en la nube ni se restaura en otro dispositivo. Una traducción solo envía el identificador del mensaje y el idioma de la conversación.
  • Hooky es encargado del tratamiento según el RGPD: mira la política de privacidad. Tú sigues siendo responsable de tu ficha: declara lo que tu app envía de verdad.

Idioma, modo oscuro, accesibilidad

Idioma
La interfaz existe en francés, inglés, español, portugués, italiano y alemán. Sigue el idioma del dispositivo en el momento de configure, y en inglés por defecto. El idioma se envía con el primer mensaje, para que tu equipo responda en el idioma adecuado y a la hora adecuada (con la zona horaria).
Modo oscuro
La conversación y la burbuja siguen el tema claro u oscuro del sistema, con el color de tu web. No hay nada que configurar.
Accesibilidad
Etiquetas de TalkBack en cada control (la burbuja: «Abrir el chat con …», y el número de no leídos), y se respeta el tamaño de texto del sistema.

R8 y ProGuard

No hay nada que añadir. El SDK no usa reflexión e incluye sus propias reglas: R8 puede reducirlo todo en tu build de producción.

Solución de problemas

Mi web ha declarado sus direcciones: ¿se rechaza la app?
No. Una app no tiene dirección: se presenta con su cabecera X-Hooky-Client y funciona aunque el sitio haya declarado sus dominios. No añadas nada en Sitios.
La burbuja no aparece
Espera a la apariencia del sitio. Comprueba que se llama a configure, con la clave pública del sitio (no la clave secreta hks_…, ni una clave API hka_…). Sin red al arrancar, aparece la próxima vez que la app vuelve al primer plano.
Cierre inesperado con HookyBubbleView
La actividad debe ser una AppCompatActivity o una ComponentActivity.
Sin conexión
El mensaje muestra el error y se queda en el campo de texto; identify y setAttributes se vuelven a enviar más tarde. Los eventos track enviados sin conexión se pierden.
Otro usuario ve la conversación anterior
Llama a Hooky.reset() al cerrar sesión y pasa un userId a identify: un identificador distinto empieza con una conversación nueva.

Historial de versiones

1.0.0
Primera versión: configure, la burbuja Compose y XML, open y close, identify (con userId y datos libres), setAttributes, track, reset, los no leídos en vivo (StateFlow y listener de Java), fotos y PDF, la traducción de los mensajes del equipo, seis idiomas, modo oscuro y TalkBack.