MapwizeSDK on iOS

The Mapwize iOS SDK allows you to add indoor maps and wayfinding in your iOS apps. After your map has been created in Mapwize Studio, you can use this SDK to display the map in your app and let the user interact with it.

This SDK only comes with the core MapView and API and is intended for the advanced Mapwize integrations. For a first integration of Mapwize in your project, please consider Mapwize UI.

Open-source Mapwize UI

If you are looking for a fully featured and ready to use View to add Mapwize Indoor Maps and Navigation in your iOS app, have a look at Mapwize UI. This open-source project enriches the core SDK with interfaces for search and directions, that you can use as is or modify to your taste.

We are ourselves using Mapwize UI to build the Mapwize app available on the App Store.

Mapbox

The Mapwize iOS SDK is built on top of Mapbox GL native for iOS.

The Mapbox map is used as base map to display the outdoor. It is an amazingly powerful SDK allowing you to do a lot of cool stuff with the map. If you want to move the map, rotate it, overlay your own data or more, you can do it directly by controlling the Mapbox map. Adding Mapwize does not remove any capability from Mapbox, it just adds more. Have a look at the Mapbox documentation to see all features.

With the Mapwize SDK, we are extending Mapbox adding the possibility of getting inside buildings. As you zoom on the map, you will automatically enter in buildings, see the different floors and be able to navigate inside. If you want to change floors, see different universes (views) of the building, draw directions inside or display the user's indoor location, then you'll interact with the Mapwize plugin.

Compatibility

Mapwize iOS SDK is compatible with iOS 10 and higher.

The SDK is written in Objective-C for maximum compatibility and performance. However, it is working and extensively tested in both Objective-C and Swift apps.

Adding Mapwize to your project

Cocoapod

Mapwize is available through CocoaPod. Using pod, all dependencies, including Mapbox, will be added automatically. If you do not want to use pod, you will need to manually download the MapwizeSDK framework as we as all dependencies.

Simply add the following line in your Podfile

pod 'MapwizeSDK'

Carthage

Mapwize is available through Carthage since 1.7.0.

Add the following lines to you Cartfile

github "IndoorLocation/indoor-location-ios" ~> 1.0.5
github "Mapwize/SSZipArchive" == 3.0.0
binary "https://www.mapbox.com/ios-sdk/Mapbox-iOS-SDK.json" ~> 5.4.0
binary "https://sdk.mapwize.io/mapwize-sdk-ios/Carthage/MapwizeSDK.json" ~> 3.0.0

Mapwize API Key

You'll need a Mapwize API key to load the plugin and allow API requests. Simply add MWZMapwizeApiKey with the key in your info.plist.

To get your own Mapwize API key, sign up for a free account at mapwize.io. Then within the Mapwize Studio, navigate to "API Keys" on the side menu.

Mapwize demo keys are available for testing in the demo projects. Please note they cannot be used in production.

Changing api key at runtime

In some case, you may want to display a map using a different api that the one used for initialization. For example, you displayed a first map for an organization A and you want to display another map for an organization B. The MWZMapwizeConfiguration is there for that.

Mapbox configuration

To run Mapbox on your device, you will need to add the following elements in your info.plist file:
- MGLMapboxAccessToken -> pk.mapwize
- MGLMapboxMetricsEnabledSettingShownInApp -> YES

The first one enables Mapbox to load the Mapwize style, while the second guarantees we provide the required information for Mapbox.
With these settings, a popup is shown to users when they click on the Mapwize logo (bottom left of the map).

Configuring the outdoor map

Mapwize SDK is using Mapbox for the outdoor map. There are 2 options regarding the outdoor:

Adding your first map

Here is the most simple demo ViewController in Swift:

import Foundation
import UIKit
import MapwizeSDK

class CreateMapViewController: UIViewController {
    private var mapwizeView: MWZMapView?
    private var mapwizeApi: MWZMapwizeApi?

