Android, iOS, Flutter, and React Native remain distinct release and lifecycle boundaries.
One capability. Four runtimes. Six lifecycle states.
Choose the exact mobile path you are shipping. The matrix preserves current version evidence, exposes missing overview coverage, and makes the host application—not the provider UI—the owner of durable state.
Place search, nearby, directions, geofence, and feedback are evaluated independently.
Every pairing is represented, including gaps in the current first-party overview.
The remaining 3 paths require product selection—not a guessed package.
Directions UI for Flutter
- Documentation
- v2.0.1
- Component
- Direction Widget
- Version
- 2.0.0
- State model
- session
The current Flutter overview lists Direction Widget 2.0.0 under documentation v2.0.1. Confirm the exact package, configuration, callback schema, and entitlement in the selected guide before binding the adapter.
Twenty paths. Every gap visible.
“Not listed” means the current overview does not establish a package. It does not mean the capability is impossible, and it never licenses reuse of another platform’s package.
Make every return, cancellation, and late callback explainable.
The generated scaffold deliberately stops at an application-owned candidate. Your repository decides whether and how that candidate becomes durable.
idle
No provider controller, route, Promise, delegate, or listener is active.
launching
One generation ID binds configuration, owner, and launch time.
active
Background, recreation, close, and duplicate-launch behavior are observable.
returned / cancelled / failed
Exactly one typed terminal result wins; late results are ignored.
candidate
Validate and normalize application route request/revision identity; provider ui is not a navigation session before committing.
committed
Persist the normalized selection/draft with version, actor, source, and audit event.
final class PlaceSelection {
const PlaceSelection(this.mapplsPin, this.label);
final String mapplsPin;
final String label;
}
abstract interface class MapplsPlaceWidget {
Future<PlaceSelection?> selectPlace();
}
Future<void> choose(MapplsPlaceWidget widget) async {
final generation = ++_launchGeneration;
final selected = await widget.selectPlace();
if (!mounted || generation != _launchGeneration || selected == null) return;
if (!RegExp(r'^[A-Za-z0-9]{6}$').hasMatch(selected.mapplsPin)) throw const FormatException('invalid_mappls_pin');
setState(() => _selected = selected); // Persist through the app repository on submit.
}The widget is a collaborator, not your database.
One route/widget state owns the MethodChannel launch Future, mounted check, cancellation, and application commit.
Validate the returned platform value, Mappls Pin, and request generation before updating Dart state.
A null result, PlatformException, route disposal, background interruption, and user cancellation are not interchangeable.
The durable record is application route request/revision identity; provider ui is not a navigation session; never retain a provider view/controller or opaque bridge result.
Test the lifecycle you cannot demo.
Happy-path selection proves almost nothing about a production mobile integration.
Android and iOS plugin versions are resolved by one lockfile
Every awaited result checks mounted/generation
PlatformException is mapped to a typed UI state
A late result cannot update a disposed route
Permission/configuration denied
Offline and slow provider response
Cancel before and after a candidate appears
Host edit invalidates a stale selection
Duplicate callback/Promise result commits once
Accessibility, focus return, and a non-widget fallback