Skip to content

fix: recover missed messages on mobile app resume#1529

Open
kuu-26 wants to merge 1 commit intoValour-Software:mainfrom
kuu-26:fix/mobile-resume-message-recovery
Open

fix: recover missed messages on mobile app resume#1529
kuu-26 wants to merge 1 commit intoValour-Software:mainfrom
kuu-26:fix/mobile-resume-message-recovery

Conversation

@kuu-26
Copy link
Copy Markdown
Contributor

@kuu-26 kuu-26 commented Apr 18, 2026

Problem

When the mobile app is reopened after being in the background, messages that arrived during the background period were not loading. Users had to manually switch channels or restart the app to see new messages.

Root Cause

Two issues were identified:

1. Missing lifecycle hooks (iOS & MacCatalyst)

The AppLifecycle.NotifyResumed() event never fired on iOS or MacCatalyst because neither platform had native lifecycle callbacks wired up. Only Android had OnResumeNotifyResumed(). Without the Resumed event, BrowserUtils.OnRefocus() never triggered, and ChatWindowComponent.OnBrowserFocused() never ran on those platforms.

Android also lacked a Backgrounded notification.

2. Race condition on resume

Even on Android where the lifecycle event did fire, there was a race condition. The flow was:

  1. AppLifecycle.NotifyResumed()BrowserUtils.OnRefocus()NodeService.CheckConnections() + Focused.Invoke()
  2. ChatWindowComponent.OnBrowserFocused()RecoverMissedMessages() immediately

CheckConnections() kicks off an async SignalR reconnection, but RecoverMissedMessages() runs immediately after without waiting for the reconnection to complete. The recovery API call could return before the server re-joins the channel, causing it to miss messages that arrived during the reconnection gap.

Changes

  • iOS AppDelegate: Add OnActivatedNotifyResumed() and DidEnterBackgroundNotifyBackground()
  • MacCatalyst AppDelegate: Same lifecycle hooks as iOS
  • Android MainActivity: Add OnPauseNotifyBackground()
  • AppLifecycle: Add Backgrounded event and NotifyBackground() method
  • ChatWindowComponent.OnBrowserFocused(): Wait up to 5 seconds for the relevant node to finish reconnecting before calling RecoverMissedMessages(). If the reconnect takes longer, log a warning and proceed anyway.

Testing

  • Build succeeds with 0 errors
  • Android: OnResume/OnPause lifecycle hooks verified
  • iOS: OnActivated/DidEnterBackground hooks added (matching standard Xamarin/MAUI patterns)
  • MacCatalyst: Same as iOS

Files Changed

  • Valour/Client.Maui/Platforms/Android/MainActivity.cs
  • Valour/Client.Maui/Platforms/iOS/AppDelegate.cs
  • Valour/Client.Maui/Platforms/MacCatalyst/AppDelegate.cs
  • Valour/Client/AppLifecycle.cs
  • Valour/Client/Components/Windows/ChannelWindows/ChatWindowComponent.razor

When the mobile app is reopened after being in the background, messages
that arrived during the background period were not loading. This was
caused by two issues:

1. Missing lifecycle hooks: iOS and MacCatalyst had no native lifecycle
   callbacks, so AppLifecycle.NotifyResumed() never fired on those
   platforms. Android only fired Resumed but not Backgrounded.

2. Race condition: OnBrowserFocused() would call RecoverMissedMessages()
   immediately, but the SignalR reconnection triggered by
   CheckConnections() is async. The recovery query could complete before
   the connection was re-established, returning stale data and missing
   messages that arrived during the reconnection gap.

Fixes:
- Add OnActivated/DidEnterBackground lifecycle hooks to iOS AppDelegate
- Add OnActivated/DidEnterBackground lifecycle hooks to MacCatalyst AppDelegate
- Add OnPause/NotifyBackground to Android MainActivity
- Add Backgrounded event to AppLifecycle
- Add reconnection wait logic in OnBrowserFocused() that waits up to 5
  seconds for the node to finish reconnecting before recovering messages
@kuu-26 kuu-26 requested a review from a team as a code owner April 18, 2026 13:44
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