    override func viewDidLoad() {
        super.viewDidLoad()
        let mapwizeConfiguration = MWZMapwizeConfiguration(apiKey: "YOUR_API_KEY")
        mapwizeApi = MWZMapwizeApiFactory.getApi(mapwizeConfiguration:mapwizeConfiguration)
        let options = MWZOptions()
        mapwizeView = MWZMapView(frame: self.view.frame, options: options, mapwizeConfiguration: mapwizeConfiguration)
        mapwizeView?.delegate = self
        mapwizeView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        self.view.addSubview(mapwizeView!)
    }
}
extension CreateMapViewController: MWZMapViewDelegate {
    func mapViewDidLoad(_ mapView: MWZMapView) {
        print("Mapwize is ready to be used")
    }
}

Mapwize plugin options

The plugin can be loaded with the following options available in the MWZOptions class:

Delegate

The Mapwize delegate provides callback for the events taking place on the map.

MWZClickEvent

In order to react to click events on the map, Mapwize provides an object that helps you know on which object the user clicked. It can be a venue, a place or just the map.

It is represented with 3 event types :

typedef enum MWZClickEventType: NSUInteger {
MAP_CLICK,
PLACE_CLICK,
VENUE_CLICK
}

The following attributes can be retrieved :

MWZClickEventType eventType;    // Enum, see above
MWZLatLngFloor* latLngFloor;    // The latLngFloor at which the click was made. The latitude and longitudes are always set, but the floor can be null. Available for all event types.
MWZPlace* place;                // Not null if eventType == PLACE_CLICK
MWZVenue* venue;                // Not null if eventType == VENUE_CLICK

A typical way to handle those event (in SWIFT):

func plugin(_ plugin: MapwizePlugin!, didTap clickEvent: MWZClickEvent!) {
    switch clickEvent.eventType {
        case VENUE_CLICK:
            let venue = clickEvent.venue
            // Do something with venue
            break
        case PLACE_CLICK:
            let place = clickEvent.place
            // Do something with place
            break;
        default:
            let latLngFloor = clickEvent.latLngFloor
            // Do something with coordinates
    }
}

Indoor Location

Displaying the user's location on the map is done by connecting an IndoorLocationProvider to Mapwize.

There are a lot of IndoorLocation providers already freely available as part of the IndoorLocation open-source framework.

If you are missing your provider, contact us at support@mapwize.io or build your own starting from the base classes.

To set the IndoorLocationProvider on the MapwizePlugin:
objective-c
- (void) setIndoorLocationProvider:(ILIndoorLocationProvider*) locationProvider;

If you want to manually set the user location, you can use the ManualIndoorLocationProvider

You can retrieve the current user position on the map using ILIndoorLocation* userLocation.

There is no delegate to be notified of any new user location. Subscribe to the IndoorLocationProvider's delegate instead.

The user's heading is also displayed on the map as an arrow from the user position. The heading is retrieved directly from the device. You can read the user heading using NSNumber* userHeading. It is not possible to manually set the user heading at this point.

FollowUserMode

You can use the follow user mode feature to automatically move the map as the user location changes.

3 modes are available on the MWZFollowUserMode class:

You can retrieve the current mode using the FollowUserMode followUserMode property and you can set it using

- (void) setFollowUserMode:(FollowUserMode) followUserMode;

The FollowUserMode is automatically set to NONE when the user manually moves the map or changes floor.

Venues

Indoor maps are defined inside venues. The map will automatically enter in a venue when the zoom is sufficient, and exit the venue when the map is moved away. Only one venue can be open at a time.

The currently displayed venue can be retrieved using the getVenue method

- (MWZVenue*) getVenue;

The method returns null if no venue is displayed on the map. The willEnterVenue, didEnterVenue and didExitVenue events from the delegate can be used.

Universes

Venues can have multiple universes. Universes are like views. In Mapwize Studio, it is possible to define which elements are displayed in each universe and define security policies for each of them.

