{"platform":{"slug":"react-native","platform":"React Native","documentationVersion":"v2.0.0","officialDocumentationUrl":"https://developer.mappls.com/documentation/sdk/react-native-sdk/","repositoryGuideSlugs":["mappls-react-native-sdk"],"supportedComponents":["Map SDK 2.0.2","Place Search Widget 2.0.0","Direction Widget 2.0.1","Nearby UI Widget 2.0.0","GeoFence Widget 2.0.0"],"lifecycleOwner":"One focused screen owns the native Promise, bridge generation, AppState changes, cancellation, and normalized JavaScript result.","returnBoundary":"Parse unknown bridge data into a versioned TypeScript value; do not store an opaque native result object.","cancellationBoundary":"Promise rejection, native cancellation, screen blur/unmount, bridge reload, and malformed data are typed separately.","credentialBoundary":"Configure both native applications with their own issued files and identities. No privileged REST credential belongs in JavaScript or the bundle.","productionChecks":["Public repository and developer-documentation version drift is resolved before dependency pinning","Peer native SDK versions are compatible","Only the focused mounted screen accepts a Promise result","Bridge data is schema-validated","Fast Refresh and native recreation do not double-commit"],"scaffold":{"language":"typescript","label":"TypeScript host contract","code":"type PlaceSelection = { version: 1; mapplsPin: string; label: string };\n\ninterface MapplsPlaceWidget {\n  selectPlace(): Promise<unknown>;\n}\n\nasync function choose(widget: MapplsPlaceWidget, generation: number) {\n  const value = await widget.selectPlace();\n  if (!isFocused() || generation !== currentGeneration()) return;\n  if (!isPlaceSelection(value)) throw new Error(\"invalid_widget_result\");\n  commitCandidate(value); // Store normalized data, never the opaque native object.\n}\n\nfunction isPlaceSelection(value: unknown): value is PlaceSelection {\n  const item = value as Partial<PlaceSelection> | null;\n  return item?.version === 1 && /^[A-Za-z0-9]{6}$/.test(item.mapplsPin ?? \"\") && typeof item.label === \"string\";\n}"},"verifiedAt":"2026-08-17","repositoryObservation":{"documentationVersion":"v2.0.1","supportedComponents":["Map SDK 2.0.3","Place Search Widget 2.0.1","Direction Widget 2.0.2","Nearby UI Widget 2.0.1","GeoFence Widget 2.0.1"],"sourceUrl":"https://github.com/mappls-api/mappls-react-native-sdk","observedAt":"2026-08-17","boundary":"The public repository main branch is newer than the current developer-documentation root. Confirm the released package, native peer versions, and selected widget guide before pinning dependencies."}},"capability":{"slug":"feedback","title":"Feedback UI","stateModel":"draft","durableIdentity":"Application feedback draft and attributable submission/reconciliation identity","platforms":{"android":{"availability":"published","component":"Feedback UI","version":"4.0.0","documentationUrl":"https://developer.mappls.com/documentation/sdk/android/"},"ios":{"availability":"published","component":"MapplsFeedbackUIKit","version":"3.0.0","documentationUrl":"https://developer.mappls.com/documentation/sdk/ios-sdk/"},"flutter":{"availability":"not-listed-in-current-overview","component":null,"version":null,"documentationUrl":"https://developer.mappls.com/documentation/sdk/flutter-sdk/"},"react-native":{"availability":"not-listed-in-current-overview","component":null,"version":null,"documentationUrl":"https://developer.mappls.com/documentation/sdk/react-native-sdk/"}}},"implementation":{"availability":"not-listed-in-current-overview","component":null,"version":null,"documentationUrl":"https://developer.mappls.com/documentation/sdk/react-native-sdk/"},"readiness":"selection-required","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 application feedback draft and attributable submission/reconciliation identity before committing."},{"state":"committed","owner":"Application repository","evidence":"Persist the normalized selection/draft with version, actor, source, and audit event."}],"stateOwnership":["One focused screen owns the native Promise, bridge generation, AppState changes, cancellation, and normalized JavaScript result.","Parse unknown bridge data into a versioned TypeScript value; do not store an opaque native result object.","Promise rejection, native cancellation, screen blur/unmount, bridge reload, and malformed data are typed separately.","The durable record is application feedback draft and attributable submission/reconciliation identity; never retain a provider view/controller or opaque bridge result."],"acceptanceTests":["Public repository and developer-documentation version drift is resolved before dependency pinning","Peer native SDK versions are compatible","Only the focused mounted screen accepts a Promise result","Bridge data is schema-validated","Fast Refresh and native recreation do not double-commit","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":"typescript","label":"TypeScript host contract","code":"type PlaceSelection = { version: 1; mapplsPin: string; label: string };\n\ninterface MapplsPlaceWidget {\n  selectPlace(): Promise<unknown>;\n}\n\nasync function choose(widget: MapplsPlaceWidget, generation: number) {\n  const value = await widget.selectPlace();\n  if (!isFocused() || generation !== currentGeneration()) return;\n  if (!isPlaceSelection(value)) throw new Error(\"invalid_widget_result\");\n  commitCandidate(value); // Store normalized data, never the opaque native object.\n}\n\nfunction isPlaceSelection(value: unknown): value is PlaceSelection {\n  const item = value as Partial<PlaceSelection> | null;\n  return item?.version === 1 && /^[A-Za-z0-9]{6}$/.test(item.mapplsPin ?? \"\") && typeof item.label === \"string\";\n}"}],"evidenceBoundary":"The current React Native v2.0.0 overview does not list Feedback UI. This is a selection-required gap, not evidence that the capability is impossible or that another platform package is compatible.","websiteUrl":"/tools/widgets/native?platform=react-native&capability=feedback"}