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.

Guides · Cross-Compilation · 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_<class>_<method> 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