Android aplicações com seed

<!-- verified-against: seed-llvm; examples: docs-examples-test -->

Este guia descreve como usar o atual Android seed plataforma e estrutura. O apoio implementado combina uma seed biblioteca (mobile), um Android anfitrião baseado em Gradle/Kotlin/CMake e uma ponte JNI que carrega o nativo seed biblioteca.

Estado atual: Android é a plataforma móvel ativa. O quadro fornece uma Superfície do Canvas retida acionada por comandos de quadro, entrada básica, ciclo de vida, inserções, métricas de tela e multi-ABI embalagem. Ainda não é um completo kit de ferramentas de widgets.

O que é suportado

O que se segue não são reivindicações de suporte atual: um catálogo completo de widgets, TalkBack para dispositivo físico, suporte completo IME selection/composition, modelagem de texto, recarga a quente, ampla matriz de dispositivos, publicação na loja ou prontidão para 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

O seed o aplicativo ainda não substitui Activity. O Android host continua responsável pelo processo, janela, Canvas, JNI e integração com o SDK. O mobile biblioteca fornece as importações portáteis da fatia implementada e só deve ser usada com um Android alvo.

Requisitos

Você deve ter:

O instalador oficial do projeto usa $HOME/Android/Sdk, não requer sudoe instala a linha de base completa:

./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

Usar --api, --abi, --image-flavor, --ndk, --avde --device para personalizar a instalação. --skip-gradle deixa a instalação do Gradle por conta do usuário. Para usar um NDK diferente da linha de base, declare explicitamente SEED_ANDROID_NDK_REVISION e confirmar 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 modelo com versão:

cp -R seed/compiler/llvm/mobile/android my-android

Compile ambas as ABIs, prepare 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/, vincula o objeto compartilhado seed como uma dependência de ponte JNI empacotada e executa assembleDebug; o arquivo permanece disponível separadamente para consumidores nativos. O arquivo my-android/seed-android.properties registra o nome nativo e o ID do aplicativo usado pelos comandos subsequentes.

Tutorial 2: desenhe uma tela

Importe a biblioteca mobile Android para o código do seu aplicativo. Um exemplo completo está em compiler/llvm/tests/mobile/android_framework.sd. O retorno de chamada do quadro 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);
}

As coordenadas e o tamanho da fonte são expressos em milipixels. As cores são inteiros ARGB. O host limita cada quadro a 256 retângulos, 32 itens de texto, 128 nós semânticos e 256 UTF-8 bytes por rótulo ou item. O texto é desenhado pelo Android Lona; seleção de fontes e modelagem avançada ainda não fazem parte do contrato.

Tutorial 3: Consumir Touch, Teclado e IME

A biblioteca mantém uma fila limitada de 128 eventos. Leia os campos antes de remover um 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 os produtores excederem a capacidade, a fila retém os eventos mais recentes. A região de seleção e composição ainda não está exposta.

Tutorial 4: Ciclo de vida e recursos

Defina apenas os ganchos necessários. Eles são executados no encadeamento Activity e não devem bloquear, reter objetos JNI ou criar tarefas sem um 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 está protegido contra execução repetida no mesmo processo; recriar Activity não reinicia o aplicativo. Destruição cancela obras pendentes na ponte; a morte do processo é o limite final da limpeza.

Aplicativos com recursos persistentes de cross-frame podem exportar seed_mobile_context_create, seed_mobile_context_on_event, seed_mobile_context_on_framee seed_mobile_context_destroy. O host mantém no máximo um contexto por geração de Activity, interrompe o encaminhamento de retornos de chamada quando esta geração é invalidada e destrói o contexto exatamente uma vez. Os ganchos legados continuam sendo a alternativa.

Use mobile.window_focused() para pausar o trabalho visual durante a perda de foco e mobile.memory_pressure() para liberar caches após onTrimMemory. Não trate esses sinais como uma garantia de que o processo permanecerá ativo.

Tutorial 5: layout, área segura e armazenamento

As inserções 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 visualizações limitadas dos caminhos privados fornecidos por Activity; use-os para armazenamento interno e cache. Não há acesso automático ao armazenamento externo. A permissão de rede declarada pelo modelo cobre a fatia net atual, mas as permissões adicionais permanecem de responsabilidade do host.

Construir fluxos

Construção 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

Construção integrada

./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 é fornecido e gera pares shared/static para as duas ABIs; o host prefere o objeto compartilhado empacotado e mantém o arquivo como um artefato separado. stage continua a aceitar bibliotecas compartilhadas ELF, valida artefatos e rejeita IDs de aplicativos inválidos. O nome do pacote nativo não pode conter / ou ...

Se o pacote Seed que contém app.sd tem um assets/ pasta, a compilação integrada também copia seus arquivos simples regulares para a pasta Android anfitrião. Os nomes são limitados a letras e dígitos ASCII, ., _e -; subpastas, arquivos ocultos e colisões com a investigação do host são rejeitados. Na inicialização, o host lê o gerado seed-mobile-assets.list indexa e extrai exatamente esses arquivos — no máximo 256 arquivos e 64 MiB — para a raiz privada somente leitura já exposta ao Seed. Ativos de estrutura ou sobreposição também listados por AssetManager não entre no pacote Seed. O mesmo manifesto e recursos de imagem, fonte, WAV e Ogg podem, portanto, seguir desktop e Android sem lógica de cópia específica do aplicativo.

Dependências diretas em audio-vorbis e grove-game-assets fazem com que a construção integrada inclua os back-ends stb correspondentes em ambas as ABIs. A ponte JNI fornece o contrato de áudio compartilhado sobre OpenSL ES, com fluxos limitados, identificadores marcados por geração, uma fila PCM estéreo de 48 kHz, consultas de bytes pendentes, pause/resume, limpeza e fechamento exatamente uma vez.

Depurar, liberar e executar

./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 pela configuração:

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 AVD

A matriz implementada mantém o system-images instalado e cria um estado AVD efêmero por execução. Cada linha usa temporário ANDROID_AVD_HOME, inicialização sem instantâneo e dados limpos; Após o teste, feche e exclua apenas o AVD. Imagens SDK, NDK, Gradle e caches de build permanecem instalados. O teste nativo e o Gradle são executados em uma cópia temporária do host; a matriz não reescreve seed-android.properties, jniLibs ou resultados no projeto original.

Fast smoke declara AVDs de telefone ARM64 nas APIs 21, 29 e 37. O conjunto de lançamento usa stable API 37 com páginas de tablet de 16 KB, perfil dobrável, memória limitada e oito ciclos de vida. Não há nível noturno e nenhum requisito para execução x86_64; android-x86_64 permanece coberto por compile/link apenas contratos.

O executor cria o APK uma vez e o reutiliza. Cada linha valida a inicialização, doctor --serial, install/cold lançamento, acessibilidade, básico touch/key/IME, insets/density/focus, lifecycle/rotation, Logcat e desligamento. O conjunto de lançamento repete o ciclo de vida conforme a linha e injeta RUNNING_CRITICAL no cenário de memória limitada. As falhas preservam a configuração, Logcat, dumpsys, gfxinfo, meminfo, árvore de acessibilidade e captura de tela 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 (padrão) registra SKIP para ferramentas ou imagens ausentes; required falha; off desativa a execução. --install-images, em chamada direta para 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 a saída detalhada do emulador. Os três cenários de lançamento do Smoke e os quatro ARM64 passam no Apple M4.

O contrato Garden utiliza a mesma infraestrutura efêmera. Valida as 64 células semânticas em retrato e paisagem durante oito rotações, movimento com animação reduzida, pause/resume, remoção da sessão de áudio durante a desmontagem, inicialização, frames/jank e retenção de PSS. Estas medições são a linha de base do AVD; eles não substituem Android LeakSanitizer ou medições de desempenho, térmicas e latência em um dispositivo físico.

Esta matriz apenas expande a evidência no emulador. A Motorola registrada em ANDROID_TARGET_BASELINE.md permanece apenas com reivindicação física. A política completa e a ordem de implementação estão em roadmap-mobile.md.

Teste 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 validação real, execute doctor, faça build, instale no AVD ou dispositivo e execute run. A linha de base da evidência está em ANDROID_TARGET_BASELINE.md. doctor --serial <adb-serial> também valida o modelo, API, ABI, patch de segurança e estado de autorização do dispositivo selecionado.

Diagnóstico de problemas

Limites e próximos passos

A ponte actual é uma base operacional, não uma promessa de compatibilidade com todo o Android SDK. Um catálogo de widgets, layout retido, navegação, um editor de texto completo, TalkBack para dispositivos físicos, plug-ins estáveis, um inspetor, um criador de perfil, recarga a quente, uma ampla matriz de dispositivos, publicação na loja e assinatura de produção permanecem no roteiro. iOS está ativo no simulador por meio do compilador, tempo de execução, host Swift e XCFramework; a execução de dispositivos físicos, o provisionamento, a assinatura e a publicação na loja permanecem abertos.

Referências