====== Android-Entwicklung mit Lyx ====== Lyx kompiliert direkt zu Android-nativen ''.so''-Bibliotheken ohne NDK-Toolchain. Die 17 Android-Units decken den vollständigen Workflow ab: NativeActivity, JNI, Logging, Asset-Manager, OpenGL ES 2, APK-Bau und mehr. → [[lyx_-_programmiersprache:guides|Guides]] · [[lyx_-_programmiersprache:guides:crosscompiling|Cross-Compilation]] · [[lyx_-_programmiersprache:units:android|std.android Referenz]] ---- ===== Architektur ===== android/jni — JNI 1.6 Typ-Aliase (JNIEnv, jobject, jclass, jint, ...) android/native_activity — ANativeActivity-Struct + Callback-Tabelle android/app_glue — Worker-Thread-Glue (android_app, APP_CMD_*) android/log — Logcat-Ausgabe via stderr android/asset — Asset Manager (APK-Assets lesen) android/native_window — ANativeWindow (Surface-Handle) android/input — AInputQueue, AInputEvent (Touch, Keys) android/sensor — ASensorManager, Beschleunigungssensor, Gyroskop android/gles2 — OpenGL ES 2.0 (Context-Setup + Render-Loop) android/looper — ALooper (Event-Loop-Integration) android/manifest_gen — AndroidManifest.xml-Generator android/apk_builder — APK-Paket erstellen (ZIP + Manifest + Classes.dex-Stub) android/zip_writer — ZIP-Schreiber (Grundlage für APK) android/random — arc4random / Bionic-Random android/restrictions — Katalog der unter SELinux/Bionic gesperrten Syscalls android/ioctl — ioctl-Nummern für ASHMEM, ALSA, V4L2 ---- ===== Schritt 1: Kompilieren für Android ===== # ARM64 Shared Library (Standard — alle Android-Geräte ab API 21): lyxc mylib.lyx --target=android --output-type=shared-lib -o libmylib.so # Mit explizitem API-Level (Default: 26 = Android 8.0): lyxc mylib.lyx --target=android --android-api=29 --output-type=shared-lib -o libmylib.so # Android x86_64 (Emulator): lyxc mylib.lyx --target=android-x86_64 --output-type=shared-lib -o libmylib_x86.so Das erzeugte ''.so'' enthält automatisch: * ''.note.android.ident'' mit dem API-Level * Bionic-kompatibles ELF64 (ARM64) * Kein ''__libc_start_main'' (Shared Library hat keinen ''_start'') ---- ===== Schritt 2: JNI-Funktionen exportieren ===== Mit ''@jni'' wird der Funktionsname automatisch in das Java-Format ''Java__'' umgeschrieben: import std.android.jni; import std.android.log; // Aufruf aus Java/Kotlin: com.example.MyApp.hello() @jni(class="com/example/MyApp", method="hello") pub fn hello(env: JNIEnv, obj: jobject): void { // Logcat-Ausgabe: AndroidLogWrite(ANDROID_LOG_INFO, "MyApp"c, "hello() called"c); } // Aufruf aus Java/Kotlin: com.example.MyApp.add(int, int) @jni(class="com/example/MyApp", method="add") pub fn add(env: JNIEnv, obj: jobject, a: jint, b: jint): jlong { return a + b; } **Java-Seite:** public class MyApp { static { System.loadLibrary("mylib"); } public native void hello(); public native long add(int a, int b); } ---- ===== Schritt 3: Logging (Logcat) ===== import std.android.log; // Einfache Ausgabe: AndroidLogWrite(ANDROID_LOG_DEBUG, "MyTag"c, "Debug-Nachricht"c); AndroidLogWrite(ANDROID_LOG_ERROR, "MyTag"c, "Fehler aufgetreten"c); ^ Konstante ^ Level ^ Anzeige in logcat ^ | ''ANDROID_LOG_VERBOSE'' | 2 | V | | ''ANDROID_LOG_DEBUG'' | 3 | D | | ''ANDROID_LOG_INFO'' | 4 | I | | ''ANDROID_LOG_WARN'' | 5 | W | | ''ANDROID_LOG_ERROR'' | 6 | E | | ''ANDROID_LOG_FATAL'' | 7 | F | ---- ===== NativeActivity (ohne Java-Activity) ===== Für rein native Anwendungen (kein Java-Code außer dem Minimal-Glue): import std.android.native_activity; import std.android.app_glue; import std.android.log; // Einstiegspunkt für NativeActivity: pub fn android_main(app: int64): void { // app ist ein Zeiger auf android_app-Struktur // Ereignisschleife: var running: int64 := 1; while running { // Nachrichten verarbeiten: var cmd: int64 := peek64(app + 0); // vereinfacht if cmd == APP_CMD_INIT_WINDOW { AndroidLogWrite(ANDROID_LOG_INFO, "App"c, "Window initialized"c); } if cmd == APP_CMD_TERM_WINDOW { running := 0; } } } **APP_CMD_*-Konstanten:** ^ Konstante ^ Wert ^ Bedeutung ^ | ''APP_CMD_INIT_WINDOW'' | 1 | Surface bereit (Render-Start) | | ''APP_CMD_TERM_WINDOW'' | 2 | Surface wird zerstört | | ''APP_CMD_GAINED_FOCUS'' | 6 | App hat Fokus | | ''APP_CMD_LOST_FOCUS'' | 7 | App hat Fokus verloren | | ''APP_CMD_PAUSE'' | 9 | App wird pausiert | | ''APP_CMD_RESUME'' | 10 | App wird fortgesetzt | | ''APP_CMD_STOP'' | 13 | App wird gestoppt | | ''APP_CMD_DESTROY'' | 14 | App wird zerstört | ---- ===== Assets aus APK lesen ===== import std.android.asset; // Asset-Manager aus ANativeActivity holen (via JNI übergeben): var assetMgr: AAssetManager := 0; // aus NativeActivity.assetManager // Asset öffnen (nur aus Lyx-Seite, wenn assetMgr als int64 übergeben): // AAssetManager_open / AAsset_read werden via FFI aufgerufen Asset-Zugriffsmodi: ^ Konstante ^ Bedeutung ^ | ''AASSET_MODE_STREAMING'' | Sequentielles Lesen (vorwärts) | | ''AASSET_MODE_RANDOM'' | Beliebiger Zugriff (seek möglich) | | ''AASSET_MODE_BUFFER'' | Ganzes Asset in RAM mappen | ---- ===== OpenGL ES 2 (gles2) ===== import std.android.gles2; // Wichtigste GL-Konstanten: // GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT // GL_TRIANGLES, GL_TRIANGLE_STRIP // GL_VERTEX_SHADER, GL_FRAGMENT_SHADER // GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER // GL_FLOAT, GL_UNSIGNED_SHORT // Render-Frame (Beispiel): // glClearColor(0.0, 0.0, 0.0, 1.0) // glClear(GL_COLOR_BUFFER_BIT) // ... Shader, VAO, Draw-Call ... // eglSwapBuffers(display, surface) ---- ===== APK erstellen ===== import std.android.apk_builder; // Vollständiges APK aus .so + Manifest: // ApkCreate("myapp.apk"c, "libmylib.so"c, manifest_xml, manifest_len); Der APK-Builder nutzt ''android/zip_writer'' intern und erzeugt: * ''AndroidManifest.xml'' (aus ''android/manifest_gen'') * ''lib/arm64-v8a/libmylib.so'' * Minimaler ''classes.dex''-Stub (für NativeActivity-Aktivierung) ---- ===== Eingeschränkte Syscalls (android/restrictions) ===== Unter Android/SELinux sind bestimmte Syscalls gesperrt: import std.android.restrictions; // ANDROID_BLOCKED_SYSCALLS enthält die Liste gesperrter Calls: // fork(), execve(), ptrace(), setuid(), mount(), ... // Für Netzwerk: bind() auf privilegierten Ports (< 1024) gesperrt Statt ''fork()'' → Threads via ''std.thread''. Statt ''execve()'' → Nativer JNI-Aufruf oder Intent. ---- ===== Welche Unit wann? ===== ^ Szenario ^ Unit ^ | Einfache JNI-Funktion aus Java aufrufen | ''android/jni'' + ''@jni''-Annotation | | Debug-Ausgabe in Logcat | ''android/log'' | | Rein native App ohne Java | ''android/native_activity'' + ''android/app_glue'' | | APK selbst bauen | ''android/apk_builder'' | | Touch-Eingabe verarbeiten | ''android/input'' | | Sensor-Daten (Gyro, Beschleunigung) | ''android/sensor'' | | OpenGL ES 2 rendern | ''android/gles2'' | | APK-Assets lesen | ''android/asset'' | Letzte Aktualisierung: 2026-06-08