feat(app): Hintergrund-Modus — App laeuft weiter wenn minimiert
Bisher pausierte Android nach ~30s im Hintergrund die JS-Engine.
WebSocket schlief ein, Trigger-Replies vom Brain kamen nicht durch,
Timer-Erinnerungen feuerten in der App nicht obwohl im Brain
ausgeloest. Nach laengerer Hintergrund-Pause warf Android den
Prozess ganz raus → beim Wiedereroeffnen Cold-Start, sah aus wie Crash.
Loesung: Foreground-Service mit persistenter Notification — die ist
ohnehin schon da fuer TTS/Mic-Aktivitaet (`AriaPlaybackService`).
Wir erweitern das Slot-System um einen `background`-Slot der dauerhaft
aktiv ist (Settings-Toggle, default an). Notification zeigt "ARIA aktiv
— Hintergrund-Modus" wenn nichts spezifisches laeuft, escaliert zu
"ARIA spricht/hoert" bei TTS/Mic. Tap → App.
Drei Dateien:
- services/backgroundAudio.ts: 'background' als 4. Slot (niedrigste
Prio, Fallback-Notification). Bestehende tts/rec/wake unveraendert.
- App.tsx: beim Start `acquireBackgroundAudio('background')` aufrufen
wenn Settings nicht explizit deaktiviert. Plus POST_NOTIFICATIONS-
Permission-Request (Android 13+).
- screens/SettingsScreen.tsx: neuer Toggle in Allgemein-Section.
Plus Hinweis auf Android-Akku-Optimierung-Whitelist falls trotzdem
was klemmt (manche Hersteller-ROMs killen aggressiv).
AndroidManifest unveraendert — foregroundServiceType="mediaPlayback|
microphone" deckt unseren Use-Case ab (ARIA spielt regelmaessig TTS
ab, was den Type rechtfertigt). Service stoppt sich selbst wenn alle
Slots leer sind, das passiert nur wenn der User in Settings den
Hintergrund-Modus deaktiviert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+39
-1
@@ -6,7 +6,8 @@
|
||||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { StatusBar, StyleSheet } from 'react-native';
|
||||
import { PermissionsAndroid, Platform, StatusBar, StyleSheet } from 'react-native';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { NavigationContainer, DefaultTheme } from '@react-navigation/native';
|
||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||
|
||||
@@ -14,6 +15,7 @@ import ChatScreen from './src/screens/ChatScreen';
|
||||
import SettingsScreen from './src/screens/SettingsScreen';
|
||||
import rvs from './src/services/rvs';
|
||||
import { initLogger, installGlobalCrashReporter } from './src/services/logger';
|
||||
import { acquireBackgroundAudio } from './src/services/backgroundAudio';
|
||||
|
||||
// --- Navigation ---
|
||||
|
||||
@@ -61,6 +63,42 @@ const App: React.FC = () => {
|
||||
};
|
||||
initConnection();
|
||||
|
||||
// Hintergrund-Modus: Foreground-Service starten damit JS-Engine +
|
||||
// WebSocket auch ueberleben wenn die App im Hintergrund ist.
|
||||
// Trigger-Replies, Reconnects, Timer-Erinnerungen kommen sonst nicht
|
||||
// durch weil Android nach ~30s die JS-Engine pausiert.
|
||||
//
|
||||
// Default an, kann in Settings → Hintergrund-Modus deaktiviert werden.
|
||||
// Braucht POST_NOTIFICATIONS Permission ab Android 13.
|
||||
const initBackground = async () => {
|
||||
const setting = await AsyncStorage.getItem('aria_background_mode');
|
||||
if (setting === 'false') {
|
||||
console.log('[App] Hintergrund-Modus deaktiviert (Settings)');
|
||||
return;
|
||||
}
|
||||
// Permission fuer die persistente Notification
|
||||
if (Platform.OS === 'android' && Platform.Version >= 33) {
|
||||
try {
|
||||
await PermissionsAndroid.request(
|
||||
'android.permission.POST_NOTIFICATIONS' as any,
|
||||
{
|
||||
title: 'Hintergrund-Modus',
|
||||
message: 'ARIA zeigt eine Notification damit Trigger und Reconnects auch laufen wenn die App im Hintergrund ist.',
|
||||
buttonPositive: 'Erlauben',
|
||||
buttonNegative: 'Spaeter',
|
||||
},
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
try {
|
||||
await acquireBackgroundAudio('background');
|
||||
console.log('[App] Hintergrund-Modus aktiv');
|
||||
} catch (err: any) {
|
||||
console.warn('[App] Hintergrund-Modus konnte nicht starten:', err?.message || err);
|
||||
}
|
||||
};
|
||||
initBackground();
|
||||
|
||||
// Beim Beenden: Verbindung sauber trennen
|
||||
return () => {
|
||||
rvs.disconnect();
|
||||
|
||||
Reference in New Issue
Block a user