{"platform":{"slug":"flutter","platform":"Flutter","documentationVersion":"v2.0.1","officialDocumentationUrl":"https://developer.mappls.com/documentation/sdk/flutter-sdk/","repositoryGuideSlugs":["mappls-flutter-sdk"],"supportedComponents":["Map SDK 2.0.5","Place Search Widget 2.0.0","Direction Widget 2.0.0","Nearby Widget 2.0.0"],"lifecycleOwner":"One route/widget state owns the MethodChannel launch Future, mounted check, cancellation, and application commit.","returnBoundary":"Validate the returned platform value, Mappls Pin, and request generation before updating Dart state.","cancellationBoundary":"A null result, PlatformException, route disposal, background interruption, and user cancellation are not interchangeable.","credentialBoundary":"Use the platform-specific Android/iOS configuration files associated with the final application identities; Web configuration is a separate browser boundary.","productionChecks":["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"],"scaffold":{"language":"dart","label":"Dart host contract","code":"final class PlaceSelection {\n  const PlaceSelection(this.mapplsPin, this.label);\n  final String mapplsPin;\n  final String label;\n}\n\nabstract interface class MapplsPlaceWidget {\n  Future<PlaceSelection?> selectPlace();\n}\n\nFuture<void> choose(MapplsPlaceWidget widget) async {\n  final generation = ++_launchGeneration;\n  final selected = await widget.selectPlace();\n  if (!mounted || generation != _launchGeneration || selected == null) return;\n  if (!RegExp(r'^[A-Za-z0-9]{6}$').hasMatch(selected.mapplsPin)) throw const FormatException('invalid_mappls_pin');\n  setState(() => _selected = selected); // Persist through the app repository on submit.\n}"},"verifiedAt":"2026-08-17"},"capability":{"slug":"place-search","title":"Place search and picker","stateModel":"selection","durableIdentity":"Mappls Pin plus application-owned display label","platforms":{"android":{"availability":"published","component":"Place Search Widget","version":"3.0.2","documentationUrl":"https://developer.mappls.com/documentation/sdk/android/"},"ios":{"availability":"published","component":"MapplsUIWidget","version":"2.0.1","documentationUrl":"https://developer.mappls.com/documentation/sdk/ios-sdk/"},"flutter":{"availability":"published","component":"Place Search Widget","version":"2.0.0","documentationUrl":"https://developer.mappls.com/documentation/sdk/flutter-sdk/"},"react-native":{"availability":"published","component":"Place Search Widget","version":"2.0.0","documentationUrl":"https://developer.mappls.com/documentation/sdk/react-native-sdk/"}}},"implementation":{"availability":"published","component":"Place Search Widget","version":"2.0.0","documentationUrl":"https://developer.mappls.com/documentation/sdk/flutter-sdk/"},"readiness":"source-ready","lifecycle":[{"state":"idle","owner":"Application screen","evidence":"No provider controller, route, Promise, delegate, or listener is active."},{"state":"launching","owner":"Platform adapter","evidence":"One generation ID binds configuration, owner, and launch time."},{"state":"active","owner":"Provider widget under host lifecycle","evidence":"Background, recreation, close, and duplicate-launch behavior are observable."},{"state":"returned / cancelled / failed","owner":"Platform adapter","evidence":"Exactly one typed terminal result wins; late results are ignored."},{"state":"candidate","owner":"Application domain","evidence":"Validate and normalize mappls pin plus application-owned display label before committing."},{"state":"committed","owner":"Application repository","evidence":"Persist the normalized selection/draft with version, actor, source, and audit event."}],"stateOwnership":["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 mappls pin plus application-owned display label; never retain a provider view/controller or opaque bridge result."],"acceptanceTests":["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"],"samples":[{"language":"dart","label":"Dart host contract","code":"final class PlaceSelection {\n  const PlaceSelection(this.mapplsPin, this.label);\n  final String mapplsPin;\n  final String label;\n}\n\nabstract interface class MapplsPlaceWidget {\n  Future<PlaceSelection?> selectPlace();\n}\n\nFuture<void> choose(MapplsPlaceWidget widget) async {\n  final generation = ++_launchGeneration;\n  final selected = await widget.selectPlace();\n  if (!mounted || generation != _launchGeneration || selected == null) return;\n  if (!RegExp(r'^[A-Za-z0-9]{6}$').hasMatch(selected.mapplsPin)) throw const FormatException('invalid_mappls_pin');\n  setState(() => _selected = selected); // Persist through the app repository on submit.\n}"}],"evidenceBoundary":"The current Flutter overview lists Place Search 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.","websiteUrl":"/tools/widgets/native?platform=flutter&capability=place-search"}