Skip to content

Fix Android support, add settings persistence, and clean up code#52

Open
Mihonarium wants to merge 3 commits intomainfrom
fix/code-quality-android-settings
Open

Fix Android support, add settings persistence, and clean up code#52
Mihonarium wants to merge 3 commits intomainfrom
fix/code-quality-android-settings

Conversation

@Mihonarium
Copy link
Copy Markdown
Owner

@Mihonarium Mihonarium commented Feb 25, 2026

Summary

Android Foreground Service (new)

  • Reliable background audio on Android: Created android-foreground-service Expo native module with a Kotlin ForegroundService using mediaPlayback type
  • Shows a minimal, silent persistent notification ("Sonic Compass is running" / current heading when backgrounded)
  • Config plugin auto-injects service declaration and FOREGROUND_SERVICE_MEDIA_PLAYBACK + POST_NOTIFICATIONS permissions into AndroidManifest.xml
  • JS bridge with platform guard (no-op on iOS)
  • Foreground service starts when audio initializes, stops on app cleanup
  • Notification updates with current heading every 2s when backgrounded

Previous fixes (still in this PR)

  • Fix Android support: Guard native BackgroundHaptics import with Platform.OS check, add proper Android vibration fallback
  • Fix audio mode: Change from DoNotMix to DuckOthers so the app doesn't kill other apps' audio
  • Add settings persistence: Save/load settings via AsyncStorage
  • Code quality cleanup: Remove duplicates in app.json, dead code, unused imports, fix stale closures
  • Restore setLastDir: Keeps track of last directional sound timestamp

Architecture

android-foreground-service/
├── expo-module.config.json     # platforms: ["android"]
├── package.json
├── src/
│   ├── index.js                # JS API: startService/stopService/updateNotification
│   └── module.js               # Platform guard (no-op on iOS)
├── android/
│   ├── build.gradle
│   └── src/main/java/.../
│       ├── AndroidForegroundServiceModule.kt   # Expo module bridge
│       └── CompassForegroundService.kt         # Android Service class
└── plugin/
    └── withForegroundService.js  # Config plugin for AndroidManifest

Test plan

  • Build and test on iOS - verify all existing functionality works unchanged
  • Build and test on Android - verify app launches, compass works, sounds play, vibration works
  • Critical: Test background mode on Android for 10+ minutes - audio and vibration should continue indefinitely
  • Verify persistent notification appears on Android when app is backgrounded
  • Verify notification shows current heading when backgrounded
  • Verify settings persist across app restarts on both platforms
  • Verify audio mixes properly with other apps (music, calls)

🤖 Generated with Claude Code

Mikhail Samin's Claude and others added 3 commits February 25, 2026 03:54
- Fix Android crash by guarding native BackgroundHaptics module import
  (iOS-only native code now falls back to no-op on Android)
- Add FOREGROUND_SERVICE permission for Android background audio
- Persist user settings (frequency, learning mode, vibration, offset)
  across app restarts using AsyncStorage
- Fix duplicate entries in app.json (UIBackgroundModes, UIRequiredDeviceCapabilities)
- Remove redundant useEffect hooks and fix stale closure in selectFrequency
- Remove broken <Text></Text> && JSX pattern
- Remove unused imports (Alert, Switch) and dead code (Battery/lowPower)
- Clean up whitespace and commented-out code
- Add CLAUDE.md with project documentation
- Update README to reflect completed TODOs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Restore setLastDir state that was incorrectly removed
- Fix silent failure: background vibration on Android was a no-op
  (BackgroundHaptics falls back to no-op on Android); now uses
  Vibration.vibrate(100) directly when in background on Android
- Fix Android audio mode: change DoNotMix to DuckOthers so compass
  cues don't kill other apps' audio (matches iOS MixWithOthers intent)
- Set shouldDuckAndroid: true so compass audio gracefully yields
  when other apps need audio focus
- Add type guard in loadSettings for corrupted AsyncStorage data
- Add Platform import for platform-specific vibration handling
- Document Android background audio limitation honestly in README
  and CLAUDE.md (expo-av lacks foreground service, OS may kill
  audio after 1-3 min)
- Shorten fallback vibration from 200ms to 100ms for crisper feel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create android-foreground-service Expo native module with:
- Kotlin ForegroundService (mediaPlayback type) with persistent notification
- Expo Modules API bridge exposing startService/stopService/updateNotification
- Config plugin injecting service declaration and permissions into AndroidManifest
- JS bridge with iOS no-op stubs

This prevents Android from killing the app under Doze mode, making
background audio and vibration work indefinitely instead of stopping
after 1-3 minutes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant