DEV Community

Cover image for Você sabe como funcionam os super apps chineses? Um estudo com Flutter
Rodrigo Castro
Rodrigo Castro

Posted on

Você sabe como funcionam os super apps chineses? Um estudo com Flutter

Você já deve ter ouvido que "o WeChat é seu WhatsApp, seu banco e seu Uber, tudo no mesmo app". Essa comparação vende bem a ideia pra quem nunca usou um super app chinês, mas é só a superfície. Por trás dela existe uma decisão de arquitetura de software bem específica, que a maioria dos artigos sobre "super apps em Flutter" nunca chega a explicar: como um único aplicativo consegue rodar dezenas de milhares de serviços de terceiros sem que cada atualização passe pela App Store?

Neste artigo eu saio do discurso de produto e vou direto pra arquitetura: como o WeChat, o Alipay e o Douyin resolvem isso tecnicamente, por que essa solução não é replicável com Flutter puro, e o que dá pra construir de fato quando o objetivo é ter vários serviços dentro do mesmo app.

Sumário

  1. O que é, tecnicamente, um super app
  2. Por que não existe "Flutter dinâmico" dentro de um super app
  3. A arquitetura real: shell nativo, engine e JSBridge
  4. O que dá (e o que não dá) pra fazer com Flutter
  5. O que já existe pronto (e em produção) no ecossistema Flutter
  6. Quatro caminhos 100% Flutter pra mini-apps dinâmicos
  7. Conclusão

O que é, tecnicamente, um super app

Um super app não é só "um app grande com muitas telas". É uma plataforma com três camadas bem definidas:

  1. Host / shell: o app que o usuário baixa da loja. Cuida de autenticação, pagamentos, permissões de sistema (câmera, localização) e a navegação de topo.
  2. Runtime de mini-programs: um motor embarcado dentro do shell, capaz de executar código de terceiros de forma isolada e segura.
  3. Mini-programs: os "apps dentro do app", desenvolvidos por times internos ou parceiros externos, publicados e atualizados sem passar pela App Store ou pela Play Store.

Diagrama das três camadas de um super app: host/shell, runtime de mini-programs e os mini-programs individuais

A peça que faz tudo funcionar é o runtime, e é exatamente aí que mora a pegadinha.


Por que não existe "Flutter dinâmico" dentro de um super app

A primeira pergunta que todo dev Flutter faz é: dá pra empacotar cada mini-app como um módulo Dart e carregar isso dinamicamente, tipo dynamic feature modules do Android?

Não, e o motivo não é técnico, é de política de loja. A Guideline 2.5.2 da Apple determina que um app precisa ser autocontido e não pode baixar, instalar ou executar código que introduza ou altere funcionalidades depois da revisão. Historicamente, a única brecha aceita era pra scripts interpretados rodando dentro do WebKit ou do JavaScriptCore embutidos no próprio iOS, desde que não mudassem o propósito principal do app declarado na loja. Um binário Dart compilado em AOT não se encaixa nessa brecha porque é código nativo, não interpretado por uma engine do sistema. Vale registrar que essa é uma área juridicamente sensível: a Apple já entrou em atrito público com a categoria de mini-programs mais de uma vez, e a fiscalização sobre esse tipo de download de código só ficou mais rígida nos últimos anos.

