Android Guia de Plataforma
O backend Android oferece um pipeline completo que transforma um projeto do IDE em um APK assinado
rodando em um emulador ou dispositivo Android real, com controles nativos
android.widget.*. O mesmo codigo Harbour que roda nos desktops Windows, macOS e Linux
agora tambem compila para Android — sem WebView, sem UI skinned, sem dependencia de runtime.
| Status | Iteracao 1 — disponivel agora |
|---|---|
| Linguagem | C (JNI) + Java |
| API Nativa | android.widget.* via JNI |
| SDK Minimo | API 24 (Android 7.0 Nougat) |
| SDK Alvo | API 34 (Android 14) |
| ABI | arm64-v8a (ARM 64-bit) |
| Toolchain | NDK r26d · SDK 34 · JDK 17 |
| Validado em | Emulador Pixel 5 / Android 14 |
UI_FormNew, UI_LabelNew,
UI_ButtonNew, UI_EditNew, UI_SetText, UI_GetText e
UI_OnClick. Mais controles (ComboBox, ListView, CheckBox, RadioButton, DatePicker…) serao
adicionados nas proximas iteracoes. Veja o Roadmap abaixo.
Visao Geral da Arquitetura
Android e o 4o backend GUI nativo do HarbourBuilder. O mesmo classes.prg que todas as outras
plataformas usam despacha para android_core.c em vez da bridge Win32 / Cocoa / GTK3, e as
chamadas JNI se transformam em controles Android reais adicionados a um FrameLayout dentro
de MainActivity.
DEFINE FORM ... BUTTON ..."] --> B["classes.prg
UI_FormNew, UI_ButtonNew, ..."] B --> C["android_core.c
HB_FUNC + bridge JNI"] C -->|JNI CallVoidMethod| D["MainActivity.java
Host FrameLayout"] D --> E["android.widget.TextView"] D --> F["android.widget.Button"] D --> G["android.widget.EditText"] F -->|onClick| H["nativeOnClick(id)"] H -->|hb_evalBlock0| B style A fill:#8b5cf6,stroke:#7c3aed,color:#fff style B fill:#f59e0b,stroke:#d97706,color:#0d1117 style C fill:#34c759,stroke:#28a745,color:#0d1117 style D fill:#34c759,stroke:#28a745,color:#0d1117 style E fill:#3ddc84,stroke:#1a8d4d,color:#0d1117 style F fill:#3ddc84,stroke:#1a8d4d,color:#0d1117 style G fill:#3ddc84,stroke:#1a8d4d,color:#0d1117 style H fill:#34c759,stroke:#28a745,color:#0d1117
Cada backend do HarbourBuilder implementa a mesma familia de HB_FUNCs UI_*; o do Android
esta em source/backends/android/android_core.c e espelha, HB_FUNC por HB_FUNC, a bridge
Win32 (source/cpp/hbbridge.cpp) e a bridge Cocoa (source/backends/cocoa/cocoa_core.m).
Pipeline de Compilacao
O item de menu Run → Run on Android… aciona um pipeline de 8 etapas que produz um APK
assinado pronto para instalar. O mesmo pipeline esta disponivel como script independente em
source/backends/android/build-apk-gui.sh.
prg → .c"] B --> C["2. clang
C → .o"] C --> D["3. clang --shared
libapp.so"] D --> E["4. aapt2 compile
recursos"] E --> F["5. aapt2 link
base.apk"] F --> G["6. javac
MainActivity.class"] G --> H["7. d8
classes.dex"] H --> I["8. zipalign + apksigner
APK assinado"] style I fill:#34c759,stroke:#28a745,color:#0d1117
- harbour.exe — compilador Harbour host transpila
.prgpara C portavel. - clang (NDK) — cross-compila C para objetos
aarch64-linux-android24. - clang --shared — linka
libapp.socom o conjunto completo de bibliotecas estaticasharbour/core(hbvm, hbrtl, hblang, hbcpage, hbrdd, hbmacro, hbpp, hbcommon, hbpcre, hbzlib, hbnulrdd, hbdebug, hbcplr, rddntx/cdx/fpt/nsx, gtstd/trm/cgi/pca, hbsix, hbhsx). - aapt2 compile — compila recursos Android (
res/). - aapt2 link — linka recursos + manifest em
base.apk; geraR.java. - javac — compila
MainActivity.javacontra o Android SDK. - d8 — dex-compila arquivos
.classparaclasses.dex. - zipalign + apksigner — alinha e assina o APK com uma keystore de debug.
API UI_* no Android
A superficie chamavel pelo Harbour exposta pelo backend Android. Todas as coordenadas estao em pixels do designer de formularios, identicas ao Win32/Cocoa/GTK3 — veja tratamento de densidade.
| HB_FUNC | Assinatura | Mapeia para |
|---|---|---|
UI_FormNew | (cTitle, nW, nH) → hForm | MainActivity.setTitle() — a Activity e o formulario |
UI_LabelNew | (hForm, cText, x, y, w, h) → hCtrl | android.widget.TextView |
UI_ButtonNew | (hForm, cText, x, y, w, h) → hCtrl | android.widget.Button |
UI_EditNew | (hForm, cText, x, y, w, h) → hCtrl | android.widget.EditText |
UI_SetText | (hCtrl, cText) | TextView.setText() |
UI_GetText | (hCtrl) → cText | TextView.getText() |
UI_OnClick | (hCtrl, bBlock) | armazena o codeblock para despacho via nativeOnClick |
UI_FormRun | (hForm) | no-op (a Activity Android possui o loop de eventos) |
Bridge JNI
Cada HB_FUNC UI_* obtem o JNIEnv da thread chamadora e invoca um id de metodo em cache
na referencia global da MainActivity. O lado Java executa a criacao do widget na thread de UI com
runOnUiThread. Cliques viajam na direcao oposta:
Button.setOnClickListener → nativeOnClick(controlId) → hb_evalBlock0.
// android_core.c — despacho UI_ButtonNew HB_FUNC( UI_BUTTONNEW ) { int id = create_widget( m_createButton, HB_ISCHAR(2) ? hb_parc(2) : "", hb_parni(3), hb_parni(4), hb_parni(5), hb_parni(6) ); hb_retni( id ); } // Java chamado de volta pelo nativo: public void createButton( final int id, final String text, final int x, final int y, final int w, final int h ) { runOnUiThread( new Runnable() { public void run() { Button b = new Button( MainActivity.this ); b.setText( text ); b.setOnClickListener( v -> nativeOnClick( id ) ); root.addView( b, lp( x, y, w, h ) ); ctrls.put( id, b ); }}); }
Handles de controles sao inteiros pequenos (1..255) retornados por cada UI_*New.
O lado Java indexa um HashMap<Integer, View>; o lado C mantem um array paralelo
PHB_ITEM g_click_handlers[256] com os codeblocks Harbour anexados via UI_OnClick.
Coordenadas com Consciencia de Densidade
Coordenadas do designer de formularios sao 1:1 com pixels de desktop Windows. No Android os mesmos
valores de pixel escalam com DisplayMetrics.density para que um botao de 100px seja
consistente em telas mdpi (×1.0), hdpi (×1.5), xhdpi (×2.0), xxhdpi (×3.0) e xxxhdpi (×4.0).
// MainActivity.java — multiplicador de densidade private int dp( int formPx ) { return Math.round( formPx * density ); } private FrameLayout.LayoutParams lp( int x, int y, int w, int h ) { FrameLayout.LayoutParams p = new FrameLayout.LayoutParams( dp(w), dp(h) ); p.leftMargin = dp(x); p.topMargin = dp(y); return p; }
Loop de Eventos (invertido)
No Win32, Cocoa e GTK a chamada Harbour oForm:Run() bloqueia em uma bomba de mensagens.
No Android o SO possui o loop de eventos: UI_FormRun() e um no-op.
O onCreate() da Activity chama nativeInit(), que inicia a VM Harbour e invoca
Main() — Main() cria os widgets via UI_*New e retorna. A partir
de entao o ciclo de vida da Activity comanda tudo; interacoes do usuario disparam
nativeOnClick, que despacha o codeblock armazenado.
Executando pelo IDE
No Windows o IDE adiciona o item de menu Run → Run on Android…. Ao clicar:
- Salva o projeto ativo (
SaveActiveFormCode). - Escreve o conteudo de
Project1.prgno diretorio de build Android. - Abre um dialogo de progresso e invoca
build-apk.shvia Git Bash. - Em caso de falha: mostra o
build-apk.logcompleto em um dialogo de erro. - Em caso de sucesso: executa
run-on-emulator.shem background — inicializa o AVD se necessario, instala o APK, lanca a activity, e exibe ologcatem um arquivo de log.
// hbbuilder_win.prg — conexao do menu DEFINE POPUP oRun PROMPT "&Run" OF oIDE MENUITEM "&Run" OF oRun ACTION TBRun() MENUITEM "&Debug" OF oRun ACTION TBDebugRun() MENUSEPARATOR OF oRun MENUITEM "Run on &Android..." OF oRun ACTION TBRunAndroid()
Requisitos do Toolchain
O target Android depende de quatro toolchains externos. O Assistente de Configuracao (Run → Android Setup Wizard…) baixa e instala automaticamente em uma janela de terminal dedicada, entao em uma maquina nova basta clicar e esperar. Os caminhos abaixo sao os que o assistente (e os scripts de build) utilizam.
| Componente | Versao | Caminho padrao (Windows) |
|---|---|---|
| Android NDK | r26d | C:\Android\android-ndk-r26d\ |
| Android SDK | platform 34 · build-tools 34.0.0 | C:\Android\Sdk\ |
| JDK | 17 (Temurin, portavel) | C:\JDK17\jdk-17.0.13+11\ |
| Harbour Host | 3.2.0dev | C:\harbour\bin\win\bcc\harbour.exe |
| Git Bash | qualquer versao recente | C:\Program Files\Git\bin\bash.exe |
| AVD | Pixel 5 · android-34 · google_apis · x86_64 | nome HarbourBuilderAVD |
O footprint total do toolchain e ≈4 GB. As instalacoes sao autonomas — sem entradas no registro,
sem alteracoes no PATH: os scripts de build exportam PATH internamente.
Assistente de Configuracao
O menu Run → Android Setup Wizard… abre um dialogo que relata cada componente do
toolchain como OK ou FALTANDO. Se algo estiver faltando, um unico Sim
lanca source/backends/android/setup-android-toolchain.sh em uma nova janela de terminal.
O script e idempotente — detecta o que ja esta instalado e baixa apenas o que falta:
| Componente | Tamanho | Fonte |
|---|---|---|
| JDK 17 Temurin | ~175 MB | Adoptium GitHub Releases |
| Android NDK r26d | ~1.5 GB | dl.google.com |
| SDK cmdline-tools | ~100 MB | dl.google.com |
| platforms;android-34, build-tools;34.0.0, platform-tools, emulator, system-image x86_64 | ~1.2 GB | via sdkmanager |
AVD HarbourBuilderAVD | — | via avdmanager |
| Bibliotecas Harbour-para-Android | 3.6 MB | releases/harbour-android-arm64-v8a.zip (incluido no repo) |
O script redireciona yes para sdkmanager --licenses para que a instalacao
nao seja interrompida, e aplica automaticamente o ajuste de ar/ranlib/strip
do NDK que os mk files do Harbour exigem. Total de ~2.8 GB de download em uma maquina vazia.
Git Bash e o unico pre-requisito que o assistente nao pode instalar para voce.
Ola Android — exemplo completo
O arquivo source/backends/android/hello_gui.prg usa a API UI_* do backend
Android diretamente:
PROCEDURE Main() LOCAL hForm, hLabel, hEdit, hBtn hForm := UI_FormNew( "Ola Android", 400, 600 ) hLabel := UI_LabelNew( hForm, "Digite seu nome:", 20, 20, 300, 30 ) hEdit := UI_EditNew( hForm, "", 20, 60, 300, 50 ) hBtn := UI_ButtonNew( hForm, "Saudar", 20, 130, 300, 50 ) UI_OnClick( hBtn, ; {|| UI_SetText( hLabel, "Ola, " + UI_GetText( hEdit ) + " !" ) } ) UI_FormRun( hForm ) // no-op no Android; a Activity possui o loop RETURN
Compilar e implantar:
# compilar o APK bash source/backends/android/build-apk-gui.sh # instalar + lancar no emulador adb install -r C:/HarbourAndroid/apk-gui/harbour-gui.apk adb shell am start -n com.harbour.builder/.MainActivity
Limitacoes Conhecidas
- arm64-v8a apenas — builds x86_64 / armv7 ainda nao estao habilitados. Todos os dispositivos modernos e o AVD de referencia sao arm64.
libharbour.sodinamico nao compila no Windows: o comando de link excede o limite de 8 KB da linha de comando do Windows (Erro 87). Linkagem estatica por app e usada no lugar (funciona em qualquer host). Nao-bloqueante.- GT padrao e
gtstd—? "texto"classico imprime no logcat, nao na UI. Para saida visivel useUI_SetText()em um label. - Integracao com o designer de formularios — o item de menu atual envia o Project1.prg
bruto como-esta. Um gerador de codigo Android dedicado que emite chamadas
UI_*a partir do formulario visual e o entregavel da iteracao 1b. - TPageControl / tabs — o backend Android implementa
UI_TabControlNew,UI_SetCtrlOwner,UI_GetCtrlPagecomo no-ops. Suporte completo a pagas vem com o binding ViewPager2.
Roadmap
| Iteracao | Entregaveis |
|---|---|
| 1 ✅ | Pipeline APK, bridge JNI, Form/Label/Button/Edit, escalonamento de densidade, despacho de click, validado no emulador |
| 1b ✅ | Designer de formularios do IDE → gerador de codigo Android (controles visuais emitem chamadas UI_*), traducao de handlers METHOD |
| 1c ✅ | Cores de form/controles + fontes transportadas (UI_SetFormColor, UI_SetCtrlColor, UI_SetCtrlFont) |
| 6 ✅ | Assistente de Configuracao — Run → Android Setup Wizard… baixa e instala JDK/NDK/SDK/AVD e extrai as bibliotecas Harbour incluidas |
| 2 | CheckBox, RadioButton, ComboBox (Spinner), ListView, DatePicker, TimePicker, ProgressBar, Slider (SeekBar) |
| 3 | Menu (ActionBar), Dialog (AlertDialog), Toast, paridade com MessageBox |
| 4 | Renderizacao de Image/Bitmap, empacotamento de recursos, icones por densidade |
| 5 | Painel adb logcat embutido no IDE + stream de build em tempo real + seletor de dispositivo (AVD / USB / Wi-Fi ADB) |
| 6b | Porta do Assistente de Configuracao para hosts macOS e Linux |
| 7 | Gerenciador de keystore de release + exportacao AAB + assistente de upload ao Play Console |
| 8 | Controles mobile: TSwitch, TSegmentedControl, TFloatingActionButton, TSwipeView, TQRScanner, TCamera, TMapView |
Arquivos Fonte
| Arquivo | Proposito |
|---|---|
source/backends/android/android_core.c | Bridge JNI e HB_FUNCs UI_* |
source/backends/android/java/com/harbour/builder/MainActivity.java | host FrameLayout programatico, despacho de click |
source/backends/android/AndroidManifest.xml | metadados do pacote, SDK min/target |
source/backends/android/res/values/strings.xml | bundle de recursos minimo |
source/backends/android/build-apk-gui.sh | pipeline de 8 etapas de build + assinatura |
source/backends/android/hello_gui.prg | PRG de demo provando o pipeline ponta-a-ponta |