Kotlin SDK
com.messagebird:bird-realtime es el cliente oficial de Kotlin para Bird Realtime: mantiene un WebSocket con el borde de Bird, se suscribe a canales y entrega eventos a medida que se publican. Está escrito a mano en lugar de generado, porque Realtime es un plano de datos WebSocket en lugar de una superficie REST, y habla el mismo dialecto de protocolo que los clientes de navegador y Swift.
Es una biblioteca JVM estándar, así que el mismo artefacto sirve para una app Android y un servidor. Los callbacks se ejecutan en el main looper de Android cuando existe uno, y en línea en caso contrario, así que no necesitas un build separado para cada caso.
Este cliente es el lado de recepción. Publicar eventos, autorizar canales y terminar conexiones son operaciones del lado del servidor en la Bird API; consulta publicar eventos.
Instalación
dependencies {
implementation("com.messagebird:bird-realtime:0.1.0")
}En Android, añade el permiso de internet a tu manifiesto. Una biblioteca ya no aporta uno:
<uses-permission android:name="android.permission.INTERNET" />Construir un cliente
import com.messagebird.realtime.BirdRealtime
import com.messagebird.realtime.BirdRealtimeOptions
val bird = BirdRealtime(
BirdRealtimeOptions(
appKey = "your-app-key",
region = "us1",
)
)Solo appKey es obligatorio, más region (us1 o eu1, que resuelve el host del borde) o un wsHost explícito. La clave de app es pública y se incluye en el código del cliente: identifica la app, no autoriza nada.
El socket se abre al construir el cliente, así que no necesitas llamar a connect() primero. connect() y disconnect() son para el ciclo de vida de la app: cierra el socket cuando tu activity desaparece y reábrelo cuando vuelve; los canales a los que te suscribiste se vuelven a suscribir automáticamente.
disconnect() deja el cliente reutilizable, así que conserva deliberadamente el hilo de trabajo en el que el cliente confina su estado. Cuando hayas terminado con un cliente de forma definitiva, haz close(), o ese hilo y el socket vivirán tanto como el proceso. La clase es AutoCloseable, así que un bloque use { } lo hace por ti. El cliente de Swift no necesita equivalente: libera ambos cuando desaparece la última referencia.
Suscribirse a un canal
val orders = bird.subscribe("orders")
orders.bind("order-updated") { data ->
println("order changed: $data")
}Los payloads llegan como kotlinx.serialization.json.JsonElement, así que léelos con la API de serialización en lugar de hacer casting.
Un canal cuyo nombre no tiene prefijo private- ni presence- es público: cualquier cliente con la clave de app puede suscribirse, así que trata su contenido como legible por cualquiera que pueda abrir tu app.
Canales privados y de presencia
Los canales privados y de presencia los autoriza tu backend, que posee el secreto de la app. Apunta el cliente a tu endpoint: hace POST de {"connection_id", "channel_name"} y espera {"auth", "member_data"?} de vuelta.
val bird = BirdRealtime(
BirdRealtimeOptions(
appKey = "your-app-key",
region = "us1",
authEndpoint = "https://your-backend.example.com/bird/auth",
authHeaders = mapOf("authorization" to "Bearer <session token>"),
)
)
val room = bird.subscribe("presence-room-42")
if (room is PresenceChannel) {
room.bind(BirdProtocol.Event.SUBSCRIPTION_SUCCEEDED) {
println("me: ${room.myId}, members: ${room.members.keys}")
}
room.bind(BirdProtocol.Event.MEMBER_ADDED) { member -> println("joined: $member") }
}Pasa un authorizer en su lugar para firmar a través de tu propia pila de red.
Un rechazo del servidor (una firma incorrecta, una app con capacidad agotada) llega a la conexión en lugar del canal, porque el protocolo no incluye atribución de canal. Obsérvalos con onError. Un fallo dentro de tu autorizador sí emite bird:subscription_error en el canal.
Iniciar sesión de un miembro
signin() indica al borde a qué miembro pertenece esta conexión. Esa identidad es lo que permite a la API dirigirse a un miembro o terminar sus conexiones, y es lo que satisface una app configurada para requerir conexiones autorizadas.
val bird = BirdRealtime(
BirdRealtimeOptions(
appKey = "your-app-key",
region = "us1",
memberAuthEndpoint = "https://your-backend.example.com/bird/auth/member",
)
)
val me = bird.signin() // suspending
println("signed in as ${me.memberId}")
bird.member.bind("order.shipped") { data ->
println("addressed to me: $data")
}Llama a signin() una vez. La identidad permanece en la conexión, así que el cliente vuelve a iniciar sesión automáticamente tras una reconexión. Un inicio de sesión automático fallido no tiene una llamada activa desde la que lanzar una excepción, así que aparece en onSigninError. Esto evita que un endpoint de miembro con fallos interfiera con las suscripciones a canales.
Ciclo de vida de la conexión
bird.onConnectionStateChange { previous, current ->
println("connection: $previous -> $current")
}
bird.onError { error ->
if (error.code == 4009) println("session ended elsewhere")
}La reconexión es automática, con backoff exponencial de jitter completo desde 1 s hasta un tope de 30 s. Los códigos de cierre en 4000-4099 son rechazos terminales: el cliente se detiene e informa el código, porque un rechazo es una decisión, no un fallo transitorio. Los códigos en 4200-4299 reconectan de inmediato; cualquier otro aplica backoff. Los canales se vuelven a suscribir con autorización nueva en cada reconexión. Consulta ciclo de vida de la conexión.
El transporte es TLS para todo host que no sea loopback. allowInsecure permite ws:// solo para localhost, 127.0.0.1 y [::1], así que una configuración copiada de un entorno de desarrollo no puede degradar silenciosamente el tráfico de producción.
Eventos de cliente
Con la configuración de eventos de cliente de la app habilitada, un cliente suscrito a un canal privado o de presencia puede publicar directamente a sus pares:
room.trigger("client-typing", buildJsonObject { put("on", true) })Consulta eventos de cliente.
Código fuente
github.com/messagebird/bird-sdk-kotlin, licencia MIT. Reporta incidencias allí.
Recursos relacionados
Continúa con la documentación, guías y ejemplos de este tema.