Iniciar sesión

Por qué tiramos nuestra app de Flutter y reconstruimos Cliqer Remote en nativo, sobre un núcleo en Rust

Creamos Cliqer Remote en Flutter, lo medimos en un móvil real y lo reconstruimos en nativo sobre un único núcleo en Rust: la mitad de batería, sin calor. Cifras y lecciones.

Cliqer Team

5 de octubre de 2026 · 18 min de lectura

A presenter holds a phone remote: one half seen through a thermal camera glowing hot, the other half cool in mint stage light

El 26 de septiembre empezamos a desarrollar Cliqer Remote, nuestra app móvil para presentadores, en Flutter. Cinco días después ya estaba en TestFlight y en el canal interno de Google Play, con todas las funciones de la versión web para presentadores: el control remoto para presentaciones, la pantalla en directo, la tinta, el chat, las notas y las llamadas. Funcionaba. Luego la medimos en móviles reales, vimos cómo uno de ellos alcanzaba una temperatura superficial de 42 °C solo con mostrar una pantalla compartida, y la tiramos.

Nadie fuera de nuestro equipo llegó a ver esa app. Lo que tienes en su lugar es una app nativa en cada plataforma: SwiftUI en iPhone, iPad y Apple Watch, Kotlin y Jetpack Compose en Android y Wear OS, y un único motor por debajo, escrito una sola vez en Rust. Esta es la historia de por qué, con las cifras que medimos por el camino.

Puntos clave
  • Un control remoto para presentaciones tiene un trabajo extraño para una app móvil: pasar una hora en una mano caliente, mostrar vídeo en directo de la pantalla y no perder nunca un toque. El tiempo de fotograma, el calor y el tamaño importan más que en la mayoría de las apps.
  • Nuestra versión en Flutter fue rápida de escribir y bonita de ver, pero sus efectos de cristal y su ruta de vídeo le costaban trabajo a la GPU en cada fotograma. En un Galaxy S24+ redujimos una pantalla de 19,8 ms a 5,7 ms de trabajo de GPU por fotograma, y aun así seguíamos peleándonos con el motor en lugar de construir el producto.
  • Después pusimos tres versiones en el mismo móvil, en la misma sala, mirando la misma pantalla en movimiento durante diez minutos cada una. La primera versión en Flutter dibujaba 47,6 fotogramas por segundo, calentó el móvil 5,9 °C y consumió 168 mAh. La app nativa no dibujó ningún fotograma de interfaz, lo calentó 0,2 °C y consumió 86 mAh: la mitad de batería.
  • Las apps nativas son más pequeñas: 10,8 MB la app de iPhone con su app de Apple Watch incluida (la de Flutter ocupaba 27,6 MB) y una descarga de 5,8 MB en Android (Flutter: 15,6 MB), medidas de la misma forma.
  • En el mismo impulso hicimos que la app de escritorio convierta un clic en un cambio de diapositiva diez veces más rápido: 48 ms en PowerPoint y 42 ms en Keynote en un Mac, donde antes tardaba alrededor de medio segundo.

Un control remoto es una app extraña de construir

La mayoría de las apps se usan en ráfagas cortas. Un control remoto para presentaciones no. Pasa toda una charla en una mano, a menudo bajo los focos del escenario, con la pantalla encendida y la radio ocupada todo el tiempo. En Cliqer también muestra una imagen en directo de la pantalla del presentador, dibuja tinta sobre las diapositivas, gestiona el chat y las notas, y puede poner al presentador en cámara cuando el anfitrión lo invita.

Esa descripción del trabajo impone tres reglas:

  1. Cada toque debe llegar, ya. Un clic que llega tarde es un ponente plantado en silencio delante del público.
  2. El móvil debe mantenerse frío. Un móvil caliente se autolimita, y un móvil limitado pierde fotogramas, decodifica el vídeo tarde y agota la batería más rápido. Además, es desagradable sostenerlo durante una hora.
  3. La app debe ser pequeña y arrancar rápido. La gente la instala en el recinto, a menudo con el wifi del congreso, minutos antes de salir al escenario.