When a venue is displayed, the method (MWZUniverse*) getUniverse will return the currently displayed universe for that venue, and (void) setUniverse:(MWZUniverse*) universe will change the universe.

You can set and get the universe for each venue using

- (void) setUniverse:(MWZUniverse*) universe forVenue:(MWZVenue*) venue;
- (MWZUniverse*) getUniverseForVenue:(MWZVenue*) venue;

Floors

Venues usually have multiple floors. Floors are identified by a number which can be decimal.

When a venue is displayed, the method (NSNumber*) getFloor will return the currently displayed floor for that venue and (NSArray<NSNumber*>*) getFloors will return the list of active floors for that venue. A floor is considered active if the geometry of one layer of that floor is intersecting with the visible region on the screen.

You can change floor using

- (void) setFloor:(NSNumber*) floor;
- (void) setFloor:(NSNumber*) floor forVenue:(MWZVenue*) venue;

The floorDidChange event is fired when the floor changes.
The floorsDidChange event is fired when the list of active floors changes, which may or may not happen at venue enter, venue exit, universe change or camera move.

Languages

The title of the places that are displayed on the map can be translated in multiple languages and you can control what language is used.

Firstly, you can set the preferered language of the user. By default, titles will be displayed in the preferred language if available in the venue. Otherwise, the main language of the venue is used.

- (void) setPreferredLanguage:(NSString*) language;
- (NSString*) getPreferredLanguage;

It is also possible to specify what language to use for a specific venue

- (void) setLanguage:(NSString*) language;
- (void) setLanguage:(NSString*) language forVenue:(MWZVenue*) venue;
- (NSString*) getLanguageForVenue:(MWZVenue*) venue;
- (NSString*) getLanguage;

Moving the map

The Mapbox map offers lots of options to move the camera viewing the map. Some specific methods are available on the MapwizePlugin to move the map towards Mapwize objects:

- (void) centerOnVenue:(MWZVenue*) venue forceEntering:(BOOL) force;
- (void) centerOnPlace:(MWZPlace*) place;
- (void) centerOnUser;

Please note that the centerOnVenue takes the forceEntering parameter. If set to false, the bounds of the maps are fit so that the entire venue is visible. For large campuses, this may mean that the zoom level is not high enough to enter the venue. If forceEntering is set to true, the map will be zoomed in to be sure that the venue is displayed, possibly not showing the entire campus.

If you want more flexibility with the centerOnVenue and centerOnPlace methods, you can use the center attribute of the MWZPlace and MWZVenue objects to build your own MGLCamera object and use the Mapbox methods to move the camera. Here is an exemple :

MGLMapCamera* camera = [[MGLMapCamera alloc] init];
camera.centerCoordinate = [place center];

// You can add more properties to the camera object if you want
// camera.altitude
// camera.pitch
// camera.bearing
// ...

[mapboxMapView setCamera:camera];
// Note that mapbox offers different setCamera methods allowing to control the animation

// If it is a place, don't forget to change the floor
if (place.floor) {
    [self setFloor:place.floor];
}

Adding markers

Markers is a convenient way to add simple pins on the map.

Mapwize Markers are positioned on a specific floor and therefore only displayed if that floor is selected. However, they are not attached to a specific venue and will be displayed even if the venue is not visible.

If you want to add more complex annotations on the map, you have all the power of Mapbox at your disposal. Have a look at their documentation

By default, the image used for the pin is the standard Mapwize pin. However, you can specify your own using an UIImage. The anchor of the marker is always the center of the image, meaning that it's always the center of the image that is on top of the coordinates you specified. If you want to have your marker only on top, simply use an image with transparency.

Promoting places

The title of places are displayed based on the zoom level. The objective is to display as many as possible without having collisions. By default, the order specified in Mapwize Studio is used to define which place is displayed first.

However, there are situations where you would like to change dynamically the order. For example, if the user clicks on a place and you display informations about it, you might want to make sure that the title of that place is displayed. Basically, you want to promote that place to the first position.

