Skip to content

Swift Quickstart

iOS / macOS native maps via MapLibre Native iOS.

Install (Swift Package Manager)

swift
// Package.swift dependencies
.package(url: "https://github.com/maplibre/maplibre-gl-native-distribution", from: "6.0.0")

Add MapLibre product to your target.

Render a map

swift
import UIKit
import MapLibre

class MapViewController: UIViewController {
    private var mapView: MLNMapView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let key = Bundle.main.object(forInfoDictionaryKey: "MFDPublicKey") as! String
        let styleURL = URL(string:
            "https://api.mapsfordevs.com/styles/standard.json?key=\(key)")!

        mapView = MLNMapView(frame: view.bounds, styleURL: styleURL)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.setCenter(CLLocationCoordinate2D(latitude: -26.20, longitude: 28.04),
                          zoomLevel: 11, animated: false)
        view.addSubview(mapView)
    }
}

Add bundle ID to your dashboard public-key allow-list.

Switch language

swift
import MapLibre

func setMapLanguage(_ map: MLNMapView, _ lang: String) {
    let layers = ["place_label", "transportation_name", "poi_label"]
    for id in layers {
        guard let layer = map.style?.layer(withIdentifier: id) as? MLNSymbolStyleLayer else { continue }
        layer.text = NSExpression(format:
            "mgl_coalesce({CAST(name_\(lang), 'NSString'), CAST(name_latin, 'NSString'), CAST(name, 'NSString')})")
    }
}

(Actual key names: MapLibre converts name:dename_de server-side in iOS bindings.)

Geocoding

swift
import Foundation

struct GeocodeItem: Decodable {
    let lat: Double
    let lng: Double
    let label: String
    let confidence: Double
    let type: String
}

struct GeocodeResponse: Decodable {
    let ok: Bool
    let items: [GeocodeItem]?
    let error: String?
}

enum MFDError: Error { case api(String) }

func geocode(query: String, country: String? = nil) async throws -> [GeocodeItem] {
    let key = Bundle.main.object(forInfoDictionaryKey: "MFDPublicKey") as! String
    var components = URLComponents(string: "https://api.mapsfordevs.com/geocode/forward")!
    components.queryItems = [URLQueryItem(name: "q", value: query),
                             URLQueryItem(name: "limit", value: "5")]
    if let country { components.queryItems?.append(URLQueryItem(name: "country", value: country)) }

    var req = URLRequest(url: components.url!)
    req.setValue("Bearer \(key)", forHTTPHeaderField: "Authorization")

    let (data, _) = try await URLSession.shared.data(for: req)
    let resp = try JSONDecoder().decode(GeocodeResponse.self, from: data)
    guard resp.ok, let items = resp.items else { throw MFDError.api(resp.error ?? "unknown") }
    return items
}

SwiftUI wrapper

swift
import SwiftUI
import MapLibre

struct MapLibreView: UIViewRepresentable {
    let styleURL: URL
    let center: CLLocationCoordinate2D
    let zoom: Double

    func makeUIView(context: Context) -> MLNMapView {
        let v = MLNMapView(frame: .zero, styleURL: styleURL)
        v.setCenter(center, zoomLevel: zoom, animated: false)
        return v
    }
    func updateUIView(_ v: MLNMapView, context: Context) {}
}