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

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

    Version

    Current public version is: 0.4.16

    Installation

    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
    

    Usage

    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
                }
            }
        }    
    }
    
    /// OBJECTIVE-C
    - (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
    
    /// OBJECTIVE-C
    self.mapBoxHelper.followingUser = YES;
    

    Floor

    New map plugin provides easy handlers for map floor navigation:

    /// SWIFT
    /// force the map to change to upper floor
    mapBoxHelper?.floorUp()
    
    /// force the map to change to lower floor
    mapBoxHelper?.floorDown()
    
    /// force the map to change to user specified floor
    mapBoxHelper?.floorAt(5)
    
    /// get current floor of the map
    let floor = mapBoxHelper?.mapFloor
    
    
    /// OBJECTIVE-C
    /// 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
    }) 
    
    
    /// OBJECTIVE-C
    /// 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.

    Routing

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

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

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

    /// SWIFT
    /// start route
    mapBoxHelper?.routeStart()
    
    /// stop route
    mapBoxHelper?.routeCancel(silent: true)
    
    
    /// OBJECTIVE-C
    /// 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)
    

    PIORouteOptions

    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.

    Database

    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

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

    Delegates

    ProximiioMapBox exposes two delegates with different scopes:

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

    ProximiioMapboxInteraction

    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
        }
    

    ProximiioMapboxNavigation

    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
        }        
    

    Models

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

    PIORouteUpdateType

    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
    }
    

    PIORouteUpdateData

    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)
        }
    }
    

    PIOGuidanceDirection

    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
        }
    

    PIOHeading

    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.

    PIOLandmark

    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.

    Extra

    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 {
                                callback(true)
                            }
    
                            if let image =  image, let url = url {
                                ImageCache.default.store(image, forKey: url.absoluteString)
                            }
                        }
                    }
                }
            }
        }
    

    Troubleshooting

    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'
            end
        end
    end
    

    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'
            end
        end
    end
    

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