Android Guía de la Plataforma

El backend de Android incorpora un pipeline completo que convierte un proyecto del IDE en un APK firmado y en ejecución sobre un emulador o dispositivo real, con controles nativos android.widget.*. El mismo código Harbour que alimenta Windows, macOS y Linux ahora también apunta a Android — sin WebView, sin UI pintada, sin dependencias de ejecución.

Estadísticas del backend
EstadoIteración 1 — disponible ya
LenguajeC (JNI) + Java
API nativaandroid.widget.* vía JNI
SDK mínimoAPI 24 (Android 7.0 Nougat)
SDK objetivoAPI 34 (Android 14)
ABIarm64-v8a (ARM de 64 bits)
ToolchainNDK r26d · SDK 34 · JDK 17
Validado enEmulador Pixel 5 / Android 14
⚠️ En desarrollo. La Iteración 1 implementa UI_FormNew, UI_LabelNew, UI_ButtonNew, UI_EditNew, UI_SetText, UI_GetText y UI_OnClick. El resto de controles (ComboBox, ListView, CheckBox, RadioButton, DatePicker…) llega en iteraciones siguientes. Ver Hoja de ruta.

Visión arquitectónica

Android es el 4º backend GUI nativo de HarbourBuilder. El mismo classes.prg que usa cada plataforma despacha a android_core.c en lugar del bridge Win32/Cocoa/GTK3, y las llamadas JNI se convierten en widgets Android reales dentro de un FrameLayout de MainActivity.

graph TB A["Harbour .prg
DEFINE FORM ... BUTTON ..."] --> B["classes.prg
UI_FormNew, UI_ButtonNew, ..."] B --> C["android_core.c
HB_FUNC + puente JNI"] C -->|JNI CallVoidMethod| D["MainActivity.java
Anfitrión 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 de HarbourBuilder implementa la misma familia de HB_FUNCs UI_*; el de Android vive en source/backends/android/android_core.c y refleja, HB_FUNC a HB_FUNC, el puente Win32 (source/cpp/hbbridge.cpp) y el puente Cocoa (source/backends/cocoa/cocoa_core.m).

Pipeline de compilación

El menú Run → Run on Android… dispara un pipeline de 8 etapas que produce un APK firmado listo para instalar. El mismo pipeline está disponible como script independiente en source/backends/android/build-apk-gui.sh.

graph LR A["Fuente .prg"] --> B["1. harbour.exe
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 firmado"] style I fill:#34c759,stroke:#28a745,color:#0d1117
  1. harbour.exe — el compilador Harbour anfitrión traduce .prg a C portable.
  2. clang (NDK) — compila cruzado a objetos aarch64-linux-android24.
  3. clang --shared — enlaza libapp.so con todas las librerías estáticas de harbour/core (hbvm, hbrtl, hblang, hbcpage, hbrdd, hbmacro, hbpp, hbcommon, hbpcre, hbzlib, hbnulrdd, hbdebug, hbcplr, rddntx/cdx/fpt/nsx, gtstd/trm/cgi/pca, hbsix, hbhsx).
  4. aapt2 compile — compila los recursos Android (res/).
  5. aapt2 link — enlaza recursos + manifest en base.apk; genera R.java.
  6. javac — compila MainActivity.java contra el SDK de Android.
  7. d8 — transforma los .class en classes.dex.
  8. zipalign + apksigner — alinea y firma v2 el APK con un keystore de depuración.

API UI_* en Android

Superficie invocable desde Harbour expuesta por el backend Android. Todas las coordenadas son en píxeles del diseñador, idénticas a Win32/Cocoa/GTK3 — ver manejo de densidad.

HB_FUNCSignaturaMapea a
UI_FormNew(cTitle, nW, nH) → hFormMainActivity.setTitle() — la Activity es el form
UI_LabelNew(hForm, cText, x, y, w, h) → hCtrlandroid.widget.TextView
UI_ButtonNew(hForm, cText, x, y, w, h) → hCtrlandroid.widget.Button
UI_EditNew(hForm, cText, x, y, w, h) → hCtrlandroid.widget.EditText
UI_SetText(hCtrl, cText)TextView.setText()
UI_GetText(hCtrl) → cTextTextView.getText()
UI_OnClick(hCtrl, bBlock)guarda el codeblock para despacharlo desde nativeOnClick
UI_FormRun(hForm)no-op (la Activity posee el bucle de eventos)

Puente JNI

Cada HB_FUNC UI_* obtiene el JNIEnv del hilo que llama e invoca un method id cacheado sobre la referencia global a MainActivity. En Java la creación real del widget se ejecuta en el hilo de UI con runOnUiThread. Los clicks viajan en sentido inverso: Button.setOnClickListener → nativeOnClick(controlId) → hb_evalBlock0.

// android_core.c — despacho de 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 llamado desde el código 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 );
    }});
}

