Yatmo iOS SDK

A Swift Package that puts the Yatmo map on a listing screen in a few lines, with a typed async client for the neighbourhood data. UIKit and SwiftUI. Built on MapLibre Native, no Google or Apple map key needed.

Requirements

Install

Xcode: File, Add Package Dependencies, paste https://github.com/yatmo/yatmo-sdk-ios, add the YatmoSDK product to your app target. Or in Package.swift:

dependencies: [
    .package(url: "https://github.com/yatmo/yatmo-sdk-ios", from: "1.0.0")
],
targets: [
    .target(name: "MyApp", dependencies: [
        .product(name: "YatmoSDK", package: "yatmo-sdk-ios")
    ])
]

No Info.plist entry is required: the SDK does not use location services.

Configure

Create one Yatmo instance per app, typically at launch, and share it:

import YatmoSDK

let yatmo = Yatmo(configuration: YatmoConfiguration(
    licenseKey: "YOUR_FRONTEND_KEY",
    country: .BE,
    language: .FR
))

The app id is read from Bundle.main.bundleIdentifier. Pass appId: explicitly only if you ship the same binary under several ids and want to force one.

The map (UIKit)

import YatmoSDK

final class ListingViewController: UIViewController {
    private lazy var mapView = YatmoMapView(yatmo: yatmo, style: .liberty)

    override func viewDidLoad() {
        super.viewDidLoad()
        mapView.frame = view.bounds
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(mapView)

        mapView.showProperty(latitude: 50.8520525, longitude: 4.3442926, zoom: 15)
        mapView.showIsochrones(mode: .walking)          // optional: 5 / 10 / 20 min polygons
        mapView.onPoiSelected = { poi in
            print(poi.name, poi.type, poi.latitude, poi.longitude)
        }
    }
}

POI markers load automatically for the visible area and refresh when the user pans or zooms. The markers use the same icons as the web plugin. The underlying MLNMapView is exposed as mapView.mapView if you need MapLibre directly (custom annotations, camera animations, gesture options).

SwiftUI

import SwiftUI
import YatmoSDK

struct ListingMap: View {
    var body: some View {
        YatmoMap(yatmo: yatmo,
                 latitude: 50.8520525,
                 longitude: 4.3442926,
                 zoom: 15,
                 style: .liberty,
                 isochrones: .walking) { poi in
            print("tapped", poi.name)
        }
        .frame(height: 320)
        .clipShape(RoundedRectangle(cornerRadius: 12))
    }
}

Map options

Name In Type Description
style YatmoMapStyle .liberty, .basic, .bright, .threeD, .positron, .dark, .libertyStonehedge. Same seven styles as the web plugin. Default: .liberty.
showProperty(latitude:longitude:zoom:) method Centres the map and drops the property pin. Zoom 15 shows the neighbourhood, 13 the district.
poiTypeIds [Int64]? Restrict the POIs to some categories. Get the ids per group from yatmo.client.simplifiedCategories() (Education, Transports, Motorways, Shopping, Tourism...). Default: nil (all).
poiIconSize CGFloat Marker size in points (24 or 32, icons exist for both). Default: 24.
showIsochrones(mode:) / hideIsochrones() method Draws the 5 / 10 / 20 minute areas for .walking, .bicycling, .driving or .transit.
fitIsochrones / isochronePadding Bool / UIEdgeInsets Like the web plugin: once the isochrones are drawn the camera fits the largest area, and hideIsochrones() restores the previous camera. Default: true / 40.
minZoomForPois Double Below this zoom no POI request is made, to keep the map fast and the payload small. Default: 13.
onPoiSelected (YatmoPoi) -> Void Called when a marker is tapped. Show your own sheet or popup; the SDK draws none.
onError (Error) -> Void Network or licence errors (401 / 403) while loading POIs or isochrones.

Data: YatmoClient

All calls are async throws and return typed models decoded from the REST API:

let client = yatmo.client

// Nearby POIs grouped by category, with travel times (same data as the Summary plugin)
let summary = try await client.summary(latitude: 50.8520525, longitude: 4.3442926)
for category in summary.categories {
    print(category.label)
    for sub in category.subCategories { print(" ", sub.label, sub.places.count) }
}

// Generated neighbourhood paragraphs
let text = try await client.summaryText(latitude: 50.8520525, longitude: 4.3442926)
print(text.paragraphs.first?.sentences.first ?? "")   // or text.text for everything

// Scores per category (0 to 10)
let scores = try await client.scores(latitude: 50.8520525, longitude: 4.3442926)

// Listing enrichment: nearest place of each category, four travel modes
let enrichment = try await client.enrichment(latitude: 50.8520525, longitude: 4.3442926)

// Address autocomplete near a position
let places = try await client.geocode(query: "Rue Neuve", latitude: 50.85, longitude: 4.35)

// Raw building blocks
let pois = try await client.points(southWest: (50.848, 4.338), northEast: (50.856, 4.350))
let isochrones = try await client.isochrones(mode: .walking, latitude: 50.8520525, longitude: 4.3442926)
let groups = try await client.simplifiedCategories()

Response shapes are documented per endpoint: Summary, Enrichment, Points, Isochrone, Geolocation. Errors surface as YatmoError with the HTTP status and the server message.

WebView fallback

To show the full web plugin (map plus summary panel, scores or tabs) on a screen, use the bundled WKWebView subclass. It builds the iframe plugin URL for you:

let web = YatmoWebView(yatmo: yatmo, options: YatmoWebViewOptions(
    latitude: 50.8520525, longitude: 4.3442926, mode: .overlay, zoom: 15, accentColor: "#428BFF"))
view.addSubview(web)

Troubleshooting

Related: Android SDK · Bring your own map · Overview.