Indoor Maps on iOS: Advanced MapKit

In this MapKit tutorial, you’ll learn how to use Indoor Maps to map the inside of buildings, switch between different stories and find your location inside the building. By Alex Brown.

Leave a rating/review
Download materials
Save for later
Share

Apple introduced Indoor Maps to MapKit in iOS 13. This program provides tools to map the inside of physical structures, allowing users to navigate a building from the inside.

In this tutorial, you’ll learn how to use Indoor Maps to add the location of the RazeWare office to a map. In the process, you’ll learn to:

  • Parse Indoor Mapping Data Format (IMDF) data into models.
  • Draw geometry from GeoJSON on a map.
  • Style map geometry.
  • Switch between different levels of a structure.
  • Access indoor locations.

Are you ready for a full tour inside RazeWare HQ? Well, read on!

Note: This advanced-level tutorial assumes you’re comfortable building an iOS app in Xcode with Swift. This tutorial uses MapKit. If you’re unfamiliar with MapKit, read MapKit Tutorial: Getting Started first.

Getting Started

Download the starter project using the Download Materials button at the top or bottom of this tutorial. Open the starter project. Build and run to see what you’re working with.

RazeMap initial screen showing map of the United Kingdom

For the less observant among you, it’s a map. :]

Yoda, a map it is

The starter project already contains the user interface, some model files and the IMDF archive you’ll work with. Right now, it’s not an overly inspiring app; it certainly wouldn’t get past the Apple Genius in app review. But you’re going to change that!

Understanding Indoor Maps

Before you start writing code, it’s important to know what kind of data you’re working with. In this tutorial, you’ll use two standards: GeoJSON and IMDF.

What Is GeoJSON?

GeoJSON is a format for representing geographic data structures. As the name implies, GeoJSON is based on the JSON format. The Internet Engineering Task Force (IETF) released it in 2015 to standardize the way programmers model geographical data.

GeoJSON supports a range of different geometry types defined using latitude and longitude pairs. You can combine the lat-long pairs to form more complex structures. A GeoJSON object may represent a:

  • Geometry: A region of space.
  • Feature: A spatially-bound entity.
  • FeatureCollection: A list of Features.

Building geometry with lat-long pairs

Take a look at the building structure outlined in the map above. Each point in the geometry of the structure has a latitude and a longitude coordinate, the same way you’d have an x-y position in a Cartesian coordinate system. Each point is labeled from 1 to 6, representing the order in which they’re drawn. The column on the left shows the actual lat-long coordinates for each point.

The GeoJSON representation of this feature looks like this:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "stroke": "#101889",
        "stroke-width": 2,
        "stroke-opacity": 1,
        "fill": "#98a1e6",
        "fill-opacity": 0.5
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -121.80389642715454,
              37.33966009140741
            ],
            [
              -121.80312395095825,
              37.338790026148
            ],
            [
              -121.80198669433592,
              37.33937007077421
            ],
            [
              -121.80222272872923,
              37.33960891137705
            ],
            [
              -121.80301666259766,
              37.33966009140741
            ],
            [
              -121.80331707000731,
              37.33998423078978
            ],
            [
              -121.80389642715454,
              37.33966009140741
            ]
          ]
        ]
      }
    }
  ]
}

You can recreate this exact structure yourself. Head over to geojson.io and paste the GeoJSON above into the editor on the right. Since each element in the array is a lat-long pair, the structure will appear in the same place as the image shown previously.

What Is IMDF?

Apple introduced the Indoor Mapping Data Format (IMDF) with iOS 13 as a new standard for modeling the inside of a structure. An IMDF archive contains a group of feature types that, when combined, can describe an indoor space including walls, doorways, stairs, levels and more. You usually create an IMDF archive by using third-party software to convert a detailed floor plan into IMDF.

Note: Creating an IMDF archive is out of scope for this tutorial. If you want to learn more about it, here’s a great tutorial on Creating and Validating IMDF Datasets.

IMDF Feature Types

You already know that IMDF archives are essentially a collection of GeoJSON files that, when combined, describe an indoor space. But how exactly does this work? You’ll find out next.

In Xcode, open the Project navigator and expand IMDF/Data. Each GeoJSON file has a name that corresponds to its feature type described in the IMDF documentation.

For example, occupant.geojson is a collection of Occupant types, building.geojson is a collection of Building types and so on. It’s as simple as that. :]

The main types you’ll look at in this tutorial are:

  • Venue
  • Unit
  • Occupant
  • Amenity
  • Level

Now that you understand the tools you’ll be using, it’s time to put them to work!

Using the GeoJSON Format

Open occupant.geojson in the Project navigator. You’ll see that GeoJSON and IMDF really aren’t as scary as they sound.

Take a look at one of the occupants in the list:

{
    "feature_type": "occupant",
    "geometry": null,
    "id": "5ac4bf40-2dbf-4bdb-9c39-495c442b7e39",
    "properties": {
        "address_id": null,
        "alt_name": null,
        "anchor_id": "76336b53-81c9-4c93-8f81-a4c008d54ba1",
        "category": "office",
        "display_point": {
            "coordinates": [
                -121.889609,
                37.329678
              ],
            "type": "Point"
        },
        "hours": "Su-Sa 09:00-17:00",
        "name": {
            "en": "Ray's Office"
        },
        "phone": "+14087924512",
        "restriction": null,
        "website": null,
        "correlation_id": null
    },
    "type": "Feature"
}

This occupant describes Ray’s office. A valid occupant must define an id, the feature_type must have a value of occupant and it must have a geometry value of null.

An occupant doesn’t need its own geometry, as it uses the geometry from the anchor that anchor_id references inside properties.

Still in occupant.geojson, copy the anchor_id of the first occupant, then open anchor.geojson and search for the id. You’ll find the associated anchor feature inside.

All the other keys in properties are metadata describing the occupant. In this article, the only key you’ll use is the name but in a real-world situation, you could expand this to show your opening hours, phone number and website, if that information was relevant for your app.

Also, that’s not Ray’s real phone number, so don’t bother trying to call. :]

A great way to learn is to use the tools at geojson.io to explore GeoJSON further. You can draw geometry directly on a map and have it output the associated JSON.

Note: You’ve covered some top level theory on GeoJSON and IMDF, but there’s a lot more to know. Apple’s documentation provides a detailed overview of IMDF and the different feature types. The official GeoJSON website has some good information, but it’s very technical.

Next up, looking into how a GeoJSON file can be converted to an actual Swift model that you can work with in your code.

Alex Brown

Contributors

Alex Brown

Author

David Sherline

Tech Editor

Julia Zinchenko

Illustrator

Morten Faarkrog

Final Pass Editor

Richard Critz

Team Lead

Cosmin Pupăză

Topics Master

Over 300 content creators. Join our team.