{"platform":{"slug":"android","platform":"Android","documentationVersion":"v2.0.2","officialDocumentationUrl":"https://developer.mappls.com/documentation/sdk/android/","repositoryGuideSlugs":["mappls-android-sdk","mappls-android-compose-demo"],"supportedComponents":["Map SDK 9.0.3","Place Search Widget 3.0.2","Direction Widget 3.0.1","Nearby UI Widget 2.0.1","GeoFence Widget 2.0.0","Feedback UI 4.0.0"],"lifecycleOwner":"One Activity, Fragment, or Compose wrapper owns launch, callback registration, saved state, and disposal.","returnBoundary":"Translate the documented Activity/Fragment result into a small application selection before persisting it.","cancellationBoundary":"Back, close, process recreation, denied configuration, and an unavailable Activity are distinct outcomes.","credentialBoundary":"Use the updated post-August-2025 Android configuration files restricted to package and signing identity; never put a server credential in the APK.","productionChecks":["BoM/component versions resolve together","Debug and release signing identities are separately approved","Rotation and process death do not duplicate a commit","Fragment/Activity listeners are removed with their owner"],"scaffold":{"language":"kotlin","label":"Kotlin host contract","code":"data class PlaceSelection(val mapplsPin: String, val label: String)\n\ninterface MapplsPlaceWidget {\n    suspend fun selectPlace(): PlaceSelection? // null means deliberate cancellation\n}\n\nclass AddressDraft(private val widget: MapplsPlaceWidget) {\n    suspend fun choose(): PlaceSelection? = widget.selectPlace()?.also { selected ->\n        require(Regex(\"^[A-Za-z0-9]{6}$\").matches(selected.mapplsPin))\n        // Persist through the application repository, not a Fragment reference.\n    }\n}"},"verifiedAt":"2026-08-17"},"capability":{"slug":"geofence","title":"Geofence editor","stateModel":"draft","durableIdentity":"Versioned application geofence draft and provider rule identity after separate publication","platforms":{"android":{"availability":"published","component":"GeoFence Widget","version":"2.0.0","documentationUrl":"https://developer.mappls.com/documentation/sdk/android/"},"ios":{"availability":"published","component":"MapplsGeofenceUI","version":"2.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":"published","component":"GeoFence Widget","version":"2.0.0","documentationUrl":"https://developer.mappls.com/documentation/sdk/react-native-sdk/docs/v2.0.0/Geofence-Widget/"}}},"implementation":{"availability":"published","component":"GeoFence Widget","version":"2.0.0","documentationUrl":"https://developer.mappls.com/documentation/sdk/android/"},"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 versioned application geofence draft and provider rule identity after separate publication before committing."},{"state":"committed","owner":"Application repository","evidence":"Persist the normalized selection/draft with version, actor, source, and audit event."}],"stateOwnership":["One Activity, Fragment, or Compose wrapper owns launch, callback registration, saved state, and disposal.","Translate the documented Activity/Fragment result into a small application selection before persisting it.","Back, close, process recreation, denied configuration, and an unavailable Activity are distinct outcomes.","The durable record is versioned application geofence draft and provider rule identity after separate publication; never retain a provider view/controller or opaque bridge result."],"acceptanceTests":["BoM/component versions resolve together","Debug and release signing identities are separately approved","Rotation and process death do not duplicate a commit","Fragment/Activity listeners are removed with their owner","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":"kotlin","label":"Kotlin host contract","code":"data class PlaceSelection(val mapplsPin: String, val label: String)\n\ninterface MapplsPlaceWidget {\n    suspend fun selectPlace(): PlaceSelection? // null means deliberate cancellation\n}\n\nclass AddressDraft(private val widget: MapplsPlaceWidget) {\n    suspend fun choose(): PlaceSelection? = widget.selectPlace()?.also { selected ->\n        require(Regex(\"^[A-Za-z0-9]{6}$\").matches(selected.mapplsPin))\n        // Persist through the application repository, not a Fragment reference.\n    }\n}"}],"evidenceBoundary":"The current Android overview lists GeoFence Widget 2.0.0 under documentation v2.0.2. Confirm the exact package, configuration, callback schema, and entitlement in the selected guide before binding the adapter.","websiteUrl":"/tools/widgets/native?platform=android&capability=geofence"}