feat(app): Background-GPS als opt-in Settings-Toggle
Stefan-Anforderung: GPS soll auch im Hintergrund liefern (Auto-Szenarien,
Handy-Tasche), aber NUR fuer Power-User die das bewusst aktivieren.
Mama-Tauglichkeit bleibt erhalten — Default AUS, keine Surprise-Permission.
Aenderungen:
AndroidManifest:
- ACCESS_BACKGROUND_LOCATION Permission
- FOREGROUND_SERVICE_LOCATION Permission
- AriaPlaybackService foregroundServiceType erweitert um |location
(vorher: mediaPlayback|microphone)
backgroundAudio.ts:
- Neuer Slot 'location' zwischen 'wake' und 'background' in der
Prioritaeten-Liste. Notification zeigt entsprechend.
gpsTracking.ts:
- isBackgroundGpsEnabled() / setBackgroundGpsEnabled() AsyncStorage-Helper
- ensureBackgroundLocationPermission() pruefte ACCESS_BACKGROUND_LOCATION
und oeffnet Android-Settings wenn fehlend (auf Android 10+ kann das
NICHT ueber den normalen Permission-Dialog angefordert werden)
- start(): wenn BG-GPS enabled, acquireBackgroundAudio('location') →
Foreground-Service hochziehen mit type=location
- stop(): releaseBackgroundAudio('location')
SettingsScreen.tsx:
- Neuer Toggle "GPS auch im Hintergrund" direkt unter dem
GPS-Tracking-Toggle, rot (#FF3B30) statt orange weil's eine stark
privacy-relevante Einstellung ist
- Erklaerungs-Text zu Android-Settings + Akku-Verbrauch
- Beim Aktivieren: Permission-Check, ggf. Android-Settings oeffnen
- Wenn Tracking bereits laeuft: neustart damit location-Slot greift
APK neu bauen erforderlich.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,9 +14,62 @@
|
||||
*/
|
||||
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { PermissionsAndroid, Platform, ToastAndroid } from 'react-native';
|
||||
import { Linking, PermissionsAndroid, Platform, ToastAndroid } from 'react-native';
|
||||
import Geolocation from '@react-native-community/geolocation';
|
||||
import rvs from './rvs';
|
||||
import { acquireBackgroundAudio, releaseBackgroundAudio } from './backgroundAudio';
|
||||
|
||||
// Opt-in Background-GPS — Settings-Toggle "GPS auch im Hintergrund".
|
||||
// Default AUS. Wenn AN: ACCESS_BACKGROUND_LOCATION-Permission noetig
|
||||
// (kann nicht ueber Standard-Dialog angefordert werden, User muss in
|
||||
// Android-Settings auf "Immer erlauben" gehen) + ForegroundService mit
|
||||
// foregroundServiceType=location wird hochgezogen.
|
||||
export const BG_GPS_STORAGE_KEY = 'aria_gps_background_enabled';
|
||||
|
||||
export async function isBackgroundGpsEnabled(): Promise<boolean> {
|
||||
try {
|
||||
const v = await AsyncStorage.getItem(BG_GPS_STORAGE_KEY);
|
||||
return v === 'true';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function setBackgroundGpsEnabled(enabled: boolean): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.setItem(BG_GPS_STORAGE_KEY, String(enabled));
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** Prueft ob ACCESS_BACKGROUND_LOCATION gewaehrt ist und oeffnet sonst die
|
||||
* Android-App-Settings damit der User "Immer erlauben" auswaehlen kann.
|
||||
* Returns true wenn permission ok, false wenn User Settings oeffnen muss. */
|
||||
export async function ensureBackgroundLocationPermission(): Promise<boolean> {
|
||||
if (Platform.OS !== 'android') return true;
|
||||
try {
|
||||
const granted = await PermissionsAndroid.check(
|
||||
'android.permission.ACCESS_BACKGROUND_LOCATION' as any,
|
||||
);
|
||||
if (granted) return true;
|
||||
// Erst FINE_LOCATION anfordern falls noch nicht da
|
||||
const fine = await PermissionsAndroid.request(
|
||||
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
|
||||
);
|
||||
if (fine !== PermissionsAndroid.RESULTS.GRANTED) return false;
|
||||
// Ab Android 10+ kann BACKGROUND_LOCATION NICHT ueber den normalen
|
||||
// PermissionsAndroid.request abgefragt werden — User muss in Settings
|
||||
// auf "Immer erlauben" wechseln. Wir oeffnen die App-Settings-Seite.
|
||||
ToastAndroid.show(
|
||||
'Bitte in Android-Einstellungen unter Standort "Immer erlauben" auswaehlen',
|
||||
ToastAndroid.LONG,
|
||||
);
|
||||
Linking.openSettings();
|
||||
return false;
|
||||
} catch (e) {
|
||||
console.warn('[gps-track] BG-Permission-Check fehlgeschlagen:', e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
type Listener = (active: boolean) => void;
|
||||
|
||||
@@ -86,6 +139,14 @@ class GpsTrackingService {
|
||||
ToastAndroid.show('GPS-Tracking: Berechtigung abgelehnt', ToastAndroid.LONG);
|
||||
return false;
|
||||
}
|
||||
// Background-GPS opt-in: wenn aktiv, ForegroundService mit type=location
|
||||
// hochziehen. Brauche ACCESS_BACKGROUND_LOCATION (User muss in Android-
|
||||
// Settings 'Immer erlauben' aktivieren). Wenn die fehlt, watchPosition
|
||||
// liefert im Hintergrund keine Updates (nur Heartbeat sendet alte Werte).
|
||||
const bgEnabled = await isBackgroundGpsEnabled();
|
||||
if (bgEnabled) {
|
||||
try { await acquireBackgroundAudio('location'); } catch {}
|
||||
}
|
||||
try {
|
||||
this.watchId = Geolocation.watchPosition(
|
||||
(pos) => {
|
||||
@@ -142,6 +203,8 @@ class GpsTrackingService {
|
||||
clearInterval(this.heartbeatTimer);
|
||||
this.heartbeatTimer = null;
|
||||
}
|
||||
// Location-Foreground-Service-Slot freigeben (falls vorher acquired)
|
||||
try { releaseBackgroundAudio('location'); } catch {}
|
||||
this.active = false;
|
||||
this.lastChangeAt = Date.now();
|
||||
this.notify();
|
||||
|
||||
Reference in New Issue
Block a user