É por isso que nenhum super app chinês executa Flutter, React Native ou qualquer framework compilado nativamente dentro dos seus mini-programs. Cada gigante resolveu isso com sua própria engine de script embarcada:

  • WeChat (framework MINA): separa a aplicação em duas threads. A camada de renderização (WXML/WXSS) roda dentro de uma WebView, enquanto a camada lógica (o JS do desenvolvedor) fica isolada numa thread JSCore, um motor JS puro, sem acesso a DOM ou window. Essa separação existe por segurança, já que o código de terceiros nunca toca a UI diretamente, e por performance, porque a UI não trava esperando o JS de negócio processar.
  • Alipay (framework APPX + V8 Worker): foi além. Cada mini-program roda seu próprio script de renderização (index.js, executado em WebView) e seu próprio script de lógica de negócio (index.worker.js, executado como Worker sobre uma engine V8 dedicada). Essa arquitetura permite inicializar a WebView e a engine V8 em paralelo, isola o JS do framework do JS do desenvolvedor em contextos V8 separados, e ainda expõe uma JSAPI pra plugins nativos se conectarem ao contexto de execução.
  • Já o Douyin usa a mesma arquitetura de base do WeChat: a documentação oficial da plataforma de mini-programs do Douyin descreve o framework como dividido em camada lógica (JS Core) e camada de renderização (WebView), com uma linguagem de marcação própria (TTML/TTSS) equivalente ao WXML/WXSS do WeChat. Vale um adendo importante aqui: a ByteDance também abriu o código de um framework chamado Lynx, com uma arquitetura de duas threads mais sofisticada (motor JS PrimJS, camada declarativa ReactLynx, bundler Rspeedy em Rust), e a própria empresa o posiciona como concorrente direto do React Native e do Flutter. Mas o Lynx resolve outro problema: ele é usado pra construir os próprios apps nativos da ByteDance (o TikTok e o Douyin em si), não é o runtime que executa os mini-programs de terceiros dentro do Douyin.

O padrão que aparece nesses três casos é o mesmo: renderização e lógica de negócio rodam em threads ou contextos separados, e o código do mini-program é sempre interpretado em runtime por uma engine embarcada no shell. Nunca compilado nativamente e instalado como um binário à parte. Vale notar que Douyin e WeChat convergem quase pro mesmo modelo (JS Core + WebView), enquanto o Alipay foi o que mais se diferenciou tecnicamente, com a arquitetura V8 Worker rodando em paralelo.

Vale um adendo: desde 2019 existe um grupo de trabalho do W3C, o MiniApps Working Group, com Alibaba, Baidu, Huawei e Xiaomi entre os participantes, tentando padronizar esse ecossistema fragmentado, definindo um formato comum de empacotamento, manifest e ciclo de vida pra mini-apps. Ainda não existe interoperabilidade real entre WeChat, Alipay e Douyin, mas isso já mostra que o problema é reconhecido como grande demais pra cada vendor resolver sozinho.


A arquitetura real: shell nativo, engine e JSBridge

Descrevendo em camadas, um super app chinês típico se parece com isto:

Diagrama mostrando o app shell com a engine de script, o bridge de comunicação e o mini-program bundle

O componente crítico é o JSBridge: uma camada de comunicação bidirecional entre o código JS do mini-program e o código nativo do shell. Quando um mini-program precisa abrir a câmera, ele não acessa o hardware diretamente. Ele chama uma função exposta pelo bridge, que delega pro código nativo, executa a operação e retorna o resultado de forma assíncrona, geralmente via postMessage ou um canal equivalente ao JavascriptChannel do webview_flutter.

Isso resolve dois problemas de uma vez:

  • Segurança: o mini-program nunca tem acesso irrestrito ao sistema, só ao que o bridge decide expor.
  • Atualização independente: como o mini-program é só um bundle JS/HTML baixado de um CDN, ele pode ser atualizado a qualquer momento sem passar por revisão de loja. É isso que permite ter dezenas de milhares deles rodando ao mesmo tempo.

O que dá (e o que não dá) pra fazer com Flutter

Aqui está a distinção mais importante do artigo, e que normalmente fica confusa: existem dois problemas diferentes escondidos atrás do termo "super app", e Flutter resolve muito bem um deles.

Problema 1: "quero um app só com muitos serviços internos, desenvolvidos e publicados pelo meu próprio time."

Isso é um monólito modular, e o Flutter é excelente nisso. Cada serviço vira um pacote Dart independente, organizado num monorepo com Melos, um formato de estrutura que já é padrão de mercado:

meu_super_app/
├── apps/
│   └── shell/              # app host
├── packages/
│   ├── core/               # DI, network, storage
│   ├── design_system/      # UI compartilhada
│   ├── carteira/
│   ├── chat/
│   └── perfil/
└── melos.yaml
Enter fullscreen mode Exit fullscreen mode
  • Um contrato comum (abstract class Module { routes(); dependencies(); initialize(); }) define como cada módulo se registra no shell.
  • O roteamento é federado com GoRouter: cada módulo expõe suas próprias rotas, o shell as agrega numa GoRouter raiz, normalmente usando ShellRoute pra manter uma navegação comum.
  • A comunicação entre módulos nunca acontece por import direto, só por contratos definidos num pacote shared, navegação por rota nomeada e um event bus (Stream ou um Bloc global de eventos) pra avisos assíncronos entre módulos que não se conhecem.
  • Cada módulo mantém seu próprio escopo de estado (Bloc, Cubit ou Riverpod), evitando vazamento de estado global.

