Aplicações Android com seed
Este guia descreve como usar a plataforma e o framework Android atuais de
seed. O suporte implementado combina uma biblioteca seed (mobile), um host
Android baseado em Gradle/Kotlin/CMake e um bridge JNI que carrega a biblioteca
nativa seed.
Estado atual: Android é a plataforma móvel ativa. O framework fornece uma superfície Canvas retida por comandos de frame, entrada básica, ciclo de vida, insets, métricas de tela e empacotamento multi-ABI. Ainda não é um toolkit completo de widgets.
O que é suportado
android-arm64como ABI móvel executada;android-x86_64permanece apenas como alvo de compilação/link compatível;- Android API 37, command-line tools 22.0, build-tools 37.0.0, Gradle 9.5.0,
AGP 9.3.0 e NDK
27.2.12479018como baseline; - bibliotecas seed compartilhadas/estáticas carregadas por um host Android;
- entrada única
seed_mobile_entrye hooks de ciclo de vida; - frames com cor de fundo, até 256 retângulos, 32 textos e 128 nós semânticos;
- toque, teclas e
InputConnection.commitTextatravés de fila limitada; - insets da janela, foco, pressão de memória, densidade e diretórios privados;
- contexto opcional por geração da
Activitye saída PCM estéreo por OpenSL ES com pausa/retomada; - execução em AVD e instalação/lançamento via
adb; - assinatura de desenvolvimento/release e execução validada no slice físico declarado Motorola Android 15/API 35 ARM64.
Não são declarações de suporte atual: catálogo completo de widgets, TalkBack físico, seleção/composição completa de IME, text shaping, hot reload, matriz geral de dispositivos, publicação em loja ou prontidão de produção.
Arquitetura
seed app (.sd)
│ integrated build: .so + .a per ABI
▼
libseed_app.so ─► JNI bridge (preferred packaged dependency)
libseed_app.a ─► separate static artifact
│ C ABI
▼
JNI bridge + SeedSurfaceView
│
▼
Activity Android / Canvas / adb / Gradle
A aplicação seed não substitui ainda a Activity. O host Android continua
responsável por processo, janela, Canvas, JNI e integração com o SDK. A
biblioteca mobile fornece os imports portáveis do slice implementado e deve
ser usada apenas com um alvo Android.
Requisitos
É necessário ter:
- macOS Apple Silicon para a matriz ARM64 validada atualmente;
- JDK 17;
clangdo NDK,adb, Android CLI/sdkmanager,aapt2, Gradle e emulator;- um AVD
arm64-v8aou dispositivo Android ARM64 autorizado poradb.
O instalador oficial do projeto usa $HOME/Android/Sdk, não requer sudo e
instala o baseline completo:
./seed mobile android setup
./seed mobile android doctor
Opções úteis:
./seed mobile android setup --sdk "$HOME/Android/Sdk" --start
./seed mobile android setup --skip-avd
./seed mobile android setup --dry-run
Use --api, --abi, --image-flavor, --ndk, --avd e --device para personalizar a instalação.
--skip-gradle deixa a instalação do Gradle sob responsabilidade do usuário.
Para usar um NDK diferente do baseline, declare explicitamente
SEED_ANDROID_NDK_REVISION e confirme a compatibilidade com o projeto.
O diagnóstico deve mostrar Android 37.0, build-tools 37.0.0, Gradle 9.5.0,
platform-tools, NDK e os sysroots API 21 de aarch64-linux-android e
x86_64-linux-android:
./seed mobile android doctor
Tutorial 1: primeira aplicação
Crie app.sd:
fn main() -> i64 {
0
}
pub fn seed_mobile_entry() -> i64 {
0
}
Crie um host copiando o template versionado:
cp -R seed/compiler/llvm/mobile/android my-android
Compile as duas ABIs, faça o staging e gere o APK:
./seed mobile android build app.sd my-android \
--package-name seed_app \
--application-id com.example.seedapp \
--package
O comando produz libseed_app.so e libseed_app.a para arm64-v8a e
x86_64, copia os artefatos para my-android/app/src/main/jniLibs/, liga o
shared object seed como dependência empacotada do bridge JNI e executa
assembleDebug; o archive permanece disponível separadamente para
consumidores nativos. O arquivo
my-android/seed-android.properties registra o nome nativo e o application ID
usados pelos comandos seguintes.
Tutorial 2: desenhar uma tela
Importe a biblioteca Android mobile no código do aplicativo. Um exemplo
completo está em
compiler/llvm/tests/mobile/android_framework.sd.
O callback de frame recebe largura, altura e tempo em nanossegundos:
use "mobile"
pub fn seed_mobile_entry() -> i64 { 0 }
pub fn seed_mobile_on_frame(width: i32, height: i32, time_nanos: i64) {
mobile.frame_clear()
mobile.frame_color(4278190335 as i64) // ARGB: opaque blue
mobile.frame_rect(1000, 1000, 2000, 2000, 4294902015 as i64)
mobile.frame_text("Hello, Android", 1500, 4500, 2400, 4294967295 as i64)
}
Coordenadas e tamanho de fonte são milipixels. As cores são inteiros ARGB. O host limita cada frame a 256 retângulos, 32 itens de texto, 128 nós semânticos e 256 bytes UTF-8 por rótulo/item. O texto é desenhado pelo Canvas Android; escolha de fonte e shaping avançado ainda não fazem parte do contrato.
Tutorial 3: consumir toque, teclado e IME
A biblioteca mantém uma fila limitada de 128 eventos. Leia os campos antes de remover o evento:
use "mobile"
fn read_input() {
while mobile.input_available() {
let kind = mobile.input_kind()
let a = mobile.input_a()
let b = mobile.input_b()
let c = mobile.input_c()
// kind 1: touch; a=action, b=x in millipixels, c=y in millipixels.
// kind 2: key; a=action, b=Android key code, c=Unicode code point.
// kind 3: text committed by the IME.
if kind == 3 {
let length = mobile.input_text_length()
// input_text_byte(index) exposes the committed text's UTF-8 bytes.
let _ = length
}
mobile.input_pop()
}
}
input_pop deve ser chamado uma vez por evento. Se produtores ultrapassarem a
capacidade, a fila conserva os eventos mais recentes. Seleção e região de
composição ainda não são expostas.
Tutorial 4: ciclo de vida e recursos
Defina apenas os hooks necessários. Eles são executados na thread da
Activity e não devem bloquear, reter objetos JNI nem criar tarefas sem grupo
estruturado:
pub fn seed_mobile_on_create() {}
pub fn seed_mobile_on_start() {}
pub fn seed_mobile_on_resume() {}
pub fn seed_mobile_on_pause() {}
pub fn seed_mobile_on_stop() {}
pub fn seed_mobile_on_destroy() {}
seed_mobile_entry é protegido contra execução repetida no mesmo processo;
recriar a Activity não reinicializa a aplicação. Destruição cancela trabalho
pendente no bridge; morte do processo é a fronteira final de limpeza.
Aplicações com recursos persistentes entre frames podem exportar
seed_mobile_context_create, seed_mobile_context_on_event,
seed_mobile_context_on_frame e seed_mobile_context_destroy. O host mantém
no máximo um contexto por geração da Activity, deixa de encaminhar callbacks
quando essa geração é invalidada e destrói o contexto exatamente uma vez. Os
hooks legados continuam sendo o fallback.
Use mobile.window_focused() para pausar trabalho visual durante perda de
foco e mobile.memory_pressure() para liberar caches após onTrimMemory.
Não trate esses sinais como garantia de que o processo continuará vivo.
Tutorial 5: layout, safe area e armazenamento
Insets são pixels físicos: 0=left, 1=top, 2=right, 3=bottom.
use "mobile"
fn content_top() -> i64 {
mobile.window_inset(1)
}
fn text_size() -> i64 {
// scaled_density_milli is the font density multiplied by 1000.
16000 * mobile.scaled_density_milli() / 1000
}
mobile.density_dpi() e mobile.scaled_density_milli() permitem adaptar
layout e tipografia. mobile.app_files_* e mobile.app_cache_* retornam views
limitadas dos caminhos privados fornecidos pela Activity; use-os para
armazenamento interno e cache. Não há acesso automático a armazenamento
externo. A permissão de rede declarada pelo template cobre o slice atual de
net, mas permissões adicionais continuam sendo responsabilidade do host.
Fluxos de build
Build manual
seed --emit-shared libseed_app.so \
--target android-arm64 --runtime-profile android \
--sysroot "$ANDROID_NDK_SYSROOT" --soname libseed_app.so app.sd
seed --emit-shared libseed_app.so \
--target android-x86_64 --runtime-profile android \
--sysroot "$ANDROID_NDK_SYSROOT" --soname libseed_app.so app.sd
./seed mobile android stage my-android arm64.so x86_64.so \
seed_app com.example.seedapp
./seed mobile android package my-android
Build integrado
./seed mobile android build app.sd my-android \
--ndk "$ANDROID_NDK_HOME" \
--package-name seed_app \
--application-id com.example.seedapp
build procura o NDK em ANDROID_NDK_HOME quando --ndk não é informado e
gera pares shared/static para as duas ABIs; o host prefere o shared object
empacotado e conserva o archive como artefato separado. stage continua
aceitando bibliotecas ELF shared, valida os artefatos e rejeita application IDs
inválidos. O package name nativo não pode conter / ou ...
Se o pacote Seed que contém app.sd tiver uma pasta assets/, o build
integrado também copia seus arquivos regulares e planos para o host Android.
Nomes ficam limitados a letras e dígitos ASCII, ., _ e -; subpastas,
arquivos ocultos e colisões com o probe do host são rejeitados. Na
inicialização, o host lê o índice gerado seed-mobile-assets.list e extrai
exatamente esses arquivos — no máximo 256 e 64 MiB — para a raiz privada
somente-leitura já exposta ao Seed. Assets de framework/overlay que o
AssetManager também enumera não entram no pacote Seed. Assim, o mesmo
manifesto e os mesmos ativos de imagem, fonte, WAV e Ogg podem acompanhar
desktop e Android sem lógica de cópia específica do aplicativo.
Dependências diretas de audio-vorbis e grove-game-assets fazem o build
integrado incluir os backends stb correspondentes nas duas ABIs. O bridge JNI
fornece o contrato de áudio compartilhado sobre OpenSL ES, com streams
limitados, handles com geração, fila PCM 48 kHz estéreo, consulta de bytes
pendentes, pausa/retomada, limpeza e fechamento exato.
Debug, release e execução
./seed mobile android package my-android
./seed mobile android package my-android --release
./seed mobile android run my-android
./seed mobile android run my-android --release
./seed mobile android run my-android --serial emulator-5554
./seed mobile android doctor --serial ZF524P7D2T
run empacota, instala, força a parada da instância anterior e executa
.MainActivity via adb, exigindo Status: ok. ANDROID_SERIAL também pode
selecionar o dispositivo.
Para iniciar o AVD instalado pelo setup:
emulator -avd seed-api37 -no-snapshot
adb wait-for-device
./seed mobile android run my-android
O nome real do AVD pode ser consultado com avdmanager list avd.
Matriz de AVDs
A matriz implementada mantém as system-images instaladas e cria estado de
AVD efêmero por execução. Cada linha usa ANDROID_AVD_HOME temporário,
inicialização sem snapshot e dados limpos; depois dos testes, encerra e exclui
apenas o AVD. Imagens do SDK, NDK, Gradle e caches de compilação permanecem
instalados.
Staging nativo e Gradle rodam em uma cópia temporária do host; a matriz não
reescreve seed-android.properties, jniLibs ou outputs no projeto original.
O smoke rápido declara phone AVDs ARM64 nas APIs 21, 29 e 37. A suite de
release usa a API 37 estável com páginas de 16 KB para tablet, perfil foldable,
memória limitada e oito ciclos de lifecycle. Não há tier nightly nem requisito
de execução x86_64; android-x86_64 permanece coberto apenas pelos contratos
de compilação/link.
O runner constrói o APK uma vez e o reutiliza. Cada linha valida boot,
doctor --serial, install/cold launch, acessibilidade, touch/key/IME básico,
insets/density/focus, lifecycle/rotação, Logcat e shutdown. A suite de release
repete lifecycle conforme a linha e injeta RUNNING_CRITICAL no cenário de
memória limitada. Falhas preservam configuração, Logcat, dumpsys, gfxinfo,
meminfo, árvore de acessibilidade e screenshot em
compiler/llvm/build/android-avd-matrix/.
make -C seed/compiler/llvm android-avd-matrix-check
make -C seed/compiler/llvm android-avd-smoke
make -C seed/compiler/llvm android-avd-release
make -C seed/compiler/llvm game-seed-garden-android-avd-check
SEED_ANDROID_AVD_API=37.0 \
SEED_ANDROID_AVD_RUNNER_POLICY=required \
make -C seed/compiler/llvm android-avd-smoke
A política auto (default) registra SKIP para ferramentas ou imagens
ausentes; required falha; off desativa execução. --install-images, na
chamada direta a scripts/android_avd_matrix.sh, instala imagens selecionadas.
SEED_ANDROID_ADB_TIMEOUT e SEED_ANDROID_AVD_BOOT_TIMEOUT limitam chamadas
adb e boot; SEED_ANDROID_AVD_VERBOSE=true preserva saída detalhada do
emulador. Os três smokes e os quatro cenários de release ARM64 passam no Apple
M4.
O contrato Garden usa a mesma infraestrutura efêmera. Ele valida as 64 células semânticas em portrait e landscape durante oito rotações, movimento com animação reduzida, pause/resume, remoção da sessão de áudio no teardown, startup, frames/jank e retenção de PSS. Essas medições são baseline de AVD; não substituem LeakSanitizer Android nem desempenho, temperatura ou latência em dispositivo físico.
Essa matriz amplia somente a evidência em emulator. O Motorola registrado em
ANDROID_TARGET_BASELINE.md permanece todo o claim físico. A política
completa e a ordem de implementação estão em roadmap-mobile.md.
Testes e validação
Valide contratos sem SDK completo com:
make -C seed/compiler/llvm android-target-test
make -C seed/compiler/llvm android-host-check
make -C seed/compiler/llvm android-package-check
make -C seed/compiler/llvm android-build-check
make -C seed/compiler/llvm android-run-check
make -C seed/compiler/llvm android-doctor-check
Para uma validação real, execute doctor, faça build, instale em AVD ou
dispositivo e rode run. O baseline de evidências está em
ANDROID_TARGET_BASELINE.md.
doctor --serial <adb-serial> também valida modelo, API, ABI, patch de
segurança e estado de autorização do dispositivo selecionado.
Diagnóstico de problemas
-
missing Android SDK/NDK: rodeseed mobile android setupou definaANDROID_HOME/ANDROID_NDK_HOME. -
missing android.jar,aapt2ou sysroot API 21: rodedoctore instale o componente indicado; não use um sysroot sem os diretórios qualificados por ABI. -
missing seed-android.properties: executestageoubuildantes depackage/run. -
Android packaging requires Gradle: instale Gradle ou coloque umgradlewexecutável no host. -
dispositivo
offlineou ausente: verifiqueadb devices, aceite a chave USB e use--serial. -
Status: okausente: consulteadb logcat, confirme o application ID e confira se as duas bibliotecas foram instaladas emjniLibs. -
falha de ABI: não misture
android-arm64comx86_64; o staging valida o tipo ELF antes de copiar a biblioteca. -
aviso
This app isn’t 16 KB compatible: use o compiler/host atuais; ambos ligam os segmentos ELF Android com alinhamento de 16.384 bytes.
Limites e próximos passos
O bridge atual é uma base operacional, não uma promessa de compatibilidade com todo o Android SDK. Catálogo de widgets, layout retido, navegação, editor de texto completo, TalkBack físico, plugins estáveis, inspector, profiler, hot reload, matriz ampla de dispositivos, publicação em loja e assinatura de produção permanecem no roadmap. iOS está ativo no simulador através do compilador, runtime, host Swift e XCFramework; dispositivo físico, provisioning, assinatura e loja permanecem abertos.
Referências
- Roadmap mobile
- Host Android versionado
- Biblioteca
mobile - Instalação da biblioteca
- ABI público JNI