Getting started with MapKit for iOS

This tutorial explains how install and setup MapKit library and create a map with a placemark for a specific location.

Step 1. Get the MapKit API key

Before you can use MapKit SDK in your application, you need the API key.

Go to the Mappable Account and register a new account or log in to an existing. The main page will display a key that is suitable for any Mappable service.

Step 2. Add the MapKit library to your project

Use CocoaPods to add the library to the project.

  1. Go to the directory with the Xcode project.

  2. Create the Podfile to list dependencies from other libraries:

    pod init
    
  3. Open the Podfile in a text editor and add a dependency for your target:

    use_frameworks!
    # The lite library only contains the map, traffic layer,
    # LocationManager, and UserLocationLayer
    # and lets you download offline maps (in the paid version only).
    pod 'MappableMobile', '1.1.0-lite'
    
    # The full library supplements lite version features with car routing,
    # bike routing, pedestrian routing, and public transport routing,
    # search, suggest, geocoding, and panorama display.
    # pod 'MappableMobile', '1.1.0-full'
    
  4. Run the following command in the project directory:

    pod install
    

    To open the project file, run the following command:

    open *.xcworkspace
    

Step 3. Provide the API key to MapKit

The MapKit SDK requires you to set up the API key in the MMKMapKit(Factory).setApiKey method.

Set your API key in the application(_:didFinishLaunchingWithOptions:) method of the application delegate and instantiate the MMKMapKit object:

func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
    MMKMapKit.setApiKey("Your API key")
    MMKMapKit.sharedInstance()
}

Note

If you're using a multi-module application and want to initialize MapKit in a method different from application(_:didFinishLaunchingWithOptions:), call the onStart() method after creating the MapKit object:

MMKMapKit.setApiKey("MAPKIT_API_KEY")
MMKMapKit.sharedInstance().onStart()

Step 4. Add the map

Initialize the map in the needed view controller:

override func viewDidLoad() {
    super.viewDidLoad()

    mapView.mapWindow.map!.move(
        with: MMKCameraPosition(
            target: MMKPoint(latitude: 25.1982, longitude: 55.272758),
            zoom: 15,
            azimuth: 0,
            tilt: 0
        ),
        animation: MMKAnimation(type: MMKAnimationType.smooth, duration: 5),
        cameraCallback: nil
    )
}

Build and run your application. There's an example of the Activity with the tappable map:

Map with the smallest zoom

Maps support multiple actions by default: move, rotate, change the zoom, and tilt.

Without additional setup, the map will be shown with the smallest possible zoom for the user's screen.

To change a map's position or zoom, use the MMKMap.move(with:animation:cameraCallback:) method:

private func move(_ map: MMKMap) {
    let cameraPosition = MMKCameraPosition(
        target: MMKPoint(latitude: 25.1982, longitude: 55.272758,
        zoom: 17.0,
        azimuth: 150.0,
        tilt: 30.0
    )

    map.move(with: cameraPosition, animation: MMKAnimation(type: .smooth, duration: 1.0))
}

The MMKMap.move(with:animation:cameraCallback:) call accepts the MMKCameraPosition argument, which fully defines the map's position, zoom, tilt, and azimuth.

There's an example of the Activity after applying the move to the map:

Map after applied move

Step 5. Note the following

MapKit stores weak references to the Listener objects passed to it. You need to store references to them in memory yourself:

Note

All Listener objects must be inherited from the NSObject class.

internal class CameraListener: NSObject, MMKMapCameraListener {
    func onCameraPositionChanged(
        with map: MMKMap?,
        cameraPosition: MMKCameraPosition,
        cameraUpdateReason: MMKCameraUpdateReason,
        finished: Bool
    ) {
        // Do something
    }
}

let cameraListener = CameraListener()

override func viewDidLoad() {
    super.viewDidLoad()
    mapView.mapWindow.map!.addCameraListener(with: cameraListener)
}

Note

By default, the methods of any Listener objects and platform interfaces are called on the main thread unless the method documentation specifies otherwise.

  • The minimum supported version for the M1 emulator is iOS 13.

  • The M1 emulator doesn't support OpenGL, so make sure to pass vulkanPreferred: true to the MMKMapView and MMKPanoView constructors. This setting is only required for the emulator build.

  • Recommended linking flag: -ObjC.

Step 6. Display a placemark on the map

Let's modify the application such that you can show a tappable placemark on the map.

  1. Add a png resource for the placemark image to the project.

    For example, we have the image named placemark_icon.png in our Assets directory.

    Icon placemark

  2. Add the placemark for the MMKMap.mapObjects collection to the specific location.

    Obtain the image for our placemark using UIImage(named:) constructor. Add the placemark for the MMKMap.mapObjects collection to the specific location using MMKMapObjectCollection.addPlacemark(with:image:) method:

    private func addPlacemark(_ map: MMKMap) {
        let image = UIImage(named: "placemark_icon") ?? UIImage()
        let placemark = map.mapObjects.addPlacemark()
        placemark.geometry = MMKPoint(latitude: 25.1982, longitude: 55.272758
        placemark.setIconWith(image)
    }
    

    You can also add text to the placemark and customize it's style using MMKPlacemarkMapObject.setTextWithText(_:style:) method:

    placemark.setTextWithText(
        "Sample placemark",
        style: MMKTextStyle(
            size: 10.0,
            color: .black,
            outlineColor: .white,
            placement: .top,
            offset: 0.0,
            offsetFromIcon: true,
            textOptional: false
        )
    )
    
  3. To subscribe to created placemark's taps use MMKMapObject.addTapListener(with:) method.

    Firstly, we need to create a listener class, that implements the MMKMapObjectTapListener.onMapObjectTap(with:point:) method:

    final private class MapObjectTapListener: NSObject, MMKMapObjectTapListener {
        init(controller: UIViewController) {
            self.controller = controller
        }
    
        func onMapObjectTap(with mapObject: MMKMapObject, point: MMKPoint) -> Bool {
            AlertPresenter.present(
                with: "Tapped point",
                message: "\((point.latitude, point.longitude))",
                from: controller
            )
            return true
        }
    
        private let controller: UIViewController
    }
    

    Then we can create a listener object and assign it to the placemark:

    private lazy var mapObjectTapListener: MMKMapObjectTapListener = MapObjectTapListener(controller: self)
    
    private func addPlacemark(_ map: MMKMap) {
        placemark.addTapListener(with: mapObjectTapListener)
    }
    

Build and run your application. There's a placemark with your custom image on the map. Tap the placemark, and the message toast will show up:

Map after placemark was tapped