Flutter puede cumplir las tres en la mayoría de las apps. La nuestra resultó ser el tipo de app en la que cuesta más de lo que aporta.

Lo que Flutter hizo bien

Hay que reconocerlo. Flutter nos llevó de una carpeta vacía a una app completa en ambas tiendas en cinco días, con una sola base de código, hot reload, un sistema de pruebas excelente y una interfaz que se veía igual en todas partes. Le escribimos 266 tests. Si estás creando una app de formularios y listas, un panel de control o una tienda, te lo seguiríamos recomendando sin dudarlo.

También aprendimos mucho de él. Casi todos los hallazgos de este artículo salieron de trazar esa versión en Flutter en un móvil real, y algunas de las correcciones viven ahora en todos los clientes de Cliqer, incluido el web.

Dónde dolió: el cristal cuesta una pantalla entera por fotograma

El aspecto de Cliqer es cristal esmerilado: paneles translúcidos que difuminan lo que hay detrás. En iPhone y iPad salía barato. En nuestro móvil Android de pruebas, un Galaxy S24+ con pantalla de 120 Hz, no. A 120 Hz, un fotograma dispone de 8,3 ms para dibujarse, entero.

Trazamos la GPU en el dispositivo y encontramos la causa en cómo el motor de renderizado lee el fondo: cada panel de cristal copiaba la pantalla entera, en cada fotograma, con multimuestreo encima. La pantalla de acceso tenía nueve paneles de cristal, así que nueve copias de pantalla completa por fotograma. La GPU de ese móvil es un diseño de clase escritorio que no renderiza por teselas: no tiene una forma barata de volver a leer lo que acaba de dibujar, y cada nuevo tamaño de textura implicaba una nueva reserva de memoria que el kernel pone a cero primero. En una traza, el 71 % del tiempo del hilo de rasterizado se fue en reservar memoria gráfica.

Lo arreglamos, pantalla a pantalla. Pasamos a una versión preliminar del motor para que un desenfoque pudiera limitarse a su panel (de 41 ms a 17 ms). Agrupamos los nueve paneles de la pantalla de acceso en una única lectura compartida (de 19,8 ms a 5,7 ms). Dejamos de animar el tamaño de cualquier superficie de cristal, porque cada nuevo tamaño era una nueva reserva, y simulamos las animaciones con capas de tamaño fijo. El peor fotograma del escáner QR pasó de 285 ms a 18 ms.

Cada una de esas correcciones era un parche para el motor, no una función para un presentador. Y con el cristal suponiendo entre el 80 y el 90 % del tiempo de GPU en una sala, siempre estábamos a un panel nuevo de volver a perder fotogramas.

Dónde dolió de verdad: el vídeo y el calor que genera

La pantalla compartida es lo más pesado que muestra la app. En la versión en Flutter, cada fotograma de vídeo decodificado se entregaba a la interfaz como una textura, lo que significaba que la interfaz se redibujaba por cada fotograma de vídeo: la sala, el cristal, los controles, todo, 45 veces por segundo, solo para mover los píxeles dentro de un rectángulo.

Lo medimos por primera vez en el Galaxy con trazas del sistema el 1 de octubre. Mientras se reproducía el vídeo, la GPU rondaba los 440 MHz. Cuando cambiaba una diapositiva, los fotogramas tardaban entre 25 y 33 ms y la GPU tocaba su techo de 800 MHz durante más de la mitad de la transición. El móvil estaba en el estado térmico «moderado» del sistema, con una temperatura superficial de 42 °C, y limitaba su propia GPU para aguantar. El calor también hacía mentir a nuestras mediciones: un móvil caliente daba resultados un 20 % más lentos que uno frío, así que cada comparación tenía que alternar versiones a la misma temperatura.

Entonces probamos el experimento obvio: poner el vídeo en una capa nativa que compone el propio sistema operativo, fuera de la interfaz. Mismo móvil, misma app, misma sala: la interfaz dejó de redibujarse por el vídeo, la frecuencia de la GPU bajó de 440 a 121 MHz y el fotograma del cambio de diapositiva pasó de entre 25 y 33 ms a entre 3 y 7 ms. Publicamos esa corrección dentro de la app de Flutter el 1 de octubre. También nos mostró dónde estaba la respuesta de verdad: en una app nativa, el vídeo siempre vive en una capa del sistema, en iPhone y en Android, así que toda esta clase de problemas desaparece por diseño y no a base de parches.

