This guide covers the setup process for integrating Open Mobile Maps into your SwiftUI application using the declarative MapView component.
Requirements
- iOS 17.0+
- Xcode 15.0+
- Swift 5.9+
The SwiftUI MapView requires iOS 17.0 or later. For earlier iOS versions, use UIKit with MCMapView or wrap it using UIViewRepresentable.
Installation
Follow the same installation steps as the iOS setup guide using Swift Package Manager.
Basic setup
The SwiftUI MapView provides a declarative interface for displaying maps.
Import the framework
Import MapCore and SwiftUI in your view:import MapCore
import SwiftUI
Create camera state
Define a @State property for the camera:@State private var camera = MapView.Camera(
latitude: 46.962592372639634,
longitude: 8.378232525377973,
zoom: 1000000
)
The camera binding is bidirectional - it updates as users interact with the map, and you can programmatically change it to update the map position.
Define layers
Create a state property for your map layers:@State private var layers: [any Layer] = []
Add MapView to your view
Use the MapView in your SwiftUI body:var body: some View {
MapView(
camera: $camera,
layers: layers
)
.onAppear {
setupLayers()
}
}
Configure layers
Set up your layers in a separate method:private func setupLayers() {
layers = [
TiledRasterLayer(
"osm",
webMercatorUrlFormat: "https://tiles.sample.org/{z}/{x}/{y}.png"
)
]
}
Complete example
Here’s a complete working example:
import MapCore
import SwiftUI
struct ContentView: View {
@State private var camera = MapView.Camera(
latitude: 46.962592372639634,
longitude: 8.378232525377973,
zoom: 1000000
)
@State private var layers: [any Layer] = []
var body: some View {
MapView(
camera: $camera,
layers: layers
)
.onAppear {
setupLayers()
}
}
private func setupLayers() {
layers = [
TiledRasterLayer(
"osm",
webMercatorUrlFormat: "https://tiles.sample.org/{z}/{x}/{y}.png"
)
]
}
}
Multiple layers
Combine multiple layers by passing them in the layers array:
private func setupLayers() {
layers = [
TiledRasterLayer(
"base",
webMercatorUrlFormat: "https://tiles.sample.org/{z}/{x}/{y}.png"
),
try! VectorLayer(
"overlay",
styleURL: "https://www.sample.org/overlay/style.json"
)
]
}
Enable 3D mode
For 3D maps, use the is3D parameter:
MapView(
camera: $camera,
layers: layers,
is3D: true
)
Custom map projection
Use a different coordinate system by providing a MapConfig:
MapView(
camera: $camera,
mapConfig: .init(
mapCoordinateSystem: MCCoordinateSystemFactory.getEpsg2056System()
),
layers: layers
)
Programmatic camera control
Update the camera binding to change the map position:
struct ContentView: View {
@State private var camera = MapView.Camera(
latitude: 46.962592372639634,
longitude: 8.378232525377973,
zoom: 1000000
)
@State private var layers: [any Layer] = []
var body: some View {
VStack {
MapView(
camera: $camera,
layers: layers
)
.onAppear {
setupLayers()
}
Button("Zoom In") {
camera.zoom = (camera.zoom ?? 1000000) / 2
}
.padding()
}
}
private func setupLayers() {
layers = [
TiledRasterLayer(
"osm",
webMercatorUrlFormat: "https://tiles.sample.org/{z}/{x}/{y}.png"
)
]
}
}
WMTS support
Parse WMTS capabilities to create layers:
private func setupWMTSLayer() {
guard let resource = MCWmtsCapabilitiesResource.create(xml),
let wmtsLayer = resource.createLayer(
"identifier",
tileLoader: MCTextureLoader()
) else {
return
}
layers = [wmtsLayer]
}
Vector tiles
Add vector tile layers using the VectorLayer type:
private func setupLayers() {
layers = [
try! VectorLayer(
"base-map",
styleURL: "https://www.sample.org/base-map/style.json"
)
]
}
Working with overlays
For overlay layers like polygons, icons, and lines, you’ll need to use UIViewRepresentable to wrap the MCMapView:
Polygon overlay
struct MapWithPolygonView: UIViewRepresentable {
@Binding var camera: MapView.Camera
let coords: [MCCoord]
func makeUIView(context: Context) -> MCMapView {
let mapView = MCMapView()
// Add base layer
mapView.add(layer: TiledRasterLayer(
"osm",
webMercatorUrlFormat: "https://tiles.sample.org/{z}/{x}/{y}.png"
))
// Add polygon layer
let polygonLayer = MCPolygonLayerInterface.create()
let polygonInfo = MCPolygonInfo(
identifier: "switzerland",
coordinates: MCPolygonCoord(positions: coords, holes: []),
color: UIColor.red.mapCoreColor,
highlight: UIColor.red.withAlphaComponent(0.2).mapCoreColor
)
polygonLayer?.add(polygonInfo)
mapView.add(layer: polygonLayer?.asLayerInterface())
// Set initial camera position
if let center = camera.center.value, let zoom = camera.zoom.value {
mapView.camera.move(
toCenterPositionZoom: center,
zoom: zoom,
animated: false
)
}
return mapView
}
func updateUIView(_ uiView: MCMapView, context: Context) {
// Handle camera updates if needed
}
}
struct ContentView: View {
@State private var camera = MapView.Camera(
latitude: 46.962592372639634,
longitude: 8.378232525377973,
zoom: 1000000
)
var body: some View {
MapWithPolygonView(
camera: $camera,
coords: [
// your coordinates here
]
)
}
}
Icon overlay
struct MapWithIconView: UIViewRepresentable {
@Binding var camera: MapView.Camera
let coordinate: MCCoord
let imageName: String
func makeUIView(context: Context) -> MCMapView {
let mapView = MCMapView()
// Add base layer
mapView.add(layer: TiledRasterLayer(
"osm",
webMercatorUrlFormat: "https://tiles.sample.org/{z}/{x}/{y}.png"
))
// Add icon layer
let iconLayer = MCIconLayerInterface.create()
let image = UIImage(named: imageName)
let texture = try! TextureHolder(image!.cgImage!)
let icon = MCIconFactory.createIcon(
"icon",
coordinate: coordinate,
texture: texture,
iconSize: .init(
x: Float(texture.getImageWidth()),
y: Float(texture.getImageHeight())
),
scale: .FIXED,
blendMode: .NORMAL
)
iconLayer?.add(icon)
mapView.add(layer: iconLayer?.asLayerInterface())
// Set initial camera position
if let center = camera.center.value, let zoom = camera.zoom.value {
mapView.camera.move(
toCenterPositionZoom: center,
zoom: zoom,
animated: false
)
}
return mapView
}
func updateUIView(_ uiView: MCMapView, context: Context) {
// Handle updates if needed
}
}
Line overlay
struct MapWithLineView: UIViewRepresentable {
@Binding var camera: MapView.Camera
let coords: [MCCoord]
func makeUIView(context: Context) -> MCMapView {
let mapView = MCMapView()
// Add base layer
mapView.add(layer: TiledRasterLayer(
"osm",
webMercatorUrlFormat: "https://tiles.sample.org/{z}/{x}/{y}.png"
))
// Add line layer
let lineLayer = MCLineLayerInterface.create()
lineLayer?.add(MCLineFactory.createLine(
"lineIdentifier",
coordinates: coords,
style: MCLineStyle(
color: MCColorStateList(
normal: UIColor.systemPink.withAlphaComponent(0.5).mapCoreColor,
highlighted: UIColor.blue.withAlphaComponent(0.5).mapCoreColor
),
gapColor: MCColorStateList(
normal: UIColor.red.withAlphaComponent(0.5).mapCoreColor,
highlighted: UIColor.gray.withAlphaComponent(0.5).mapCoreColor
),
opacity: 1.0,
widthType: .SCREEN_PIXEL,
width: 50,
dashArray: [1, 1],
dashFade: 0.0,
dashAnimationSpeed: 0.0,
lineCap: .BUTT,
lineJoin: .ROUND,
offset: 0.0,
dotted: false,
dottedSkew: 0.0
)
))
mapView.add(layer: lineLayer?.asLayerInterface())
// Set initial camera position
if let center = camera.center.value, let zoom = camera.zoom.value {
mapView.camera.move(
toCenterPositionZoom: center,
zoom: zoom,
animated: false
)
}
return mapView
}
func updateUIView(_ uiView: MCMapView, context: Context) {
// Handle updates if needed
}
}
Next steps
UIKit setup
Learn how to use Open Mobile Maps with UIKit
Add layers
Learn how to add and customize map layers