CI-Build: Kotlin aktivieren + Sync-Button mit Fehler-Feedback [apk]
Some checks failed
Build APK / build-apk (push) Failing after 3m21s

- build.yml: kotlin-android-Plugin (1.9.24) + JVM-Target 17 aktiviert — .kt-Dateien
  wurden vorher stillschweigend ignoriert (kein Kotlin-Compiler), NetDiagScannerPlugin
  fehlte im APK -> 'plugin not implemented' fuer alle nativen Scan-Methoden
- build.yml: MainActivity.java durch .kt ersetzen (rm + cat), vermeidet
  Klassenkollision und registriert das Plugin korrekt
- sync.svelte.ts: syncManual() -- gibt immer sichtbares Toast-Feedback
  (Fehler-Details, offline, nicht angemeldet, alles synchronisiert)
- AppHeader.svelte: Sync-Button ruft syncManual() statt syncNow()

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Eduard Wisch 2026-05-19 16:05:23 +02:00
parent 21cb06f219
commit 250e0f9eba
3 changed files with 64 additions and 13 deletions

View file

@ -42,11 +42,36 @@ jobs:
cp native-plugin/NetDiagScannerPlugin.kt "$PLUGIN_DST/"
cp native-plugin/Snmp.kt "$PLUGIN_DST/"
- name: MainActivity — Plugin registrieren
- name: Kotlin im Gradle-Build aktivieren
run: |
MAIN=android/app/src/main/java/de/data_it_solution/netdiag/MainActivity.kt
if ! grep -q 'NetDiagScannerPlugin' "$MAIN"; then
cat > "$MAIN" <<'KT'
# Das native Plugin ist Kotlin. Das von `cap add android` erzeugte
# App-Modul hat aber KEIN Kotlin aktiviert. Ohne kotlin-android-Plugin
# werden .kt-Dateien beim Build stillschweigend ignoriert (kein Fehler)
# -> NetDiagScannerPlugin landet nie im APK -> "plugin not implemented".
KOTLIN_VERSION=1.9.24
# 1. Kotlin-Gradle-Plugin auf Projektebene verfügbar machen
if ! grep -q 'kotlin-gradle-plugin' android/build.gradle; then
sed -i "/com.android.tools.build:gradle/a\\ classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:${KOTLIN_VERSION}\"" android/build.gradle
fi
# 2. Plugin im App-Modul anwenden + JVM-Target auf 17 (Java-Target von Capacitor 6)
APP=android/app/build.gradle
if ! grep -q 'kotlin-android' "$APP"; then
sed -i "/apply plugin: 'com.android.application'/a apply plugin: 'kotlin-android'" "$APP"
sed -i "/^android {/a\\ kotlinOptions { jvmTarget = '17' }" "$APP"
fi
# 3. Coroutines-Abhängigkeit (vom Plugin genutzt)
if ! grep -q 'kotlinx-coroutines-android' "$APP"; then
sed -i '/dependencies {/a \ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0"' "$APP"
fi
- name: MainActivity durch Kotlin-Variante ersetzen (Plugin registrieren)
run: |
PKG=android/app/src/main/java/de/data_it_solution/netdiag
# `cap add android` erzeugt MainActivity.java — die registriert das
# Plugin NICHT und würde mit unserer .kt-Klasse kollidieren (gleiche
# Klasse, gleiches Package). Also Java-Datei löschen, Kotlin schreiben.
rm -f "$PKG/MainActivity.java"
cat > "$PKG/MainActivity.kt" <<'KT'
package de.data_it_solution.netdiag
import android.os.Bundle
@ -59,14 +84,6 @@ jobs:
}
}
KT
fi
- name: Kotlin-Coroutines sicherstellen
run: |
GRADLE=android/app/build.gradle
if ! grep -q 'kotlinx-coroutines-android' "$GRADLE"; then
sed -i '/dependencies {/a \ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0"' "$GRADLE"
fi
- name: Capacitor sync
run: npx cap sync android

View file

@ -33,7 +33,7 @@
</div>
<button
class="flex items-center gap-1 rounded px-2 py-1 text-xs text-zinc-300 active:bg-zinc-800"
onclick={() => sync.syncNow()}
onclick={() => sync.syncManual()}
title="Synchronisieren"
>
<span class="h-2.5 w-2.5 rounded-full {dot}"></span>

View file

@ -10,6 +10,7 @@
import { Network } from '@capacitor/network';
import { ApiError, isLoggedIn, syncProtocol } from './api';
import { getDirtyProtocols, saveProtocol } from './db';
import { toast } from './toast.svelte';
type SyncStatus = 'idle' | 'syncing' | 'offline' | 'error';
@ -83,6 +84,39 @@ class SyncState {
await this.refreshPending();
this.status = 'idle';
}
/**
* Manueller Sync per Tap auf die Sync-Ampel im Header.
* Gibt IMMER sichtbares Feedback (Toast) der `syncNow()`-Hintergrundlauf
* bricht still ab, dadurch wirkte der Button vorher "tot".
*/
async syncManual(): Promise<void> {
if (!this.online) {
toast.show('Offline — keine Verbindung zum Server', 'info');
return;
}
if (!isLoggedIn()) {
toast.show('Nicht angemeldet — bitte erst einloggen', 'info');
return;
}
if (this.status === 'syncing') {
toast.show('Synchronisierung läuft bereits …', 'info');
return;
}
await this.refreshPending();
if (this.pendingCount === 0) {
toast.show('Alles synchronisiert', 'success');
return;
}
await this.syncNow();
if (this.status === 'error') {
toast.show(this.lastError || 'Sync fehlgeschlagen', 'error', 5000);
} else {
toast.show('Protokolle übertragen', 'success');
}
}
}
export const sync = new SyncState();