O resultado: você ganha modularização, times trabalhando em paralelo, testes isolados por pacote. Mas tudo ainda é compilado e publicado como um único binário, numa única versão, numa única submissão de loja.

Problema 2: "quero permitir que terceiros publiquem serviços dentro do meu app, atualizáveis sem passar pela loja."

Esse é o problema que o WeChat resolve, e o Flutter não resolve nativamente. Pra chegar perto disso você precisaria de:

  • Um shell Flutter (ou nativo) hospedando um WebView ou uma engine JS embarcada, algo como o flutter_js, que embute o QuickJS.
  • Mini-apps como bundles de HTML, CSS e JS baixados de um servidor próprio.
  • Um JSBridge implementado via JavascriptChannel do webview_flutter, expondo as APIs nativas que os mini-apps podem chamar.
  • Um sistema de catálogo controlando quais mini-apps existem, suas versões e permissões.

Nesse ponto a camada de UI dos seus mini-apps deixa de ser Flutter. Vira HTML e JS rodando dentro de uma WebView. Você está construindo, na prática, seu próprio mini runtime de mini-programs, não um app Flutter modular.


O que já existe pronto (e em produção) no ecossistema Flutter

Antes de fechar, vale mostrar que parte desse problema já tem solução real no mundo Flutter, só que resolvendo pedaços diferentes dele.

  • FlutterBoost, da Alibaba: é a peça que sustenta o "AliFlutter", a estratégia da própria Alibaba pra rodar Flutter em escala dentro do ecossistema de apps do grupo, incluindo o Xianyu (Idle Fish), um dos maiores apps Flutter em produção do mundo. A maioria dos apps da Alibaba usa uma pilha híbrida nativa mais Flutter, e o FlutterBoost existe justamente pra fazer telas nativas e telas Flutter conviverem no mesmo app, com uma única API de roteamento unificada e um canal de eventos (o BoostChannel) pra comunicação entre os dois lados. É o padrão mais próximo de "super app real em produção usando Flutter" que existe documentado, mas repare que ainda é modularização de containers dentro de um único binário, não mini-programs de terceiros publicados independentemente.
  • Shorebird: esse é o mais interessante pro debate da regra 2.5.2. Ele criou um mecanismo de code push pra Flutter, embarcando um Flutter engine modificado que roda o código Dart através da Dart VM de forma interpretada, permitindo enviar patches de código pro app em produção sem passar pela revisão da loja. Funciona porque, tecnicamente, o app "release" enviado pra loja já contém a engine capaz de interpretar bytecode Dart. O patch não instala um executável novo, só atualiza o que a VM interpreta, caindo na mesma exceção histórica que permite JS interpretado. É a prova de que essa exceção da Apple não é exclusiva de JavaScript. Mas hoje o Shorebird resolve "meu time quer atualizar meu próprio app sem esperar a loja", não "quero permitir que terceiros publiquem mini-apps dentro do meu app". São problemas parecidos na superfície, mas com modelos de confiança bem diferentes: um mexe no seu próprio código, o outro precisa de sandboxing de código de terceiros.

Juntando os dois: hoje, com ferramentas maduras do próprio ecossistema Flutter, já dá pra montar um monólito modular com atualização mais rápida que o ciclo normal de loja. Isso cobre muito bem o primeiro problema. O segundo, mini-programs de terceiros de verdade, continua exigindo uma camada de engine de script separada, como fazem WeChat, Alipay e Douyin.


Quatro caminhos 100% Flutter pra mini-apps dinâmicos, e o trade-off de cada um

Se o objetivo é ter mini-apps atualizáveis sem passar pela loja, mas sem sair do ecossistema Flutter, existem quatro caminhos reais.

