Skip to content

Add native location-provider override (setExternalLocation) - #1145

Open
trueshail wants to merge 1 commit into
mapbox:mainfrom
amusetechnologies:pr/external-location-provider
Open

trueshail wants to merge 1 commit into
mapbox:mainfrom
amusetechnologies:pr/external-location-provider

Conversation

@trueshail

@trueshail trueshail commented Sep 3, 2026

Copy link
Copy Markdown

Summary

Adds a way to drive the map puck from an externally-supplied location instead of the default GPS-only location engine — a custom LocationProvider/HeadingProvider on both mobile platforms, wired through a small setExternalLocation/clearExternalLocation API on the location settings.

Resolves #1085.

Updated for v3: this branch has been ported from the pre-v3 flat layout to the federated package structure introduced in #19427.

What's here

  • mapbox_maps_flutter_platform_interface: LocationSettingsPlatformInterface gains setExternalLocation/clearExternalLocation.
  • mapbox_maps_flutter: LocationSettingsManager forwards both to the platform implementation.
  • mapbox_maps_flutter_mobile (Dart): LocationSettings backs them with a hand-written MethodChannel. This is deliberately not Pigeon-generated — the Pigeon input specs for this plugin aren't published, only the generated output — so the channel is kept isolated from generated code.
  • mapbox_maps_flutter_mobile (iOS): ExternalLocationProvider.swift implements LocationProvider + HeadingProvider, registered via mapView.location.override(provider:).
  • mapbox_maps_flutter_mobile (Android): ExternalLocationProvider.kt implements LocationProvider, registered via mapView.location.setLocationProvider(...).
  • mapbox_maps_flutter_web: throws UnsupportedError. GL JS's GeolocateControl owns the puck position and exposes no location-provider override, so there is nothing to override.
  • Docs: doc comments on the facade (including a usage example) and a CHANGELOG entry. Happy to add prose to the docs site separately — the v3 README is a quickstart and no longer carries per-feature guide sections.

The override activates lazily on the first setExternalLocation call; clearExternalLocation restores the platform default provider (GPS). Until either is called, puck behavior is unchanged — this is purely additive.

floor is applied on iOS only, whose native Location type carries it. Android's LocationConsumer API has no floor concept, so it's dropped there; this is documented on the API.

Usage

// Start driving the puck from an external source.
mapboxMap.location.setExternalLocation(
  latitude: 37.775,
  longitude: -122.418,
  heading: 90.0,
  accuracy: 5.0,
);

// Later, hand the puck back to the platform's default provider (e.g. GPS).
mapboxMap.location.clearExternalLocation();

Motivation

Useful for apps that need to drive the puck from a custom positioning source — e.g. an indoor-positioning SDK while inside a mapped venue, falling back to GPS outdoors — without the platform's own location engine ever being in the loop. Per #1085, this is a capability others have asked for too.

Testing

  • flutter analyze across the workspace reports no new issues: 247 before and after this change, all pre-existing.
  • All four package suites pass (286 tests), including 3 new channel tests in mapbox_maps_flutter_mobile/test/external_location_test.dart and 3 new delegation tests in mapbox_maps_flutter/test/location_settings_test.dart.
  • The native sources are unchanged from the version previously verified on real iOS simulator and Android debug builds of the example app; LocationComponentController.kt and LocationController.swift are byte-identical between the 2.x and v3 trees, so the port moved them without modification. The example app has not been rebuilt against v3 as part of this port — worth a CI run before merge.

Note on API shape

I've added the two methods directly to LocationSettingsPlatformInterface, which makes them required for any implementer. If you'd prefer them optional (default implementations that throw, so out-of-tree platform implementations don't break), say the word and I'll restructure.

@trueshail
trueshail requested a review from a team as a code owner September 3, 2026 23:58
@trueshail
trueshail requested a review from evil159 September 3, 2026 23:58
@CLAassistant

CLAassistant commented Sep 3, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@trueshail
trueshail force-pushed the pr/external-location-provider branch 3 times, most recently from 8735c9b to 89ff52b Compare September 4, 2026 13:34
Adds a custom LocationProvider on both mobile platforms so the map puck
can be driven by an externally-supplied location instead of the default
GPS-only location engine. Useful when the location comes from an
indoor-positioning SDK, a simulation, or a vehicle's own sensors.

Resolves mapbox#1085.

- platform_interface: LocationSettingsPlatformInterface gains
  setExternalLocation/clearExternalLocation.
- mapbox_maps_flutter: LocationSettingsManager forwards both to the
  platform implementation.
- mobile (Dart): LocationSettings backs them with a hand-written
  MethodChannel, deliberately NOT Pigeon-generated -- this repo ships
  the generated Pigeon output but not the input specs, so the channel is
  kept isolated from generated code and easy to regenerate around.
- mobile (iOS): ExternalLocationProvider.swift implements
  LocationProvider + HeadingProvider, registered via
  mapView.location.override(provider:).
- mobile (Android): ExternalLocationProvider.kt implements
  LocationProvider, registered via mapView.location.setLocationProvider.
- web: throws UnsupportedError. GL JS's GeolocateControl owns the puck
  position and exposes no location-provider override.

The override activates lazily on the first setExternalLocation call, so
puck behaviour is unchanged until it is used; clearExternalLocation
restores the platform default provider (GPS).

floor is applied on iOS only, whose native Location type carries it;
Android's LocationConsumer API has no floor concept, so it is dropped
there.

Verified: flutter analyze reports no new issues (247 before and after,
all pre-existing), and all four package test suites pass (286 tests),
including 3 new channel tests in mobile and 3 new delegation tests in
the facade.

Ported to the v3 federated package layout; the original version of this
change targeted the pre-v3 flat layout on the 2.x line.
@trueshail
trueshail force-pushed the pr/external-location-provider branch from 89ff52b to 9d4c230 Compare September 21, 2026 15:32
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.

Support Location Override

2 participants