{"platform":{"slug":"ios","platform":"iOS","documentationVersion":"v2.0.2","officialDocumentationUrl":"https://developer.mappls.com/documentation/sdk/ios-sdk/","repositoryGuideSlugs":["mappls-ui-widget-ios-distribution","mappls-nearby-ui-ios-distribution","mappls-direction-ui-ios-distribution","mappls-geofence-ui-ios-distribution"],"supportedComponents":["MapplsUIWidget 2.0.1","MapplsNearbyUI 2.0.0","MapplsDirectionUI 2.0.0","MapplsGeofenceUI 2.0.0","MapplsFeedbackUIKit 3.0.0","MapplsMap 6.1.4"],"lifecycleOwner":"One presenting UIViewController or SwiftUI representable owns presentation, delegate lifetime, dismissal, and cancellation.","returnBoundary":"Copy the documented delegate result into a Sendable application value before dismissing the provider controller.","cancellationBoundary":"Interactive dismissal, explicit cancel, delegate error, scene deactivation, and no result are represented separately.","credentialBoundary":"Bundle only the issued iOS configuration files for the exact bundle identity. Server tokens and cross-application configuration do not belong in the app.","productionChecks":["Swift Package versions match the documented release family","The delegate cannot outlive its presenting owner","Interactive dismissal records cancellation once","Scene restoration never reuses a stale candidate"],"scaffold":{"language":"swift","label":"Swift host contract","code":"struct PlaceSelection: Sendable {\n    let mapplsPin: String\n    let label: String\n}\n\nprotocol MapplsPlaceWidget: Sendable {\n    @MainActor func selectPlace() async throws -> PlaceSelection?\n}\n\n@MainActor\nfunc choose(using widget: any MapplsPlaceWidget) async throws -> PlaceSelection? {\n    guard let selected = try await widget.selectPlace() else { return nil }\n    precondition(selected.mapplsPin.range(of: #\"^[A-Za-z0-9]{6}$\"#, options: .regularExpression) != nil)\n    return selected // Repository commit happens outside the provider controller.\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":"MapplsGeofenceUI","version":"2.0.0","documentationUrl":"https://developer.mappls.com/documentation/sdk/ios-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 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 presenting UIViewController or SwiftUI representable owns presentation, delegate lifetime, dismissal, and cancellation.","Copy the documented delegate result into a Sendable application value before dismissing the provider controller.","Interactive dismissal, explicit cancel, delegate error, scene deactivation, and no result are represented separately.","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":["Swift Package versions match the documented release family","The delegate cannot outlive its presenting owner","Interactive dismissal records cancellation once","Scene restoration never reuses a stale candidate","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":"swift","label":"Swift host contract","code":"struct PlaceSelection: Sendable {\n    let mapplsPin: String\n    let label: String\n}\n\nprotocol MapplsPlaceWidget: Sendable {\n    @MainActor func selectPlace() async throws -> PlaceSelection?\n}\n\n@MainActor\nfunc choose(using widget: any MapplsPlaceWidget) async throws -> PlaceSelection? {\n    guard let selected = try await widget.selectPlace() else { return nil }\n    precondition(selected.mapplsPin.range(of: #\"^[A-Za-z0-9]{6}$\"#, options: .regularExpression) != nil)\n    return selected // Repository commit happens outside the provider controller.\n}"}],"evidenceBoundary":"The current iOS overview lists MapplsGeofenceUI 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=ios&capability=geofence"}