Abordagem Como funciona Segurança jurídica (Apple) Performance/peso Consistência visual Maturidade
Pacotes Dart (monólito modular) Módulos compilados junto no binário, via monorepo e Melos Nenhum risco, é código nativo revisado normalmente Nativa, sem overhead Perfeita, é tudo Flutter nativo Alta, padrão de mercado
UI dirigida por dados (SDUI / GenUI SDK) Servidor envia um JSON descrevendo a tela, montado sobre um catálogo de widgets já compilados no app Nenhum risco, não há código sendo baixado, só dados (mesma categoria de remote config) Leve, só trafega JSON Perfeita, mas limitada ao catálogo de widgets já existente no app Padrão testado há anos fora do Flutter (Airbnb, Spotify); dentro do Flutter, oficializado pelo Google via GenUI SDK, ainda em alpha
Interpretador Dart (dart_eval/flutter_eval) Bytecode Dart baixado e interpretado dentro do próprio app, renderizando widgets reais Zona cinzenta, os próprios mantenedores admitem incerteza e se apoiam no precedente do Hermes (React Native) De 10 a 50 vezes mais lento que Dart AOT, comparável a Ruby, só no código interpretado Perfeita, widgets Flutter reais Baixa/média, projeto jovem, cobertura parcial da linguagem
Flutter Web dentro de WebView Mini-app compilado pra Flutter Web (CanvasKit/Wasm), carregado via webview_flutter mais JSBridge Sólida, é exatamente a exceção nomeada na Guideline 2.5.2 pra conteúdo web em WebView Pesada, CanvasKit adiciona de 1.5 a 2MB de Wasm antes do primeiro pixel Alta, mas com as costuras clássicas de WebView (scroll, teclado, gestos) Alta, usa infraestrutura web madura, mas incomum nesse uso específico

O padrão que aparece na tabela não é uma linha reta simples entre "seguro e pesado" e "leve e arriscado". A UI dirigida por dados quebra essa lógica: ela é ao mesmo tempo a mais segura juridicamente e a mais leve tecnicamente, só que paga o preço em liberdade de expressão, não em performance ou compliance. Um mini-app SDUI não pode ter lógica de negócio própria nem widgets que o host não conhece de antemão. É ótimo pra telas guiadas, formulários, catálogos, checkouts simples, mas não serve pra um mini-program livre e arbitrário como os do WeChat.

Pra um MVP ou uma POC de portfólio, isso muda a decisão. Pacotes Dart continuam sendo o caminho certo pro primeiro problema, o de modularização interna. Se a ideia é demonstrar o segundo problema, o de mini-apps de terceiros, de forma defensável e com esforço razoável, a UI dirigida por dados é provavelmente o ângulo mais interessante pra mostrar hoje: é recente (o GenUI SDK do Google é literalmente de 2026), resolve o problema de compliance de forma elegante, e ainda dá gancho pra falar de IA generativa compondo UI, que é assunto quente. Flutter Web em WebView continua sendo a opção mais robusta quando o mini-app precisa de liberdade total de lógica.


Conclusão

"Super app" virou clichê de pitch de startup, mas por trás dele existem arquiteturas radicalmente diferentes. Se o objetivo é organizar um app grande com múltiplos serviços internos, o caminho é modularização séria: pacotes Dart, contratos, roteamento federado, event bus. Isso é 100% Flutter, sem gambiarra.

Se o objetivo é replicar o modelo chinês de verdade, com um ecossistema de mini-programs de terceiros atualizáveis sem loja, você está resolvendo um problema de plataforma: engine de script embarcada, bridge nativo, sandboxing. E o Flutter vira só a camada do shell, não a camada onde os serviços rodam.

Entender essa diferença antes de começar a arquitetar evita meses de decisões erradas. É esse tipo de clareza que separa uma implementação de portfólio de uma implementação de produção.


Este artigo é parte de um estudo prático que venho construindo em Flutter, explorando na prática os limites entre modularização de monólito e arquitetura real de mini-app.

Fontes técnicas: documentação oficial do WeChat Mini Program, documentação oficial da plataforma de mini-programs do Douyin, artigo da Alibaba Cloud sobre o V8 Worker do Alipay, repositório oficial do FlutterBoost no GitHub, site oficial do Lynx, MiniApps Working Group do W3C, documentação do Shorebird sobre code push em Flutter e documentação oficial do GenUI SDK for Flutter.

Top comments (0)