NAV Navbar
  • Introduction
  • Version
  • Installation
  • Usage
  • Function & Helpers
  • Database
  • Delegates
  • Models
  • Extra
  • Troubleshooting
  • Introduction

    Welcome to the MapBox iOS SDK reference, an easy helper to have fully featured map interactions and routing solution.


    Current public version is: 0.4.16


    Installation in managed by Cocoapods, (if you don't already have it installed, see the "Getting Started" guide).

    Add simply a new line in your file like this:

    pod 'Proximiio'
    pod 'ProximiioMapbox`

    And then proceed installing open your terminal to the directory where the Podfile is stored and run this command:

    pod install


    In order to use the ProximiioMapBox plugin we need to have installed and working Proximiio, in particular add support for Synchronization and caching.

    Here a simple overview on how use it:

    /// SWIFT
    /// setup map and proximiio integration
    fileprivate func setupMap() {
        /// setup map
        let mapToken = Proximiio.sharedInstance()?.token() ?? ""
        Proximiio.sharedInstance()?.delegate = self
        let config = ProximiioMapboxConfiguration(token: mapToken)
        /// prepare map
        mapView = MGLMapView(frame: view.frame)
        /// setup ProximiioMapbox handler
        if let mapView = mapView {
            mapBoxHelper = ProximiioMapbox(mapView: mapView, configuration: config)
            mapBoxHelper?.initialize { result in
                if result == .success {
                    self.mapBoxHelper?.mapNavigation = self
                    self.mapBoxHelper?.mapInteraction = self
    - (void) setupMap {
        NSString *mapToken = [[Proximiio sharedInstance] token];
        ProximiioMapboxConfiguration *configuration = [[ProximiioMapboxConfiguration alloc] initWithToken:mapToken];
        self.mapView = [[MGLMapView alloc] initWithFrame:self.view.frame];
        [self.view addSubview:self.mapView];
        if (self.mapView != NULL) {
            self.mapBoxHelper = [[ProximiioMapbox alloc] initWithMapView:self.mapView configuration:configuration apiVersion:@"v5"];
            [self.mapBoxHelper initialize:^(enum ProximiioMapboxAuthorizationResult result) {
                if (result == ProximiioMapboxAuthorizationResultSuccess) {
                    self.mapBoxHelper.mapNavigation = self;
                    self.mapBoxHelper.mapInteraction = self;

    Function & Helpers

    ProximiioMapbox provides you some functions and helpers to fast manage your implementation.

    Here listed the most relevant ones.

    Follow user position

    Library has built-in automation to follow user position, you can enable/disable that with a simple snippet.

    /// SWIFT
    mapBoxHelper?.followingUser = true
    self.mapBoxHelper.followingUser = YES;


    New map plugin provides easy handlers for map floor navigation:

    /// SWIFT
    /// force the map to change to upper floor
    /// force the map to change to lower floor
    /// force the map to change to user specified floor
    /// get current floor of the map
    let floor = mapBoxHelper?.mapFloor
    /// force the map to change to upper floor
    [self.mapBoxHelper floorUp];
    /// force the map to change to lower floor
    [self.mapBoxHelper floorDown];
    /// force the map to change to user specified floor
    [self.mapBoxHelper floorAt:1];
    /// get current floor of the map
    NSUInteger floor = self.mapBoxHelper.mapFloor;

    Map position helper

    You can easily manage to move the map with some quick helpers:

    /// SWIFT
    /// center the map to user position    
    mapBoxHelper?.centerAtUser(zoom: Double = 18, animated: Bool = true, completed: { success in 
        /// callback on completed
    /// center the map to the specified feature    
    mapBoxHelper?.centerAtFeature(_ feature: ProximiioGeoJSON, zoom: Double = 18, animated: Bool = true, completed: { success in 
        /// callback on completed
    /// center the map to user position    
    [self.mapBoxHelper centerAtUserWithZoom:18 animated:YES
                                      completed:^(BOOL) {
    /// center the map to the specified feature    
    [self.mapBoxHelper centerAtFeature:feature zoom:18 animated:YES completed:^(ProximiioGeoJSON * _Nonnull) {
        /// callback on completed    

    Both the two functions expose a callback that can be optionally triggered when the animation ends.


    We provide a built-in, offline, solution to calculate routes between user position and a target POI.

    /// SWIFT
    mapBoxHelper?.route(destination: feature, preview: false)
    [self.mapBoxHelper routeWithDestination:feature preview:YES options: nil];

    Once a route has been calculated you can proceed starting/stopping it:

    /// SWIFT
    /// start route
    /// stop route
    mapBoxHelper?.routeCancel(silent: true)
    /// start route
    [self.mapBoxHelper routeStart:nil];
    /// stop route
    [self.mapBoxHelper routeCancelWithSilent:YES];

    Routes can be calculate according some specific requirements, we add a PIORouteOptions model that take care of this.

    We provided also some quick helper for preview and auto start like:

    mapBoxHelper?.routeFindAndStart(destination: feature, options: options)
    mapBoxHelper?.routeFindAndPreview(destination: feature, options: options)

    Is also possible request a route between two POIs, using this function:

    mapBoxHelper?.routeFind(from: featureA, to: featureB, options: options, previewRoute: false, startRoute: false)

    Or totally from a custom position and level:

    mapBoxHelper?.routeFind(from: coordinate, level: 0, to: featureB, options: options, previewRoute: false, startRoute: false)


    This model provide information and limitation to be applied by the offline algorithm that generates the route to a POI.

    The tweakable values are:

    let options = PIORouteOptions()
    options.avoidBarriers = false
    options.avoidElevators = false
    options.avoidEscalators = false
    options.avoidNarrowPaths = false
    options.avoidRamps = false
    options.avoidRevolvingDoors = false
    options.avoidStairs = false
    options.avoidTicketGates = false

    By default all the values are set to false.


    ProximiioMapbox has an embedded local database to keep POI information.

    You can easily access it using PIODatabase.sharedInstance() shared object.

    let db = PIODatabase.sharedInstance()
    // amenities
    let amenities = db.amenities
    // features
    let poi = db.features
    // poi
    let poi = db.pois
    // poi and level changers
    let poi = db.poisAndLevelChanger

    Each is an array of elements of type ProximiioGeoJSON that provide out of the box helpers for different information about the entity.


    ProximiioGeoJSON model has automated localization handling for some fields like description and title. In order to use feel free to use helpers like getTitle().


    ProximiioMapBox exposes two delegates with different scopes:

    Their implementation and naming can have some difference between swift and objective-c implementation, refer below.


    Takes care of providing delegate for interaction on the mapbox instance like: changing floor, tapping on map or request a re-route.

    // Objective-C
    - (void)changeWithFloor:(NSInteger)floor;
    - (void)onTapWithFeature:(ProximiioGeoJSON * _Nonnull)feature;
    - (void)onRequestReRoute;
    /// Swift
        func change(floor: Int) {
            // triggered when floor has changed
        func onTap(feature: ProximiioGeoJSON) {
            // triggered if user taps on a POI
        func onRequestReRoute() {
            // triggered if a re-route is manually requested


    Takes care of providing delegate for events connected to a navigation.

    // Objective-C
    - (void)onRouteWithRoute:(PIORoute * _Nullable)route;
    - (void)routeEventWithEventType:(enum PIORouteUpdateType)type text:(NSString * _Nonnull)text additionalText:(NSString * _Nullable)additionalText data:(PIORouteUpdateData * _Nullable)data;
    - (void)onHazardEntered:(ProximiioGeoJSON * _Nonnull)hazard;
    - (void)onSegmentEntered:(ProximiioGeoJSON * _Nonnull)segment;
    - (void)onDecisionEntered:(ProximiioGeoJSON * _Nonnull)decision;
    - (void)onLandmarkEntered:(NSArray<PIOLandmark *> * _Nonnull)landmark;
    - (void)onHazardExit:(ProximiioGeoJSON * _Nonnull)hazard;
    - (void)onSegmentExit:(ProximiioGeoJSON * _Nonnull)segment;
    - (void)onDecisionExit:(ProximiioGeoJSON * _Nonnull)decision;
    - (void)onLandmarkExit:(NSArray<ProximiioGeoJSON *> * _Nonnull)landmark;
    // SWIFT
        func onRoute(route: PIORoute?) {
            // triggered if a route has been found
        func routeEvent(eventType type: PIORouteUpdateType, text: String, additionalText: String?, data: PIORouteUpdateData?) {
            // triggered if a route event happen
        func onHazardEntered(_ hazard: ProximiioGeoJSON) {
            // triggered if user is close to hazard
        func onSegmentEntered(_ segment: ProximiioGeoJSON) {
            // triggered if user has entered a new segment
        func onPositionUpdate(_ position: CLLocationCoordinate2D) {
            // useful to have current user position
        func onHeadingUpdate(_ heading: Double) {
            // useful to have current user heading
        func onDecisionEntered(_ decision: ProximiioGeoJSON){
            // useful to have a decision poi
        func onLandmarkEntered(_ landmark: [PIOLandmark]){
            // useful to have landmarks information
        func onHazardExit(_ hazard: ProximiioGeoJSON){
            // hazard exit
        func onSegmentExit(_ segment: ProximiioGeoJSON){
            // segment exit
        func onDecisionExit(_ decision: ProximiioGeoJSON){
            // decision exit
        func onLandmarkExit(_ landmarks: [ProximiioGeoJSON]){
            // landmark exit


    The library makes use of several model and primitives. Here a list of the most relevant, their scope and values.


    This enum is used on routeEvent response, it easily provide you information about how to handle the visual interfance for the navigation.

    Supported values are the following:

    @objc public enum PIORouteUpdateType: Int {
        case calculating, recalculating // if route is being calculate or re-calculated
        case routeNotfound // if route fails to be generated
        case canceled // if the user dimiss a route
        case  finished // if the user has reached the end of a route
        // priority of the update
        case new, update, soon, immediate


    This model provides a reference to the current node of the route involved in an update. If exists it provides also a reference to the next node with a similar structure (but with optional values).

    @objc public class PIORouteUpdateData: NSObject {
        /// current index of the node is processed from the route nodeList
        @objc public let nodeIndex: Int
        /// bearing of current node
        @objc public let stepBearing: Double
        /// direction
        @objc public let stepDirection: PIOGuidanceDirection
        /// distance of the node
        @objc public let stepDistance: Double
        // optional reference to the next step
        @objc public let nextStepBearing: Double?
        @objc public let nextStepDistance: Double?
        @objc public let nextStepDirection: PIOGuidanceDirection?
        /// current position
        @objc public let position: CLLocationCoordinate2D
        /// remaining distance in meters
        @objc public let pathLengthRemaining: Double
        public var stepHeading: PIOHeading {
            return calculateHeading(stepBearing.degreeNormalized)


    This model provide an helper to the direction of the user.

    @objc public enum PIOGuidanceDirection: Int, Equatable {
        case start // beginning of the route
        case turnAround // when user need to change direction
        case finish // user reaches the end
        case straight // continue straight
        /// turn types
        case leftSlight, leftNormal, leftHard
        case rightSlight, rightNormal, rightHard
        /// level change types
        case upElevator, upEscalator, upStairs
        case downElevator, downEscalator, downStairs

    The type of turn is calculated agains the degree between user position and node according to this logic:

        /// return current information about guidance direction
         func degreesToStepDirection() -> PIOGuidanceDirection {
            let test = self.degreeNormalized
            if fabs(test) < 22.5 { return .straight }
            if fabs(test) > 157.2 { return .turnAround}
            if test < -112.5 { return .leftHard}
            if test <= -67.5 { return .leftNormal}
            if test <= -22.5 { return .leftSlight}
            if test > 157.5 { return .rightHard}
            if test >= 67.5 { return .rightNormal}
            if test >= 22.5 { return .rightSlight}
            return .straight


    This model provide an helper to the heading of the route.

    @objc public class PIOHeading: NSObject {
        @objc public var text: String
        @objc public var rotation: Double

    It exposes a degree value in rotation and a text, localized, about heading direction.


    It takes care of provide information about any landmark the routing system is able to discover close to current user location.

    It provides two sub variables side and feature.

    Side is an enum that give you information on the side the landmark is:

    @objc public enum PIOLandmarkSide: Int {
        case left, right

    Feature is a normal ProxmiioGeoJSON object.


    Preload POI images

    Map can make use of images for POI and Amenities, an interesting way to boost performance and lower time-await is to preload that before app starts.

    In combination with Kingfisher (that you have to install as third party pod), you can easily create a function like the one presented below.

    Looping the PIODatabase will be possible to force pre-caching of the images needed.

    Actually we suggest to run this func when both the syncAmenities and syncFeatures are finished.

    import ProximiioMapbox
    private func preloadFeatureImages(callback: @escaping ((Bool) -> Void)) {
            var completed = 0
            PIODatabase.shared.features.forEach { feature in
                feature.images.forEach {
                    if let imgUrl = URL(string: $0) {
                        completed += 1
                        ImageDownloader.default.downloadImage(with: imgUrl, retrieveImageTask: nil, options: [], progressBlock: nil) { (image, _, url, _) in
                            completed -= 1
                            if completed == 0 {
                            if let image =  image, let url = url {
                      , forKey: url.absoluteString)


    If the library produce error on build, try add these few lines at the bottom of your Podfile.

    post_install do |installer|
        installer.pods_project.targets.each do |target|
            target.build_configurations.each do |config|
                config.build_settings['SWIFT_VERSION'] = '5.2'
                config.build_settings['ENABLE_BITCODE'] = 'NO'

    Instead if during submisison you receive a warning mail for Too many simbols you can tweak your podfile like below:

    post_install do |installer|
        installer.pods_project.targets.each do |target|
            target.build_configurations.each do |config|
                config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf'

    If needed you can even combine the two above in one solution.