Files
mesh-configs/skills/devops/mobile-apk-flutter-build/SKILL.md
T

8.2 KiB
Raw Blame History

name, description, version, author, platforms
name description version author platforms
mobile-apk-flutter-build Flutter-APK auf headless VPS bauen: Setup + AGP-Pitfalls. 1.0.0 mehlzoerwer
linux

Mobile APK bauen (Flutter, headless Linux-VPS)

Klasse: Eine Flutter-App als Android-APK auf einem headless Linux-VPS bauen und zum Download bereitstellen. Verifiziert 2026-08-07 für PersoEnt (VPS netcup, Ubuntu 24.04).

Hardware-Notiz: flutter doctor meldet "Android Studio not installed" und fehlendes Chrome/Linux-Toolchain — beide sind für APK-Build nicht nötig. Android toolchain ✓ reicht.

1. Flutter SDK installieren

cd /opt
curl -sL -o /tmp/flutter.tar.xz "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.24.5-stable.tar.xz"
tar xf /tmp/flutter.tar.xz          # → /opt/flutter
echo 'export PATH="$PATH:/opt/flutter/bin"' >> /root/.bashrc
export PATH="$PATH:/opt/flutter/bin"
flutter --version                   # prüft Dart-Version (3.5.x)

2. 🔥 git safe.directory — DER "0.0.0-unknown"-Fix (PITFALL)

Wenn flutter --version / flutter pub meldet "Flutter SDK version 0.0.0-unknown" oder fatal: detected dubious ownership in repository at '/opt/flutter', dann ist Flutters git-Versionserkennung gebrochen. Fix:

git config --global --add safe.directory /opt/flutter

Ohne diesen Schritt schlägt jeder pub get an Flutters eigener Versionsprüfung fehl ("The current Flutter SDK version is 0.0.0-unknown ... version solving failed"). Das ist NICHT ein echtes Versionsproblem — nur ownership. Nach dem Fix zeigt flutter --version wieder 3.24.5 • stable.

3. Android SDK + Java

apt-get install -y openjdk-17-jdk unzip

# cmdline-tools:
mkdir -p /opt/android-sdk/cmdline-tools
curl -sL -o /tmp/cmdtools.zip "https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip"
unzip -q cmdtools.zip -d /opt/android-sdk/cmdline-tools/
mv /opt/android-sdk/cmdline-tools/cmdline-tools /opt/android-sdk/cmdline-tools/latest   # 'latest' zwingend!

export ANDROID_HOME=/opt/android-sdk
export PATH="$PATH:/opt/android-sdk/cmdline-tools/latest/bin"
yes | sdkmanager --licenses
sdkmanager "platforms;android-34" "build-tools;34.0.0" "platform-tools"

Gradle lädt fehlende Build-Tools (z.B. 33.0.1) automatisch nach. Android-Studio NICHT nötig.

4. Projekt anlegen + Dependencies

flutter create --platforms=android --org de.persoent --project-name persoent_app persoent_app
cd persoent_app

Statt manuelle Versionen in pubspec zu erraten → flutter pub add <pkg> (löst passende Version selbst, inkl. :^0.0.0 bei 0.x-Paketen):

flutter pub add pocketbase google_sign_in http shared_preferences

5. 🔥 AGP namespace-Konflikt mit älteren Plugins (PITFALL)

Symptom: flutter build apk → "Could not create ... LibraryVariantBuilderImpl. > Namespace not specified. Specify a namespace in the module's build file." (im Plugin, z.B. :health_connect).

Ursache: AGP 8.1 (im Projekt, android/settings.gradle) erzwingt namespace, aber ältere Plugin-Pakete (z.B. health_connect ^0.x) haben keinen. Optionen:

  • Einfachster robuster Weg: das brechende Plugin flutter pub remove <pkg> vorerst entfernen, das Grundgerüst (Login+Dashboard) bauen → erst funktionierendes APK, dann Health-Integration gezielt lösen.
  • Oder AGP 8.1 → 7.3 zurückstufen (matcht Flutters Gradle), riskant.

Bau-Strategie (empfohlen): erst minimales APK, das kompiliert; native Plugins (Health Connect usw.) danach einzeln, um Fehlerursachen zu isolieren.

5b. 🔥 health_connect auf pub.dev ist ein LEERES 0.0.0-Paket (PITFALL)

Symptom: flutter pub add health_connect liefert health_connect-0.0.0 (im ~/.pub-cache/.../health_connect-0.0.0 nur ein leeres Verzeichnis), und der Build bricht mit dem AGP-namespace-Fehler.

Fakt: Es existiert KEIN offizielles, funktionsfähiges health_connect-Flutter-Paket auf pub.dev. Googles Health-Connect-Integration ist ein GitHub-Beispiel, das das Android-SDK nativ bundelt — nicht als veröffentlichtes pub-Paket gepflegt. health_connect/health_connect_android auf pub.dev sind leere Platzhalter.

Konsequenz für PersoEnt: Google-Gesundheitsdaten sind NICHT über ein magisches pub.dev-Paket abrufbar. Der echte Weg erfordert nativen Android-Health-Connect-Code (SDK-Binding) — das skizzierte der Nutzer als langfristige "PersoEnt als App"-Entscheidung; vorerst liefert die APK Login+Dashboard, Health-Import ist separat zu bauen. Siehe auch references/persoent-google-health-strategy.md (Google-Fit-REST deprecated, Health Connect nur Android-nativ, kein Server-REST-Sync).

6. Gate + Build

flutter analyze          # vorher: fängt unbenutzte Imports / falsche Klassennamen
flutter build apk --release
  • APK: build/app/outputs/flutter-apk/app-release.apk (~22MB)
  • Erster Gradle-Build dauert lange (Downloads). Nutze langen Timeout.
  • test/widget_test.dart muss zum neuen Code passen (Default referenziert MyApp).

7. Zum Download bereitstellen (VPS)

mkdir -p /var/www/<projekt>/html/app
cp build/app/outputs/flutter-apk/app-release.apk /var/www/<projekt>/html/app/<Name>-Android.apk
chown -R www-data:www-data /var/www/<projekt>/html/app/
# Test:
curl -s -o /dev/null -w "%{http_code}" "https://<domain>/app/<Name>-Android.apk"   # 200

8. 🔥 Google-Sign-In Fehlercode 10 (PITFALL)

Symptom in der App (Nutzerscreenshot): PlatformException(sign_in_failed, [google_sign_in] 10: null, null). Fehlercode 10 = OAuth-Client-Konfiguration fehlt/unverifiziert:

  • Dem Google-Cloud-Projekt fehlt der Android-OAuth-Client, oder
  • der SHA-1-Fingerprint der App ist dort nicht hinterlegt.

Fix (Nutzer-Einbindung nötig, nur deren Konto kann das):

  1. SHA-1 aus der gebauten APK extrahieren und eintragen:
    keytool -printcert -jarfile app-release.apk | grep SHA1
    
  2. Google-Cloud → Credentials → OAuth-Client "Android" mit diesem SHA-1 anlegen.
  3. Die generierte Client-ID in android/app/src/main/AndroidManifest.xml als <meta-data android:name="com.google.android.gms.auth.API_KEY" .../>-Block eintragen, APK neu bauen.

9. 📸 Nutzer-Screenshots auswerten (Handy-Foto) ohne vision-Tool

Wenn der Nutzer einen Screenshot schickt und kein vision_analyze-Tool verfügbar ist, lässt sich der Text (Fehlermeldungen) per Tesseract-OCR auslesen:

tesseract /root/.hermes/cache/images/<img>.jpg -  2>/dev/null   # Text auf stdout

Weg: browser_get_images liefert keine lokalen Dateien → stattdessen file <pfad> (Maße bestätigen) + tesseract zum Extrahieren von Fehlertext. Liefert z.B. PlatformException(...)-Zeilen — genug, um die Diagnose (Code 10, etc.) zu stellen. Hinweis: tesseract ist auf Ubuntu oft vorinstalliert (/usr/bin/tesseract).

Referenzen

  • references/persoent-apk-2026-08-07.md — Session-Transcript: voller Verlauf, Versionen, Fehlerbilder
  • references/persoent-google-health-strategy.md — PersoEnt: Google-Gesundheitsdaten-Strategie (Fit-REST deprecated, Health-Connect nur nativ; Detektiv-Korrelations-Analytik)
  • references/persoent-cost-tracking.md — PersoEnt/Mesh-Kosten-Tracking + Budget-BREMSE (OpenRouter): mesh-cost-track.sh (stündlich, je Agent) + mesh-cost-break.py (kill_switches bei Deckel) + Agent-Poller-Guard (PAUSED → keine Task-Übernahme), E2E-getestet. PITFALLs: DREI OpenRouter-Kostenquellen unterscheiden (/auth/key usage≠Credits, /credits total_usage=USD verbindlich, Body-usage.cost); Usage KUMULATIV → tag-übergreifendes Delta (letzter-heute − letzter-gestern, max(0,·) gegen Reset), sonst endlos PAUSED; DeepSeek V4 Pro = 64% (Bremsen auf Modell-Ebene via hermes config set model.providers.openrouter.blocked_models, Singular model.); Master-exempt von PAUSED. FINALER NUTZER-COST-MODEL (ab 08-08 ersetzt Monats-Cap): 1$/Tag/Agent hart, solange Credits da, KEIN Team-Monats-Stopp, Guthaben-0→Stopp.
  • references/hermes-config-ops.md — Hermes-System-Operation (VPS/Master): Config NIE via patch — immer hermes config set; approvals.mode=auto (allowlist bleibt hart); BACKUP-ONLY-Regel (.bak vor jeder Änderung → keine extra Freigabe); Memory-Limits (4400/2750, verdoppelt); „Wir, nicht du" Team-Pflicht bei Kernsystemen.