Promoting places make them come first on the rendering. Of course, the collision mechanism still apply so if 2 promoted places collide, then only the first in the promotion list comes first. Also, promoted places only show on their floor when their venue are visible.

Showing Direction

To display directions on the map, the first step is to compute them. For that, you'll need to use the API methods to get a MWZDirection object as described in the API section.

When you have a MWZDirection object, you can display it on the map using

- (void) setDirection:(MWZDirection*) direction;
- (void) setDirection:(MWZDirection *)direction  options:(MWZDirectionOptions*) options;

The first method will use defaut DirectionOptions.

Once a direction is set, you can retrieve it or remove it.

- (MWZDirection*) getDirection;
- (void) removeDirection;

Showing Navigation (Dynamic direction)

Navigation is used as direction is. The difference is that navigation show the evolution of the user on the direction line.

The navigation should be used only if the starting point of the direction is the user position and if you have a IndoorLocation system working in your venue.

In order to provide an understandable visualization, Mapwize recompute the IndoorLocation to put the user position dot at the most realistic position on the direction path. Below, you will read how to use this information to recompute direction if needed.

Styling places

Do you want to show if a meeting room is available or not, or color the prefered shops of the user? Then dynamic styling of places is what you are looking for.

You can overwrite the style of any place at any time using the setStyle function. Set the style to nil to return to the default style.

The available attributes for the style are

Offline

Maps can be made available offline using the MWZOfflineManager. When offline, the following features are available:

Data is downloaded for specific universes of specific venues.

If a venue/universe has been taken offline, all data for that venue/universe will come from the local database regarless the network availability. Changes made to the venue map on Mapwize Studio will not be available in the app until a new download is done. It is the developer's responsibility to trigger venue re-downloads.

MWZOfflineManager

To download content for a specific universe of a venue and make that venue/universe available offline, use downloadDataForVenue:

+ (void) downloadDataForVenue:(MWZVenue*) venue universe:(MWZUniverse*) universe success:(void (^)(void)) success progress:(void (^)(int)) progress failure:(void (^)(NSError* error)) failure;
+ (void) downloadDataForVenue:(MWZVenue*) venue universe:(MWZUniverse*) universe skipMapboxDownload:(BOOL) skipMapboxDownload success:(void (^)(void)) success progress:(void (^)(int)) progress failure:(void (^)(NSError* error)) failure;

To update the local data for a venue, the same downloadDataForVenue method can be used again.

If a venue/universe does not need to be offline anymore, removeDataForVenue can be used to delete all data from database and filesystem.

+ (void) removeDataForVenue:(MWZVenue*) venue universe:(MWZUniverse*) universe;

Note: After removing or downloading data, displayed maps need to be refreshed using MapwizePlugin#refreshWithVenue:(MWZVenue*) venue universe:(MWZUniverse*) universe. Otherwise, maps might not display properly or be inconsistent.

The following methods allow you yo check which venues and universes are available offline.

// Check if a venue/universe is offline or not
+ (BOOL) isOfflineForVenue:(MWZVenue*) venue universe:(MWZUniverse*) universe;

// Get the list of offline venues
- (NSArray<MWZVenue*>*) getOfflineVenues;

// Get the list of offline universes for the given venue
- (NSArray<MWZUniverse*>*) getOfflineUniversesForVenue:(MWZVenue*) venue;

API

A complete set of functions are available to query raw Mapwize objects. Some API functions are available offline if the venue and universe was downloaded using the MWZOfflineManager. The API documentation is available in the advanced documentation.

Custom Server Url

If you are using a custom instance of Mapwize server, you have to set the api URL with the key MWZServerUrl in your info.plist or use a custom MWZMapwizeConfiguration with serverUrl.

The default value is https://api.mapwize.io/

Evolution and support

For any question or request, please contact us at support@mapwize.io.