Los handles de control son enteros pequeños (1..255) devueltos por cada UI_*New. En Java un HashMap<Integer, View> los indexa; en C un PHB_ITEM g_click_handlers[256] paralelo guarda los codeblocks registrados con UI_OnClick.

Coordenadas conscientes de la densidad

Las coordenadas del diseñador son 1:1 con píxeles de Windows Desktop. En Android esos mismos valores se multiplican por DisplayMetrics.density, de modo que un botón de 100 px se ve consistente en pantallas mdpi (×1.0), hdpi (×1.5), xhdpi (×2.0), xxhdpi (×3.0) y xxxhdpi (×4.0).

// MainActivity.java — multiplicador de densidad
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;
}

Bucle de eventos (invertido)

En Win32, Cocoa y GTK la llamada oForm:Run() bloquea en una cola de mensajes. En Android el SO posee el bucle: UI_FormRun() es un no-op. El onCreate() de la Activity invoca nativeInit(), que arranca la VM de Harbour y llama a Main()Main() crea los widgets mediante UI_*New y retorna. A partir de ahí el ciclo de vida de la Activity dirige todo; las interacciones del usuario disparan nativeOnClick, que despacha el codeblock almacenado.

Ejecutar desde el IDE

En Windows el IDE añade un menú Run → Run on Android…. Al pulsarlo:

  1. Guarda el proyecto activo (SaveActiveFormCode).
  2. Escribe el contenido de Project1.prg en el directorio fuente del build Android.
  3. Abre un diálogo de progreso e invoca build-apk.sh vía Git Bash.
  4. En caso de fallo: muestra el build-apk.log completo en un diálogo de error.
  5. En caso de éxito: lanza run-on-emulator.sh en segundo plano — arranca el AVD si hace falta, instala el APK, lanza la Activity y guarda logcat en un fichero.
// hbbuilder_win.prg — cableado del menú
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 del toolchain

El target Android depende de cuatro toolchains externos. El Setup Wizard (Run → Android Setup Wizard…) los descarga e instala automáticamente en una ventana terminal propia, así que en una máquina limpia sólo tienes que hacer clic y esperar. Las rutas de abajo son las que usa el wizard (y los scripts de build).

ComponenteVersiónRuta por defecto (Windows)
Android NDKr26dC:\Android\android-ndk-r26d\
Android SDKplatform 34 · build-tools 34.0.0C:\Android\Sdk\
JDK17 (Temurin, portable)C:\JDK17\jdk-17.0.13+11\
Harbour anfitrión3.2.0devC:\harbour\bin\win\bcc\harbour.exe
Git Bashcualquiera recienteC:\Program Files\Git\bin\bash.exe
AVDPixel 5 · android-34 · google_apis · x86_64llamado HarbourBuilderAVD

Ocupa ≈4 GB de disco. Las instalaciones son autocontenidas — sin entradas de registro ni cambios de PATH: los scripts exportan PATH internamente.

Setup Wizard

Menú Run → Android Setup Wizard… abre un diálogo que reporta cada componente como OK o MISSING. Si falta algo, un Yes lanza source/backends/android/setup-android-toolchain.sh en una terminal nueva. El script es idempotente — detecta lo que ya está y baja sólo lo que falta:

ComponenteTamañoOrigen
JDK 17 Temurin~175 MBAdoptium GitHub Releases
Android NDK r26d~1.5 GBdl.google.com
SDK cmdline-tools~100 MBdl.google.com
platforms;android-34, build-tools;34.0.0, platform-tools, emulator, system-image x86_64 ~1.2 GBvia sdkmanager
AVD HarbourBuilderAVDvia avdmanager
Harbour-for-Android libs3.6 MBreleases/harbour-android-arm64-v8a.zip (incluido en el repo)

El script redirige yes a sdkmanager --licenses para que el install no se pare en prompts de licencia, y aplica automáticamente el tweak NDK (ar/ranlib/strip) que los mk files de Harbour esperan. Total ~2.8 GB de descarga en una máquina limpia. Git Bash es el único prerequisito que el wizard no puede instalar por ti.

Hola Android — ejemplo completo

El fichero source/backends/android/hello_gui.prg usa la API UI_* del backend Android directamente:

PROCEDURE Main()

   LOCAL hForm, hLabel, hEdit, hBtn

   hForm  := UI_FormNew( "Hola Android", 400, 600 )
   hLabel := UI_LabelNew(  hForm, "Escribe tu nombre:", 20, 20,  300, 30 )
   hEdit  := UI_EditNew(   hForm, "",                   20, 60,  300, 50 )
   hBtn   := UI_ButtonNew( hForm, "Saludar",            20, 130, 300, 50 )

   UI_OnClick( hBtn, ;
      {|| UI_SetText( hLabel, "Hola, " + UI_GetText( hEdit ) + " !" ) } )

   UI_FormRun( hForm )   // no-op en Android; la Activity posee el bucle

RETURN

Compilar y desplegar:

# compilar el APK
bash source/backends/android/build-apk-gui.sh

# instalar y lanzar en el emulador
adb install -r C:/HarbourAndroid/apk-gui/harbour-gui.apk
adb shell am start -n com.harbour.builder/.MainActivity

Limitaciones conocidas

Hoja de ruta

IteraciónEntregables
1 ✅Pipeline APK, puente JNI, Form/Label/Button/Edit, escalado por densidad, despacho de clicks, validado en emulador
1b ✅Generador de código Android desde el diseñador (los controles visuales emiten llamadas UI_*), traducción de METHOD handlers
1c ✅Colores de form/controles + fuentes viajan al APK (UI_SetFormColor, UI_SetCtrlColor, UI_SetCtrlFont)
6 ✅Setup Wizard — Run → Android Setup Wizard… descarga e instala JDK/NDK/SDK/AVD y extrae las libs Harbour precompiladas
2CheckBox, RadioButton, ComboBox (Spinner), ListView, DatePicker, TimePicker, ProgressBar, Slider (SeekBar)
3Menú (ActionBar), Diálogo (AlertDialog), Toast, paridad MessageBox
4Render de Imagen/Bitmap, empaquetado de recursos, sets de iconos por densidad
5Panel adb logcat embebido en el IDE + stream de build en vivo + selector de dispositivo (AVD / USB / Wi-Fi ADB)
6bPort del Setup Wizard a macOS y Linux
7Gestor de keystores de release + export AAB + asistente de subida a Play Console
8Controles específicos de móvil: TSwitch, TSegmentedControl, TFloatingActionButton, TSwipeView, TQRScanner, TCamera, TMapView

Ficheros fuente

ArchivoPropósito
source/backends/android/android_core.cpuente JNI y HB_FUNCs UI_*
source/backends/android/java/com/harbour/builder/MainActivity.javaanfitrión FrameLayout programático, despacho de clicks
source/backends/android/AndroidManifest.xmlmetadatos del paquete, SDK mín/obj
source/backends/android/res/values/strings.xmlpaquete mínimo de recursos
source/backends/android/build-apk-gui.shpipeline de 8 etapas + firma
source/backends/android/hello_gui.prgPRG demo que prueba el pipeline de extremo a extremo

En esta página

Visión arquitectónica Pipeline de compilación API UI_* en Android Puente JNI Coordenadas por densidad Bucle de eventos (invertido) Ejecutar desde el IDE Requisitos del toolchain Hola Android — ejemplo Limitaciones conocidas Hoja de ruta Ficheros fuente