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
- Xcode 15+ (Swift 5.9+)
- iOS 16+ simulator or device
- A Geog API key (create one in the console)
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
| File | Description |
|---|---|
Config.xcconfig | Build configuration — API key injected via build settings into Info.plist |
GeogExample/Services/GeogService.swift | API client — authentication and places search |
GeogExample/MapView.swift | UIViewRepresentable bridge — wraps MLNMapView with programmatic style |
GeogExample/PlacesSearchView.swift | SwiftUI search panel — search input, results list, and map marker management |
GeogExample/Models/Place.swift | Codable data model for search results |
GeogExample/ContentView.swift | Root 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:
- Go to Tokens in the console
- Edit your token's settings
- 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
- Examples Overview — All examples (this example uses direct API-key auth with bundle ID restrictions)
- Vector Tiles API — Tile endpoint reference
- Places API — Search endpoint reference (preview — will change)
- Styles & Sprites — Hosted themes, sprites, and npm packages