Create your first application
Follow this tutorial to build an iOS app with an interactive map.
What you need:
- Xcode installed
- Free API key from MagicLane
Step 1: Create a new project
- Open Xcode and select File > New > Projectcma
- Choose App under the iOS tab
- Set your product name (e.g.
HelloMap), interface to Storyboard or SwiftUI, and language to Swift - Click Create
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:
https://github.com/magiclane/magiclane-maps-sdk-ios - Select the latest stable version and click Add Package
Complete the full SDK integration steps if you haven't already.
Step 3: Write the code
The projectApiToken global 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:
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:
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:
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:
import SwiftUI
import GEMKit
struct ContentView: View {
var body: some View {
MapReader { proxy in
MapBase()
.ignoresSafeArea()
}
}
}
Paste your API token in place of YOUR_API_TOKEN_HERE, in between the quotes.
Understanding the code
GEMSdkParameters— Configuration object for SDK initialization; requires aGEMSdkExceptionshandleractivationToken— Your API key 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
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
and more in the examples section of our documentation.
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 API key is valid
Add this code to verify your token:
GEMSdk.shared().verifySdk(projectApiToken) { status in
switch status {
case .valid:
print("✓ API key is valid")
case .expired:
print("✗ API key expired")
case .accessDenied:
print("✗ Access denied")
default:
print("✗ Verification failed: \(status.rawValue)")
}
}
Map shows a watermark
This means your API key is missing or invalid.
Without a valid API 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:).