iOS Example

A Swift/SwiftUI application that renders a MapLibre Native vector tile map and adds places search. Uses UIViewRepresentable to bridge MapLibre's UIKit view into SwiftUI.

Prerequisites

Quick Start

git clone https://github.com/geogdev/examples.git
cd examples/mobile/ios-maplibre
open GeogExample.xcodeproj

Wait for Swift Package Manager to resolve dependencies, then add your API key to Config.xcconfig:

GEOG_API_KEY = gk_live_your-api-key-here

Press Cmd+R to build and run.

Project Structure

FileDescription
Config.xcconfigBuild configuration — API key injected via build settings into Info.plist
GeogExample/Services/GeogService.swiftAPI client — authentication and places search
GeogExample/MapView.swiftUIViewRepresentable bridge — wraps MLNMapView with programmatic style
GeogExample/PlacesSearchView.swiftSwiftUI search panel — search input, results list, and map marker management
GeogExample/Models/Place.swiftCodable data model for search results
GeogExample/ContentView.swiftRoot SwiftUI view composing map and search

How It Works

Bundle ID Authentication

Mobile apps authenticate using bundle ID restrictions instead of token exchange. When you create an API token in the console, you can restrict it to specific iOS bundle identifiers (e.g., com.yourcompany.yourapp). The app sends its bundle ID via the X-App-Bundle-Id header, and the Geog API rejects calls whose header doesn't match an allowed identifier.

Bundle ID restrictions reduce casual abuse — an extracted key won't work from an app with a different bundle ID — but the header is client-supplied and can be spoofed. For production apps with high-value keys, consider proxying API calls through your own backend so the key is never shipped in the binary.

To configure bundle ID restrictions:

  1. Go to Tokens in the console
  2. Edit your token's settings
  3. Add your app's bundle identifier under Allowed Bundle IDs

API Key Configuration

The API key is stored in Config.xcconfig and injected into the app through Xcode build settings → Info.plist. GeogService reads it from the bundle at launch:

let apiKey = Bundle.main.object(forInfoDictionaryKey: "GEOG_API_KEY") as! String

Map Authentication

The app configures MLNNetworkConfiguration so all requests to api.geog.dev (tiles and places) include the Bearer and bundle ID headers automatically:

let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = [
    "Authorization": "Bearer \(apiKey)",
    "X-App-Bundle-Id": Bundle.main.bundleIdentifier ?? ""
]
MLNNetworkConfiguration.shared.sessionConfiguration = config

UIViewRepresentable Bridge

MapView wraps MLNMapView (UIKit) for use in SwiftUI using the UIViewRepresentable protocol with a Coordinator for delegate callbacks.

Full Source

github.com/geogdev/examples/tree/main/mobile/ios-maplibre

See Also