Skip to content

[iOS] Navigation event listeners do not fire callbacks - EventChannel bridge issue #505

@orestislef

Description

@orestislef

Platform: iOS
Package version: google_navigation_flutter 0.6.5
Device/Simulator: Physical iPhone (iOS 18)
Issue type: Bug

Description

Navigation event listeners (NavInfo, RoadSnappedLocation, RouteChanged, etc.) do not fire callbacks on iOS, despite guidance running successfully and Google's native UI displaying turn-by-turn navigation correctly.

Steps to Reproduce

  1. Initialize navigation session
  2. Register event listeners (NavInfo, RoadSnappedLocation, etc.) using the standard API
  3. Set destination and start guidance
  4. Verify guidance is running via GoogleMapsNavigator.isGuidanceRunning() (returns true)
  5. Begin moving or simulate movement along route

Expected Behavior

Event listeners should fire callbacks as navigation state changes:

  • setNavInfoListener should fire when approaching turns, route changes occur
  • setRoadSnappedLocationUpdatedListener should fire on location updates
  • setOnRemainingTimeOrDistanceChangedListener should fire as time/distance changes
  • Other navigation events should fire as documented

Actual Behavior

No listener callbacks fire on iOS. All listeners register successfully without errors, but callbacks never execute. The StreamSubscription objects are returned successfully, but no events are emitted through the EventChannel.

Evidence

What works:

  • Google's native navigation UI displays turn-by-turn instructions correctly
  • Route calculation succeeds (status: NavigationRouteStatus.statusOk)
  • Guidance starts successfully (isGuidanceRunning() returns true)
  • Voice guidance works
  • Polling via getCurrentTimeAndDistance() returns correct data
  • Map displays route and updates position correctly

What doesn't work:

  • setNavInfoListener - callback never fires
  • setRoadSnappedLocationUpdatedListener - callback never fires
  • setOnRouteChangedListener - callback never fires
  • setOnRemainingTimeOrDistanceChangedListener - callback never fires
  • setSpeedingUpdatedListener - callback never fires
  • setOnArrivalListener - callback never fires
  • setOnReroutingListener - callback never fires
  • setTrafficUpdatedListener - callback never fires

Code Sample

// Listeners registered before starting guidance
Future<void> setupListeners() async {
  _navInfoSubscription = GoogleMapsNavigator.setNavInfoListener(
    (navInfo) {
      // This callback NEVER fires on iOS
      print('NavInfo received: ${navInfo.navInfo}');
    },
    numNextStepsToPreview: 10,
  );

  _locationSubscription = await GoogleMapsNavigator.setRoadSnappedLocationUpdatedListener(
    (event) async {
      // This callback NEVER fires on iOS
      print('Location: ${event.location}');
    },
  );

  _timeDistanceSubscription = GoogleMapsNavigator.setOnRemainingTimeOrDistanceChangedListener(
    (event) {
      // This callback NEVER fires on iOS
      print('Time/Distance changed');
    },
    remainingTimeThresholdSeconds: 1,
    remainingDistanceThresholdMeters: 1,
  );
}

// Start guidance after listeners are set up
final routeStatus = await GoogleMapsNavigator.setDestinations(destinations);
await GoogleMapsNavigator.startGuidance();

final isRunning = await GoogleMapsNavigator.isGuidanceRunning();
print('Guidance running: $isRunning'); // Prints: true

// Wait for events... but they never arrive

Logs

flutter: Setting up navigation listeners
flutter: NavInfo listener registered
flutter: Location listener registered
flutter: Route changed listener registered
flutter: Time/Distance listener registered
flutter: ALL LISTENERS REGISTERED SUCCESSFULLY
flutter: Route calculation status: NavigationRouteStatus.statusOk
flutter: Route calculated successfully
flutter: Starting guidance...
flutter: Guidance started
flutter: isGuidanceRunning: true
flutter: Guidance is running - listeners should now fire

[Moving along route for 2 minutes - NO CALLBACKS FIRE]

// However, polling works:
final timeAndDistance = await GoogleMapsNavigator.getCurrentTimeAndDistance();
print('Distance: ${timeAndDistance.distance}m'); // Works - returns correct data

Diagnosis

The issue appears to be in the iOS EventChannel bridge between native code and Flutter. The native iOS Navigation SDK receives NavInfo data (proven by Google's native UI working correctly), but the Flutter plugin does not forward these events to Dart callbacks.

Comparison with official example app: The example app in the repository does not use setNavInfoListener for iOS, which suggests this feature may not be fully implemented or tested on iOS.

Workaround

Currently using polling as a workaround:

Timer.periodic(Duration(seconds: 1), (timer) async {
  try {
    final data = await GoogleMapsNavigator.getCurrentTimeAndDistance();
    // Use data.time and data.distance
  } catch (e) {
    // Handle error
  }
});

This provides ETA and distance but not turn-by-turn instructions, maneuvers, or other NavInfo data that is only available through the listener.

Request

Please investigate the iOS EventChannel implementation for navigation event listeners. All listener registration methods return StreamSubscription objects successfully, but events are not being emitted. This prevents developers from building custom navigation UIs on iOS while still being able to use Google's native UI as a fallback.

Environment

flutter doctor -v output:
[✓] Flutter (Channel stable, 3.24.5)
[✓] Xcode - develop for iOS and macOS (Xcode 16.2)
[✓] iOS device (iPhone - iOS 18)

Package:
google_navigation_flutter: ^0.6.5

iOS Deployment Target: 15.0

Additional Context

This issue affects production applications that need custom navigation UIs. While Google's native UI works well, many apps require branded/custom overlays with specific styling and additional information displays. The polling workaround provides basic ETA/distance but lacks access to turn instructions, maneuvers, remaining steps, and other critical NavInfo fields.

Metadata

Metadata

Assignees

Labels

priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions