LogoLogo
CMSGitHubSupportBook a demo
  • Documentation
  • Academy
  • Help Center
  • Welcome
  • SDKS & Frameworks
    • Web
      • Getting Started
        • Prerequisites
          • MapsIndoors
          • Map Engine Provider
            • Option 1: Get your Mapbox Access Token
            • Option 2: Get your Google Maps API Keys​
          • Map Engine Setup
        • Getting Started: MapsIndoors
      • Map Visualization
        • Highlight, Hover and Select
        • Remove Labels from Buildings and Venues
        • Change Building Outline
        • Managing Collisions Based on Zoom Level
        • 3D Maps
          • Managing your 3D Maps
        • Base Map Styling - Google Maps
        • Managing feature visibility for Mapbox
      • Wayfinding
        • Directions
        • Directions Service
          • Tailoring the directions to your specific needs
        • Directions Renderer
          • Customizing the Route Animation
        • Multi-stop navigation
          • Custom Icons
        • User's Location as Point of Origin
      • Search
        • Search Operations
        • Searching
        • Using External ID, Geospatial Joins
        • Utilizing MapsIndoors Web Components and Other Searches
      • Map Management
      • Data Visualization
        • Display Heatmap Overlay
      • Other guides
        • Authentication
          • Single Sign-On
            • SSO Configuration
            • SSO Authorisation
          • 2-Factor Authentication
          • Password Reset
        • Application User Roles
        • Custom Properties
        • Display Language
        • Language
        • User Positioning
          • Show User's Location aka. Blue Dot
          • Using Cisco DNA Spaces
        • Working with Events
        • Turn Off Collisions Based on Zoom Level
        • Remove Labels from Buildings and Venues for Web
        • Synchronizing data for a subset of venues
        • Custom Floor Selector
      • Display Rules in Practice
      • Offline Data
      • Managing map visibility
    • Android
      • Getting Started
        • Prerequisites
        • Create a New Project
        • Show a Map
        • Create a Search Experience
        • Getting Directions
        • Enable Live Data
        • Integrating MapsIndoors into your own App
        • Migrating from V3 to V4
          • Migrating to Mapbox V11
      • Directions
        • Directions Service
        • Directions Renderer
          • User's Location as Point of Origin
        • Wayfinding Instructions
          • See Route Element Details
        • Using multi-stop navigation
      • Searching
        • Searching on a Map
        • Creating a Search Experience
      • Switching Solutions
      • Caching & Offline Data
      • Display Language
      • Displaying Objects
        • Application User Roles
        • Getting a Polygon from a Location
        • Location Clustering
        • Location Data Sources
        • Location Details
        • Turn Off Collisions Based on Zoom Level
        • Enabling and Disabling features on the map
      • Change Building Outline Color
      • Event Logging
      • Configuring a menu with AppConfig
      • Display Heatmap Overlay
      • Custom Properties
      • Custom Floor Selector
      • External IDs
      • User Positioning
        • Show User's Location aka. Blue Dot
        • Using Cisco DNA Spaces
        • Using Google Fused Location Provider
        • Using Indoor Atlas
      • Authentication
        • Single Sign-On
          • SSO Configuration
          • SSO Authorisation
        • 2-Factor Authentication
        • Password Reset
      • Display Rules in Practice
        • Label styling through Display Rules
      • Highlight and Select
    • iOS
      • Getting Started
        • Prerequisites
        • Set Up Your Environment
        • Display a Map
        • Search
        • Getting Directions
        • Migrating from v3 to v4
      • Directions
        • Directions Renderer
          • User's Location as Point of Origin
        • Wayfinding Instructions
          • See Route Element Details
        • Directions Service
        • Using multi-stop navigation
      • Searching
        • Searching on a Map
        • Creating a Search Experience
      • Caching & Offline Data
      • Displaying Objects
        • Application User Roles
        • Getting a Polygon from a Location
        • Location Details
        • Turn Off Collisions Based on Zoom Level
        • Enabling and Disabling features on the map
      • Custom Floor Selector
      • Change Building Outline Color
      • Custom Map Padding
      • Custom Properties
      • Display Rules in Practice
        • Label styling through Display Rules
      • Switching Solutions
      • Show User's Location aka. Blue Dot
        • Using Indoor Atlas
        • Using Cisco DNA Spaces
      • Highlight and Select
      • Display Language
    • React Native
      • Getting Started
        • Prerequisites
        • Project Setup
        • Displaying a Map
        • Creating a Search Experience
        • Getting Directions
        • Enabling Live Data
      • Showing Blue Dot
    • Flutter
      • Getting Started
        • Prerequisites
        • Create a New Project
        • Show a Map
        • Create a Search Experience
        • Getting Directions
      • Migration Guide
    • Integration API
      • Integration API Access
        • Access with Swagger
        • Access with Postman
        • Access with Python
        • Client credentials flow
      • Data Description
      • Reverse Geocoding
      • Route Access
      • OpenAPI Specification
    • Built-In Map Edits
      • Getting started
      • Authentication
      • Release notes
      • Reference docs
  • Products
    • Product Overview
    • CMS
      • Interface Overview
      • Display Rules
      • Media Library
        • 2D Models and Icons
        • 3D Models
      • Editing Data
      • Solution Settings
      • Settings
      • Data Concepts
      • User Roles
      • Route Network
        • Barrier Route Element
        • Door Route Element
      • Additional Location Details
    • Map Template
      • Getting Started
        • Web Component
        • React Component
      • Configuration
        • Query Parameters
      • Customization
      • Deploying Map Template to a cloud storage provider
      • 2D/3D Visibility Switch
      • External customization of the Map Template
      • Location Details configuration
      • Kiosk
        • QR code configuration
  • Other
    • Design
      • Standard MapsIndoors Map Style
      • Using a Custom Mapbox MapStyle
    • Changelog
      • Web SDK
        • V4
        • V3
      • Android SDK
        • V4
        • V3
      • iOS SDK
        • V4
        • V3
      • React Native SDK
      • Flutter SDK
      • MI Components
      • Map Template
    • Glossary
  • Legacy Docs
    • Android SDK V3
      • Getting Started
        • Prerequisites
        • Create a New Project
        • Show a Map
        • Create a Search Experience
        • Getting Directions
        • Enable Live Data
        • Integrating MapsIndoors into your own App
    • iOS SDK V3
      • Getting Started
        • Prerequisites
        • Set Up Your Environment
        • Display a Map
        • Search
        • Directions
        • Live Data
        • Integrating MapsIndoors into your own App
      • Inspect Route Element for iOS v3
      • Using Cisco DNA Spaces
      • Using Indoor Atlas
      • Switching Solutions
      • Show User's Location aka. Blue Dot
      • Application User Roles
      • Getting a Polygon from a Location
      • Location Details
  • MapsIndoors SDK Firewall
  • Google Analytics & Logging
  • Reference Docs
    • Web SDK
    • Android SDK
    • iOS SDK
    • React Native SDK
    • Flutter SDK
Powered by GitBook
On this page
  • MapsIndoors SDK Map Engine Flavors​
  • MapsIndoors Initialization & Usage​
  • MapControl Initialization​
  • SolutionConfig & AppConfig​
  • Display Rules​
  • DirectionsService & DirectionsRenderer​
  • App User Roles​
  • Map & Camera Behavior Configs​
  • The "Go-To" Function​
  • Map Filtering​
  • Positioning Providers​
  • Location Data Sources​

Was this helpful?

Export as PDF
  1. SDKS & Frameworks
  2. iOS
  3. Getting Started

Migrating from v3 to v4

Last updated 1 month ago

Was this helpful?

The iOS SDK for MapsIndoors has received a major update to version 4.0.0, which comes with improved interfaces and flexibility for developing your own map experience. The MapsIndoors SDK now additionally supports Mapbox, alongside some reworked and refactored features that simplify development and SDK behavior. This guide will cover changes to the SDK and how to use it to provide you with a guide on how to upgrade from v3 to v4. If you have any questions concerning this document, or migrating to v4 in general, please contact MapsPeople technical support.

MapsIndoors SDK Map Engine Flavors

With the release of v4, the MapsIndoors SDK is released as multiple separate libraries depending on the Map Provider - Google Maps or Mapbox. You now import the SDK flavor of your choosing with either:

pod 'MapsIndoorsGoogleMaps', '~> 4.9'

or

pod 'MapsIndoorsMapbox11', '~> 4.9'

(Remember to check the for the latest version)

MapsIndoors Initialization & Usage

MapsIndoors is a shared instance, which can be described as the data layer of the SDK. Below you will find an example that demonstrates how initialization has been simplified between v3 and v4.

Initialization

v3

In v3 you would start the SDK by providing a MapsIndoors API key and a Google API key, in order to start loading a solution.

MPMapsIndoors.provideAPIKey("YOUR_MAPSINDOORS_API_KEY", googleAPIKey: "YOUR_GOOGLE_API_KEY")

In order to wait until MapsIndoors had finished loading the solution, you would call synchronizeContent with a completion.

MPMapsIndoors.synchronizeContent { error in
  // The SDK has finished loading
}

In v3 you had no real way to close the MapsIndoors SDK, releasing system resources when no map is shown.

In v3, you would access MapsIndoors data via data providers or services, e.g:

let solution = try await MPSolutionProvider().solution()
                
let venues = try await MPVenueProvider().venues()

let locations1 = try await MPLocationsProvider().locations()
                
let locations2 = try await MPLocationService.sharedInstance().locations(using: MPQuery(), filter: MPFilter())

In v4, we have improved the interface to initiate the SDK for smaller and safer implementations. In v4 you start loading a solution with a MapsIndoors API by:

do {
    try await MPMapsIndoors.shared.load(apiKey: "YOUR_MAPSINDOORS_API_KEY")
} catch {
    // Do something with the thrown error
    print(error)
}

Note that this is async/await and therefore requires an asynchronous context, and potentially throws an error if there were problems during loading MapsIndoors data. You can therefore be sure on the next line, that the SDK has either successfully loaded, or failed.

Additionally in v4, you can now close the SDK, releasing system resources when MapsIndoors is no longer actively needed for your application’s state.

MPMapsIndoors.shared.shutdown()

The Google API key is no longer set on MapsIndoors - but rather on MPMapConfig when creating MPMapControl.

In v4, everything data should be accessed via MPMapsIndoors.shared instance

let solution = MPMapsIndoors.shared.solution

let venues = await MPMapsIndoors.shared.venues()
                
let locations1 = await MPMapsIndoors.shared.locationsWith(query: MPQuery(), filter: MPFilter())

MapControl instantiation and initialization are separate concepts. You create a new instance of MPMapControl and configure it with a map and view.

To create a MPMapControl instance in v3, it was really straight forward.

let mapControl = MPMapControl(map: googleMapView)

In v4, in order to support multiple map engines, we have changed how you create a MPMapControl instance. You now have to call a factory function on MapsIndoors, and provide an MPMapConfig.

if let mapControl = MPMapsIndoors.createMapControl(mapConfig: mapConfig) {
  // MapControl instance
}

An MPMapConfig is a configurable wrapper around either a Google Maps or Mapbox view. Depending on which flavor of the SDK you are using, either of the following approaches will derive a MPMapConfig, which you can use to create a MPMapControl:

Google:

let mapConfig = MPMapConfig(gmsMapView: googleMapsView, googleApiKey: "AIza....")

Mapbox:

let mapConfig = MPMapConfig(mapBoxView: mapboxMapView, accessToken: "mapbox api key")

AppConfig and SolutionConfig can now be accessed with:

let solutionConfig = MPMapsIndoors.shared.solution?.config
solutionConfig?.collisionHandling = .removeLabelFirst
solutionConfig?.enableClustering = false

let appConfig = await MPMapsIndoors.shared.appData()

AppConfig is for applications specific information, you may want to store in MapsIndoors data for use in your application. AppConfig can be edited in the CMS. SolutionConfig is for adjusting SDK behavior and settings, e.g. enable or disable clustering of POIs. SolutionConfig can also be edited in the CMS.

Display rules have changed significantly between v3 and v4. The concept remains the same - each location has a rule, describing how it is rendered, and values are inherited from the location’s type’s display rule if not defined in the location’s own display rule.

The following code snippets show how to edit the display rule of a MapsIndoors location, and to undo the change.

let location = try await MPLocationsProvider().location(withId: "myLocationId")
if let displayRule = mapControl?.getEffectiveDisplayRule(for: location) {
    displayRule.showPolygon = true
    displayRule.polygonFillColor = .red
}

In order to modify a display rule, and later reset it (e.g. if you wanted to highlight the location temporarily), you would have to remember a copy of the display rule prior to modifying it. Then later, you can set the copied display rule onto the location.

var rememberedRule: MPLocationDisplayRule?

// Modifying for highlight
let location = try await MPLocationsProvider().location(withId: "myLocationId")
if let displayRule = mapControl?.getEffectiveDisplayRule(for: location) {
    rememberedRule = displayRule.copy() as? MPLocationDisplayRule
    displayRule.showPolygon = true
    displayRule.polygonFillColor = .red
}

// Resetting
if let originalDisplayRule = rememberedRule {
    mapControl?.setDisplayRule(originalDisplayRule, for: location)
}

You could access the built-in display rules either directly on your MPMapControl instance, or by name.

let selectionHighlight = mapControl?.locationHighlightDisplayRule
let blueDotDisplayRule = mapControl?.getDisplayRule(forTypeNamed:"my-location")
if let location = MPMapsIndoors.shared.locationWith(locationId: "myLocationId") {
    if let displayRule = MPMapsIndoors.shared.displayRuleFor(location: location) {
        displayRule.polygonVisible = true
        displayRule.polygonFillColor = .red
    }
}
if let location = MPMapsIndoors.shared.locationWith(locationId: "myLocationId") {
    if let displayRule = MPMapsIndoors.shared.displayRuleFor(location: location) {
        displayRule.reset()
    }
}

Resetting a display rule will return it to its initial values. Any values you can previously set, will be reverted back to CMS values.

The SDK has some display rules dedicated for some SDK specific rendering, which cannot be edited in the CMS, e.g. building outline, selection highlight, blue dot. These rules are not bound to any unique location, so instead you can fetch them using MPDisplayRuleType enum.

E.g. change the building outline stroke color and width, optionally used to highlight the current building.

let buildingOutlineRule = MPMapsIndoors.shared.displayRuleFor(displayRuleType: .buildingOutline)
buildingOutlineRule?.polygonStrokeColor = .blue
buildingOutlineRule?.polygonStrokeWidth = 10.0

The jump from v3 to v4 also introduces small differences in route directions querying and rendering.

var origin = MPPoint(lat: 38.897382, lon: -77.037447, zValue:0)
var destination = MPPoint.init()
private let renderer = MPDirectionsRenderer()

let directions = MPDirectionsService()
let directionsQuery = MPDirectionsQuery(originPoint: origin, destination: destination)

directions.routing(with: directionsQuery) { (route, error) in
    self.renderer.map = self.mapView
    self.renderer.route = route
    self.renderer.routeLegIndex = 0
    self.renderer.animate(5)
}
let origin = MPPoint(latitude:57.059884140172585, longitude: 9.939936105948238, z: 0)
let destination = MPPoint(latitude: 57.05718292988392, longitude: 9.930720035736968, z: 0)

let directionsQuery = MPDirectionsQuery(originPoint: origin, destinationPoint: destination)

let directionsService = MPMapsIndoors.shared.directionsService
let route = try? await directionsService.routingWith(query: directionsQuery)

let renderer = mapControl?.newDirectionsRenderer()
renderer?.fitBounds = true
renderer?.route = route
renderer?.animate(duration: 5)

App user roles as a feature remains the same, however the interface for getting available user roles and applying user roles has changed.

In v3 you would use a MPSolutionProvider instance to query a list of all available user roles for the loaded MapsIndoors solution. Applying user roles was done by assigning to the userRoles property on MapsIndoors.

MPSolutionProvider().getUserRoles { (userRoles, error) in
    if let janitorRole = userRoles.first(where: { role in role.userRoleName == "janitor" }) {
        MapsIndoors.userRoles = [janitorRole]
    }
}

In v4 the interface has been moved to the shared MPMapsIndoors instance, where the list of available user roles for a given solution can be found. Applying user roles is similar to v3, just assign to the userRoles property on the shared instance of MPMapsIndoors.

let allRoles = MPMapsIndoors.shared.availableUserRoles
            
if let janitorRole = allRoles.first(where: { userRole in userRole.userRoleName == "janitor" }) {
    MPMapsIndoors.shared.userRoles = [janitorRole]
}

In v4, we have introduced MPFilterBehavior and MPSelectionBehavior. These object contains behavioral configuration to describe how and if the camera should behave. The following can be configured:

  • var moveCamera: Bool { get set }

  • var showInfoWindow: Bool { get set }

  • var allowFloorChange: Bool { get set }

  • var animationDuration: Int { get set }

E.g. say you want to select a location, but not move the camera to the location:

let selectionBehavior = MPSelectionBehavior.default
selectionBehavior.moveCamera = false
mapControl.select(location: location, behavior: selectionBehavior)

In v3, there was a convenience method to easily move the camera to a given MPLocation.

if let location = MPLocationsProvider().location(withId: "myLocationId") {
    mapControl?.go(to: location)
}

In v4 the goTo(...) convenience method has been expanded upon, so it can be used with anything adhering to the MPEntity protocol, which includes MPLocation, MPBuilding, MPVenue, and even your own data types, as long as they adhere to MPEntity.

if let location = MPMapsIndoors.shared.locationWith(locationId: "myLocationId") {
    mapControl.goTo(entity: location)
}
if let venue = MPMapsIndoors.shared.venueWith(id: "venue id") {
    mapControl.goTo(entity: venue)
}
if let building = MPMapsIndoors.shared.buildingWith(id: "building id") {
    mapControl.goTo(entity: building)
}

You can filter content on the map - say you only wanted to show all meeting rooms on the map.

In v3, you could set searchResults on your MPMapControl instance, to only show a list of locations.

let query = MPQuery()
let filter = MPFilter()
filter.types = ["MeetingRoom"]

MPLocationService.sharedInstance().getLocationsUsing(query, filter: filter) { (locations, error) in
    mapControl?.searchResult = locations
}

In v4, you can use an MPFilter directly to apply a filter on your MPMapControl instance.

let filter = MPFilter()
filter.types = ["MeetingRoom"]
mapControl.setFilter(filter: filter, behavior: .default)

You can also still simply use an array of MPLocation to set a filter on the map.

let filterBehavior = MPFilterBehavior.default
filterBehavior.moveCamera = false
filterBehavior.allowFloorChange = false

mapControl.setFilter(locations: myLocations, behavior: filterBehavior)

To clear the map filter, and return to normal displaying, call clearFilter()

mapControl.clearFilter()

The interfaces for using position providers with MapsIndoors, was bloated in v3, so you would have to implement a lot more behavior than was strictly necessary. In v4 we have trimmed down the interface, to ease integrations with positioning systems.

In v3, the MPPositionProvider protocol required that you implemented your positioning integration in a particular way.

protocol MPPositionProvider {
    
    var preferAlwaysLocationPermission: Bool
    
    var locationServicesActive: Bool
    
    var delegate: MPPositionProviderDelegate?
    
    var latestPositionResult: MPPositionResult?
    
    var providerType: MPPositionProviderType
    
    func requestLocationPermissions()
    
    func updateLocationPermissionStatus()
    
    func startPositioning(_ arg: String?)
    
    func stopPositioning(_ arg: String?)
    
    func startPositioning(after millis: Int32, arg: String?)
    
    func isRunning() -> Bool
    
}

protocol MPPositionProviderDelegate {
    
    func onPositionUpdate(_ positionResult: MPPositionResult)
    
    func onPositionFailed(_ provider: Any)
    
}

Even the simplest possible provider would look like:

class MockPositionProvider : NSObject, MPPositionProvider {
    
