feat: section 4 — Android battery optimization prompt

One-time prompt on first launch (Android only) directing the user to
exclude bincio-rec from battery optimization. Uses the direct
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS system dialog with a fallback to
the general settings page for OEMs that block the direct intent.
Dismissal persisted in AsyncStorage so prompt never repeats.
This commit is contained in:
Davide Scaini
2026-06-03 09:09:51 +02:00
parent 5f12b2857d
commit 765efe288e
3 changed files with 39 additions and 2 deletions
+2
View File
@@ -4,6 +4,7 @@ import * as Notifications from 'expo-notifications';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { AppNavigator } from './src/navigation/AppNavigator';
import { requestNotificationPermissions } from './src/services/gps';
import { promptBatteryOptimizationIfNeeded } from './src/services/batteryOptimization';
// Show notifications even when the app is in the foreground (iOS suppresses by default)
Notifications.setNotificationHandler({
@@ -18,6 +19,7 @@ Notifications.setNotificationHandler({
export default function App() {
useEffect(() => {
requestNotificationPermissions();
promptBatteryOptimizationIfNeeded();
}, []);
return (
+2 -2
View File
@@ -117,9 +117,9 @@ Items below are what remains before v1 is shippable.
- [x] **Permission request**`requestNotificationPermissions()` called in `App.tsx` on mount; foreground notification handler set at module level so iOS shows banners while app is active
- [x] **Milestone tracker** — module-level `runningDistanceMeters` / `lastNotifiedKm` / `prevPoint` in `gps.ts`, reset on each `startGpsRecording()`; each incoming location adds haversine distance and fires a notification when a new km is crossed, gated on the `kmNotifications` AsyncStorage setting
### 4 — Android battery optimization prompt (12 hours)
### 4 — Android battery optimization prompt
- [ ] On first launch, detect if the app is affected by battery optimization (`expo-intent-launcher`) and show a one-time prompt directing the user to whitelist bincio-rec; persist dismissal in AsyncStorage so it only shows once
- [x] `src/services/batteryOptimization.ts` — Android-only, one-time prompt (dismissed flag in AsyncStorage); uses `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` intent to open the system dialog for bincio-rec directly; falls back to `IGNORE_BATTERY_OPTIMIZATION_SETTINGS` (general page) on OEMs that block the direct intent; called from `App.tsx` on mount alongside notification permission request
### 5 — Map (optional upgrade)
+35
View File
@@ -0,0 +1,35 @@
import { Platform, Alert } from 'react-native';
import * as IntentLauncher from 'expo-intent-launcher';
import AsyncStorage from '@react-native-async-storage/async-storage';
const PROMPT_SHOWN_KEY = 'batteryOptPromptShown';
export async function promptBatteryOptimizationIfNeeded(): Promise<void> {
if (Platform.OS !== 'android') return;
const shown = await AsyncStorage.getItem(PROMPT_SHOWN_KEY);
if (shown) return;
await AsyncStorage.setItem(PROMPT_SHOWN_KEY, 'true');
Alert.alert(
'Allow background GPS',
'To record accurately while the screen is off, bincio-rec needs to be excluded from battery optimization.\n\nTap "Open settings", find bincio-rec, and select "Don\'t optimize".',
[
{
text: 'Open settings',
onPress: () =>
IntentLauncher.startActivityAsync(
IntentLauncher.ActivityAction.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
{ data: 'package:com.bincio.rec' },
).catch(() =>
// Fallback: some OEMs don't support the direct intent — open the general page
IntentLauncher.startActivityAsync(
IntentLauncher.ActivityAction.IGNORE_BATTERY_OPTIMIZATION_SETTINGS,
),
),
},
{ text: 'Later', style: 'cancel' },
],
);
}