Mismo móvil, misma sala, diez minutos

Las afirmaciones sobre el calor salen baratas, así que lo medimos. El 5 de octubre pusimos tres versiones en el mismo Galaxy S24+, una tras otra, diez minutos cada una, desenchufado, en la misma sala, mirando la misma pantalla compartida en movimiento. Antes de cada prueba, el móvil se volvía a enfriar.

  1. Flutter, primera versión: la app tal como la construimos al principio, con el vídeo dibujado por la interfaz.
  2. Flutter, optimizada: la misma app tras las correcciones de cristal y vídeo descritas arriba.
  3. Nativa: el nuevo Cliqer Remote.

La primera versión en Flutter redibujaba toda su interfaz 47,6 veces por segundo solo para mostrar un vídeo, mantenía la GPU a una media de 366 MHz y usaba 1,47 segundos de CPU por cada segundo. La app nativa no dibujó ni un solo fotograma de interfaz en diez minutos: solo se movía la capa de vídeo. Su GPU promedió 129 MHz, su CPU 0,69 segundos por segundo, y consumió 86 mAh de batería frente a 168 mAh. Es la mitad de batería para el mismo trabajo.

Y el calor. En diez minutos, la primera versión en Flutter llevó la batería de 36,2 °C a 42,1 °C, y el móvil empezó a limitarse a sí mismo. La versión de Flutter optimizada subió 1,9 °C. La app nativa subió 0,2 °C. Una charla dura más de diez minutos, y esa diferencia es la que notas en la mano.

Para ser justos con la versión de Flutter optimizada: se quedó cerca. Nuestras propias correcciones dentro de Flutter eliminaron la mayor parte del coste, y la nativa la superó por un margen menor: un 12 % menos de CPU y un 25 % menos de batería. La clave es de dónde parte cada una. La primera versión era lo que da de serie una buena app de Flutter; la nativa consigue el resultado frío sin parches.

Cómo lo medimos, para que puedas repetirlo: trazas de Perfetto en el dispositivo (línea temporal de fotogramas, frecuencia de la GPU, contadores de batería), tiempo de CPU del proceso según el kernel y la propia temperatura de la batería del móvil, con la misma animación a 60 fps en la pantalla compartida en todas las pruebas. Un móvil y una prueba por versión, así que toma las cifras como una prueba de campo cuidadosa, no como un benchmark de laboratorio. Además, la prueba nativa empezó unos 2 °C más fría, por eso comparamos el aumento.

Lo que construimos en su lugar

El nuevo Cliqer Remote es nativo en todas las plataformas y se apoya en un único motor compartido.

La interfaz es nativa en cada plataforma. En iPhone y iPad es SwiftUI con el propio Liquid Glass del sistema. En Android es Jetpack Compose, con desenfoque de fondo real allí donde la plataforma lo permite. Las apps de Apple Watch y Wear OS también son nativas, lo bastante ligeras para llevar Siguiente y Atrás en la muñeca.

El motor se escribe una sola vez, en Rust. Entrar en una sala, reconectar y reanudar tras un cambio de red, recibir el vídeo de la pantalla, enviar clics, láser y tinta, el chat, las notas, el temporizador, las llamadas y el emparejamiento de un móvil con un ordenador viven en una única biblioteca de Rust que comparten ambas apps. Cada app solo dibuja la interfaz, decodifica el vídeo con el decodificador por hardware del sistema y se comunica con la cámara y el micrófono. Una corrección del protocolo se hace una vez y llega a ambas plataformas, y las dos apps no pueden distanciarse.

Rust fue la elección natural para ese motor: sin recolector de basura que pause un fotograma, seguridad de memoria sin runtime, y compila a una única biblioteca pequeña para iOS y Android. Es rápido donde importa. En un Mac, nuestro motor empaqueta un fotograma H.264 de 20 KB en 31 µs, completa un handshake seguro en 198 µs por lado y, en nuestras pruebas, entrega un fotograma de vídeo de 100 KB a la interfaz de Android en 46 µs (tardaba 440 µs antes de que optimizáramos esa frontera). A través de un relé, un viaje de ida y vuelta tuvo una mediana de 13 a 16 ms en nuestras pruebas.

