Create your first application¶
Follow this tutorial to build an iOS app with an interactive map.
📝 INFO What you need
- Xcode installed
- Service key from UNL - via UNL Platform
Step 1: Create a new project¶
- Open Xcode and select File > New > Project
- Choose App under the iOS tab
- Set your product name (e.g.
HelloMap), interface to Storyboard or SwiftUI, and language to Swift - Click Create
📝 INFO
Using an existing project? Skip to Step 2 and add the SDK to your existing app.
Step 2: Install the SDK¶
- In Xcode, go to File > Swift Packages > Add Package Dependency
- Paste the repository URL: {TODO}
- Select the latest stable version and click Add Package
⚠️ WARNING
Complete the full SDK integration steps if you haven't already.
Step 3: Write the code¶
🚨 DANGER
The
projectApiTokenglobal variable is used here for simplicity. If you are going to commit your code to version control, make sure to store your API token securely.
- UIKit
- SwiftUI
Open AppDelegate.swift and add this to the code:
// UIKit
import UIKit
import GEMKit
let projectApiToken = "YOUR_API_TOKEN_HERE"
class MapExceptionsHandler: NSObject, GEMSdkExceptions {
func onSdkActivationDetails(_ reason: ActivationAboutToExpireType, remainingTime: Int) {
print("Activation expiring: \(remainingTime)s remaining")
}
}
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
private let exceptionsHandler = MapExceptionsHandler()
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let parameters = GEMSdkParameters(exceptions: exceptionsHandler)
parameters.activationToken = projectApiToken
GEMSdk.shared().initSdk(with: parameters) { error in
if error == .kNoError {
print("SDK initialized successfully")
} else {
print("SDK init failed: \(error.rawValue)")
}
}
return true
}
}
Then open ViewController.swift and replace everything with this:
// UIKit
import UIKit
import GEMKit
class ViewController: UIViewController {
private var mapViewController: MapViewController?
override func viewDidLoad() {
super.viewDidLoad()
let controller = MapViewController()
controller.view.backgroundColor = .systemBackground
mapViewController = controller
addChild(controller)
view.addSubview(controller.view)
controller.didMove(toParent: self)
controller.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
controller.view.topAnchor.constraint(equalTo: view.topAnchor),
controller.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
controller.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
controller.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
mapViewController?.startRender()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
mapViewController?.stopRender()
}
deinit {
mapViewController?.destroy()
}
}
Open HelloMapApp.swift (or your main App file) and replace everything with this:
//SwiftUI
import SwiftUI
import GEMKit
let projectApiToken = "YOUR_API_TOKEN_HERE"
class MapExceptionsHandler: NSObject, GEMSdkExceptions {
func onSdkActivationDetails(_ reason: ActivationAboutToExpireType, remainingTime: Int) {
print("Activation expiring: \(remainingTime)s remaining")
}
}
@main
struct HelloMapApp: App {
private let exceptionsHandler = MapExceptionsHandler()
init() {
let parameters = GEMSdkParameters(exceptions: exceptionsHandler)
parameters.activationToken = projectApiToken
GEMSdk.shared().initSdk(with: parameters) { error in
if error == .kNoError {
print("SDK initialized successfully")
} else {
print("SDK init failed: \(error.rawValue)")
}
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Then open ContentView.swift and replace everything with this:
// SwiftUI
import SwiftUI
import GEMKit
struct ContentView: View {
var body: some View {
MapReader { proxy in
MapBase()
.ignoresSafeArea()
}
}
}
Paste your Service Key in place of YOUR_API_TOKEN_HERE, in between the quotes.
Understanding the code¶
GEMSdkParameters— Configuration object for SDK initialization; requires aGEMSdkExceptionshandleractivationToken— Your ServiceKey for SDK authentication and auto-activationinitSdk(with:completionHandler:)— Initializes the SDK; the completion handler fires when initialization finishesMapViewController— UIKit view controller that displays the interactive mapMapBase/MapReader— SwiftUI views for displaying and interacting with the mapdestroy()— Frees map resources when the view controller is deallocated
Step 4: Run your app¶
- Select a simulator or connected device in Xcode
- Press Cmd + R to build and run
📝 INFO
When you initialize the SDK with a valid API key, it also performs an automatic activation. This allows better flexibility for licensing.
What's next?¶
Explore what you can do with the map:
- Draw shapes — Add polygons, lines, and circles
- Change map styles — Switch between light, dark, and custom themes
- Search for places — Find addresses and points of interest
- Add navigation — Calculate routes and get turn-by-turn directions
Troubleshooting¶
SDK initialization returns an error¶
Check the SDKErrorCode returned by initSdk(with:completionHandler:):
.kNoError— Success.kActivation— Activation required; verify your API token- Other codes — Check your network connection and token validity
How to check if my Service Key is valid¶
Add this code to verify your token:
GEMSdk.shared().verifySdk(projectApiToken) { status in
switch status {
case .valid:
print("✓ Service key is valid")
case .expired:
print("✗ Service key expired")
case .accessDenied:
print("✗ Access denied")
default:
print("✗ Verification failed: \(status.rawValue)")
}
}
Map shows a watermark¶
This means your Service key is missing or invalid.
Without a valid Service key:
- ❌ Map downloads won't work
- ❌ Map updates disabled
- ⚠️ Watermark appears
- ⚠️ Limited features
Fix: Ensure you set a valid activationToken on GEMSdkParameters before calling initSdk(with:completionHandler:).