    var delegate: MPPositionProviderDelegate?
    
    var latestPositionResult: MPPositionResult?
    
    var providerType: MPPositionProviderType = .GPS_POSITION_PROVIDER
    
    var preferAlwaysLocationPermission: Bool = true
    
    var locationServicesActive: Bool = true
    
    private var running = false

    private func updatePosition() {
        if running {
            latestPositionResult = MPPositionResult()
            latestPositionResult?.geometry = MPPoint(lat: Double.random(in: 0...90), lon: Double.random(in: 0...90))
            delegate?.onPositionUpdate(latestPositionResult!)
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                self.updatePosition()
            }
        }
    }
    
    func startPositioning(after millis: Int32, arg: String?) {
        DispatchQueue.main.asyncAfter(deadline: .now() + (0.001 * Double(millis))) {
            self.startPositioning(arg)
        }
    }
    
    func startPositioning(_ arg: String?) {
        running = true
        updatePosition()
    }

    func stopPositioning(_ arg: String?) {
        running = false
    }
    
    func requestLocationPermissions() {
        // request system permissions for positioning
    }
    
    func updateLocationPermissionStatus() {
        // update system permissions status for positioning
    }

    func isRunning() -> Bool {
        return running
    }

}

For v4, we have simplified the position provider protocol for MPPositionProvider and MPPositionProviderDelegate, which now looks like:

public protocol MPPositionProvider {
    var delegate: MPPositionProviderDelegate? { get set }
    var latestPosition: MPPositionResult? { get }
}

public protocol MPPositionProviderDelegate {
    func onPositionUpdate(position: MPPositionResult)
}

MPPositionResult has also been simplified.

Here is a small example of a mock implementation:

class MockPositionProvider: MPPositionProvider {
    
    var delegate: MPPositionProviderDelegate?
    
    var latestPosition: MPPositionResult?

    func simulate() {
        latestPosition = MPPositionResult(coordinate: CLLocationCoordinate2D(latitude: Double.random(in: 0...90), longitude: Double.random(in: 0...90)))
        delegate?.onPositionUpdate(position: latestPosition!)
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.simulate()
        }
    }
    
}

You attach it to the MapsIndoors SDK, by setting it on your MPMapControl instance (and enable showUserPosition)

let positionProvider = MockPositionProvider()
mapControl.showUserPosition = true
mapControl.positionProvider = positionProvider

positionProvider.simulate()

Creating custom Location Sources.

To create MPLocationUpdate instances, you would simply call the init:

MPLocationUpdate.init(id: ["LOCATION ID"], from: ["LOCATION OBJECT"])

Then inside viewDidLoad you register your custom sources:

MapsIndoors.register([
    MyCustomSource.init(type: "Robot")
])

The concept for registering custom location sources is very similar to that of v3. In that you create your own custom Location Sources, however the way to create create MPLocationUpdate is slightly different.

MPMapsIndoors.createLocationUpdateFactory().updateWithId(id: ["LOCATION ID"], from: ["LOCATION OBJECT"])

And for registering the sources, after initializing the SDK, you call the register method:

 Task {
        try await MPMapsIndoors.shared.load(apiKey: ["API KEY"])
        mapControl = MPMapsIndoors.createMapControl(mapConfig: ["MAP CONFIG"])
        /***
        Inside `viewDidLoad`, after initialising the SDK, register the sources
        ***/
        MPMapsIndoors.shared.register([
            MyCustomSource(type: "Robot")
            ])

MapsIndoors Data

v4

MapsIndoors Data

MapControl Initialization

v3

v4

SolutionConfig & AppConfig

Display Rules

v3

Editing a display rule

Resetting display rules

Editing built-in SDK display rules

v4

Editing a display rule

Resetting display rules

Editing built-in SDK display rules

DirectionsService & DirectionsRenderer

v3

v4

App User Roles

v3

v4

Map & Camera Behavior Configs

The "Go-To" Function

v3

v4

Map Filtering

v3

v4

Positioning Providers

v3

v4

Location Data Sources

v3

v4

​
changelog
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​