Y además más pequeña

Medimos ambas versiones de la misma forma. La app de iPhone, tal como se sube a Apple, pasó de 27,6 MB a 10,8 MB, y eso incluyendo la app de Apple Watch (1,5 MB). La descarga para un móvil Android, medida con la propia herramienta de bundles de Google para el mismo móvil de 64 bits, pasó de 15,6 MB a 5,8 MB. Ocupar más o menos un tercio del tamaño anterior importa cuando alguien instala la app con el wifi del recinto a cinco minutos de empezar.

La caza de milisegundos no se detuvo en el móvil

Una app móvil más rápida es solo la mitad de un clic. La otra mitad es el ordenador que ejecuta la presentación, y mientras reconstruíamos las apps también fuimos a por ese lado.

Clics: de medio segundo a una décima

Cuando un clic llega a la app de escritorio de Cliqer, tiene que avanzar la presentación y después decir a todos en la sala qué diapositiva se está mostrando. Esa segunda parte consistía en preguntar a la app de presentaciones su número de diapositiva tras cada clic, y esa pregunta era lenta.

Cliqer 2.3 mantiene abierta una conexión con PowerPoint o Keynote y lee la posición directamente del paso que acaba de dar. En un Mac, en 20 pruebas, la mediana del clic a la diapositiva bajó de 509 ms a 48 ms en PowerPoint y de 408 ms a 42 ms en Keynote. Diez pulsaciones rápidas, las que hace un presentador para saltarse una sección, tardaban antes 5,3 segundos en estabilizarse. Ahora se fusionan en un único movimiento y llegan en 254 ms.

Vídeo que no se queda atrás con un wifi malo

A principios de este año descubrimos por qué una pantalla compartida podía congelarse durante segundos en wifi. El vídeo de pantalla en Cliqer viaja por un canal de datos fiable, y el estándar sobre el que se construye ese canal espera al menos un segundo entero antes de reenviar un paquete perdido, y duplica la espera en cada repetición. Chrome usa 400 ms. Cada fotograma detrás del perdido esperaba en la cola, luego el anfitrión forzaba un refresco completo en esa misma cola y, con un enlace lento, lo hacía una y otra vez.

Ajustamos los temporizadores de reenvío a los valores de Chrome e impedimos que los refrescos se encolaran detrás del atasco. En una simulación de red con un modelo de pérdidas de wifi, una compartición en 1080p pasó de entre 15 y 22 congelamientos de un segundo o más cada dos minutos a entre 0 y 2, y el retraso mediano respecto al directo pasó de hasta 2,3 segundos a 12 ms. También limitamos los refrescos completos a uno por flujo cada medio segundo, porque cada uno de ellos va a todos los espectadores: antes de ese límite, un espectador podía recibir 19 refrescos completos por segundo, unos 40 Mbit/s.

En el lado del móvil, el decodificador de vídeo por hardware del Galaxy retenía un fotograma normal durante unos 60 ms, aproximadamente una vez por segundo. Pedir al decodificador que funcionara a máxima velocidad lo dejó en cero fotogramas tardíos en 50 segundos. Esa corrección viene incluida en la app nativa de Android.

Lo que le diríamos a otro equipo

Si desarrollas algo en tiempo real para móviles, aprender esto nos costó días y aplicarlo lleva minutos:

  1. Mide en tu peor dispositivo real, no en el emulador. Nuestro emulador funcionaba a 60 Hz con otro backend gráfico y no podía mostrar ni uno solo de los problemas del cristal.
  2. Alterna versiones a la misma temperatura. Un móvil caliente daba resultados un 20 % más lentos. Comparar una prueba en frío con una en caliente te engañará.
  3. Cuenta tus lecturas de desenfoque. Cada desenfoque de fondo puede costar una copia de pantalla completa por fotograma. Agrúpalos, acótalos y nunca animes el tamaño de una superficie desenfocada.
  4. Nunca redibujes tu interfaz por el vídeo. Pon el vídeo en una capa que componga el sistema. Fue la mayor mejora individual de GPU, batería y calor que medimos.
  5. Pide al decodificador por hardware velocidad de tiempo real. En Android, configura la tasa de operación (operating rate) del decodificador. Una sola línea eliminó un parón de 60 ms cada segundo.
  6. Revisa los temporizadores de tu transporte. Los canales de datos fiables heredan temporizadores de reenvío de estándares más antiguos. Un mínimo de un segundo es una eternidad para el vídeo en directo.
  7. Trata los refrescos completos como los fotogramas caros que son. Limítalos por flujo, porque cada uno va a todos los espectadores.
  8. Fusiona las ráfagas de entrada. Diez pulsaciones deberían ser un movimiento de diez, no diez viajes de ida y vuelta.
  9. Lee lo que tus herramientas escriben en tu build. Una toolchain preliminar activó un flag de renderizado en nuestro manifiesto de Android sin preguntar.

Qué significa esto para ti

10x

más rápido del clic a la diapositiva en PowerPoint y Keynote en un Mac

5.8 MB

de descarga en Android, más o menos un tercio del tamaño anterior

10.8 MB

la app de iPhone con su app de Apple Watch incluida

Half

de la batería de nuestra primera versión en Flutter, mismo móvil, mismos 10 minutos

Cliqer Remote es nativo en iPhone, iPad, Android, Apple Watch y Wear OS. Los clics son más rápidos, el móvil se mantiene frío y consume la mitad de batería que nuestra primera versión, el vídeo se dibuja como el móvil está diseñado para dibujarlo y la app ocupa más o menos un tercio de su tamaño anterior. La versión web para presentadores sigue funcionando en cualquier navegador sin instalar nada, así que nadie en tu sala se queda nunca fuera.

Descarga las apps

Cliqer Remote para iPhone, iPad, Android y tu reloj.

Latencia del control remoto para presentaciones: por qué importan los milisegundos

Lo que pasa realmente entre un toque y el cambio de diapositiva.

Cómo hicimos que compartir pantalla fuera cuatro veces más rápido

La otra gran historia de rendimiento de este año.

Por qué sacamos nuestro tiempo real de Cloudflare

La misma búsqueda de estabilidad, en el lado del servidor.

Preguntas frecuentes

flutterrustnative appsswiftuijetpack composeperformancelatencyengineering

Escrito por Cliqer Team

Creamos Cliqer, el control remoto por Internet que se usa en escenarios, aulas y salas de reuniones de todo el mundo.

Dirige tu próximo show con Cliqer

Cualquier presentación, cualquier teléfono, en cualquier lugar. La app de escritorio aloja la sala, los presentadores solo abren un enlace.

Sigue leyendo

Más novedades del producto para tu próximo show

A laptop running Cliqer Studio and a phone running Cliqer Remote on a backstage tech table, the stage projection wall glowing behind them
Novedades del producto

Por qué Cliqer 3 es nativo: lo que intentó la versión 2 y por qué gana un motor nativo

Por qué Cliqer 3 es nativo: un motor en Rust, vídeo por hardware, salidas de pantalla reales y NDI en lugar de una app web dentro de un contenedor de escritorio.
A dedicated server rack glowing mint in a dark data hall
Novedades del producto

Por qué sacamos el tiempo real de Cliqer de Cloudflare (y por qué seguimos siendo fans)

Cuatro meses en el edge de Cloudflare: qué falló, qué construimos para sobrellevarlo y por qué Cliqer funciona ahora en nuestros propios servidores dedicados.
A software engineer reviewing a video latency graph on a monitor in a dimly lit office
Novedades del producto

Cómo hicimos que compartir pantalla fuera cuatro veces más rápido

La historia de ingeniería detrás de la reducción de la latencia al compartir pantalla en Cliqer, de más de dos segundos a aproximadamente medio segundo.
Newsletter

Recibe la próxima guía antes de tu próximo show

Guías prácticas para presentadores, equipos de AV y equipos de eventos, más las versiones de Cliqer que importan. Sin spam, te das de baja con un clic.