IOS Integration

Overview

Mist SDK will provide you the indoor blue dot experience using Mist’s 16 vBLE antenna array Access point. Using this SDK you will know where the user is and can provide the proximity-related notification using Mist patented vBeacon technology.
MistSDK DR uses a dead reckoning approach to calculate the user’s current position by using a previous position and advancing that position based on known and estimated speeds over elapsed time. Meaning DR is designed to take all location information available that a user had when connected and work the same as though the client is connected, even when experiencing a disconnect or blimp in the connection.

Mist SDK(iOS) supports DR and Non-DR versions. It is compatible with Objective C and Swift 4.2 or later.

Mist iOS vBLE SDK supports following features:

  1. Zones and vBLE events callbacks
  2. App Wake Up
  3. Maps supported

System requirements

  1. Deployment Target: 10.1 or later
  2. Xcode : 10.1 or later
  3. Mist AP wireless network infrastructure
  4. BLE enabled iOS device
  5. Access to Mist Account

App Permissions

MistSDK will require your iOS App to access location, Bluetooth, accelerometer and internet permissions on device. You need to add the following keys to Info.plist file in your project:

  1. Location: NSLocationWhenInUseUsageDescription and NSLocationAlwaysAndWhenInUseUsageDescription key is required to access location.
  2. Internet: NSAppTransportSecurity<dictionary>, NSAllowsArbitraryLoads key enabled as true, to allow internet access in your iOS app.
  3. Bluetooth: NSBluetoothPeripheralUsageDescription(deprecated from iOS 13.1 or later) and NSBluetoothAlwaysUsageDescription are required to allow the ability to connect to bluetooth peripherals.
  4. Accelerometer: NSMotionUsageDescription key is required in your app to access the device accelerometer.
<key>NSAppTransportSecurity</key>
   <dict>
   <key>NSAllowsArbitraryLoads</key>
      <true/>
   </dict>
<key>NSMotionUsageDescription</key>
<string>(Insert description)</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>(Insert description)</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>(Insert description)</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>(Insert description)</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>(Insert description)</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>(Insert description)</string>

Installation using Cocoa-pods:

Follow the steps to integrate Cocoa-Pod in Xcode project or [Refer CocoaPods Getting Started guide]::

  • Open terminal and change directory to your project folder, create and initialize Podfile using commands below.
$ cd ./project_folder_path
$ sudo gem install cocoapods
$ pod init
  • Open the Podfile with a text editor and add < pod ‘MistSDK’> component to the pod file. For instance:
//for Non-DR, use <pod 'MistSDK'>
target 'MyApp' do
   #Pods for MyApp
   pod 'MistSDK'
end

// for DR, use < pod 'MistSDKDR' >.
target 'MyApp' do
   #Pods for MyApp
   pod 'MistSDKDR'
end
  • Go back to the terminal and Run <$pod install> in your project directory
$pod install
  1. Open MyApp.xcworkspace and build.
  2. Add import MistSDK in swift OR #import <MistSDK/MistSDK.h> in Objective c to get started.

Note: Mist SDK DR version is not compliant with bitcode. You need to set BitCode -> Enable = No in the build setting of your XCode Project.

Installation – Manually using framework:

  1. To get ‘MistSDK – Non-DR’ version:
    a. Download zip SDK Releases OR git clone from the terminal.
  2. To get ‘MistSDK – DR’ version:
    a. Download zip SDK Releases.
  3. For latest Non-DR version, go to folder mist-vble-ios-sdk > Frameworks > 1.5.58 to get MistSDK.framework .
    (folderPath mist-vble-ios-sdk/Frameworks/1.5.58/MistSDK.framework) .
  4. Similarly, for latest DR version, go to mist-vble-ios-sdk-dr2 > Frameworks > 1.5.272-dr to get MistSDK.framework .(folderPath mist-vble-ios-sdk/Frameworks/1.5.272-dr/MistSDK.framework) .
  5. Drag and drop the MistSDK.framework in the project file.(enable the checkbox in Options > Copy files if needed)
  6. In your Xcode project file add MistSDK.framework to Targets > Build Phases > Embed Frameworks OR Link Binary with libraries.
  7. Add import MistSDK in swift OR #import <MistSDK/MistSDK.h> in Objective c.

Integrate Mist SDK [Swift/Objective c]

  1. Get Mobile SDK secret from Mist Portal: Get the Mobile SDK Secret from the following path: Mist Login -> Organization -> Mobile SDK -> secret. [Refer FAQs: where can I find my secret key?]
  2. Enroll your device with Mobile SDK secret:
    a. Use the MobileSDK secret to enroll your device to the Organization using MSTOrgCredential. (Refer Objective  C/Swift Code below) .
    b. Once enrolled, you will receive org_id and secret (secretToken) from response which is required to initialize MSTCentralManager.

    //Objective c
    [MSTOrgCredentialsManager enrollDeviceWithToken:@"(Mist Portal - Mobile SDK secret)" onComplete:^(NSDictionary *response, NSError *error) {
       NSLog(@"OrgName %@", [response objectForKey:@"name"]);
       NSLog(@"orgId %@", [response objectForKey:@"org_id"]);
       NSLog(@"secretToken %@", [response objectForKey:@"secret"]);
    }];
    //Swift
    MSTOrgCredentialsManager.enrollDevice(withToken:"(Mist Portal - Mobile SDK secret)", onComplete: { response, error in 
          guard error == nil, response != nil, let env = secret.first else {
          print("Error: Cannot enroll devices to organization. \n\(String(describing: error))")
          return
          } 
       guard let response = response,
       let orgName = response["name"] as? String,
       let orgId = response["org_id"] as? String,
       let secretToken = response["secret"] as? String else {
          print("Error: Cannot retrieve org or secret from org enrollment")
          return
          }
    })
  3. Initialize MSTCentralManager:
    MSTCentralManager object is used to start and stop the delivery of location-related events to your app.

    //Objective c
    self.mstCentralManager = [[MSTCentralManager alloc] initWithOrgID:orgID AndOrgSecret:orgSecret];
    self.mstCentralManager.delegate = self;
    [self.mstCentralManager setAppState:[[UIApplication sharedApplication] applicationState]];
    [self.mstCentralManager setEnviroment:env.uppercaseString]; // Set SDK Environment
    //Swift
    self.mstCentralManager = MSTCentralManager(orgID: org_id, andOrgSecret: secret)
    self.mstCentralManager?.delegate = self
    self.mstCentralManager?.setAppState(UIApplication.shared.applicationState)
    self.manager?.setEnviroment(env.uppercased()) // Set SDK Environment
  4. Location information:
    a. To start receiving location update use the code below

    //Objective c 
    [self.mstCentralManager startLocationUpdates];
    //Swift
    self.mstCentralManager?.startLocationUpdates()

    b. To stop receiving location update use the clode below. This method is called whenever your code no longer needs to receive location events.

    //Objective c 
    [self.mstCentralManager stopLocationUpdates];
    //Swift
    self.mstCentralManager?stopLocationUpdates()
  5. MSTCentralManagerDelegate protocol: MSTCentralManager adopts MSTCentralManagerDelegate protocol and provides you the indoor location events. Implement this protocol in your class.c. Get Map info:

    You can get the map detail of your current map from the object MSTMap. MSTMap provides you the mapId, mapName and mapURL to render the map on the device. ‘didUpdateMap’ method is used to get the map detail whenever a new map is available.

    MSTMap object contains the following variable:

    mapName

    mapId

    ppm: Pixel per meter

    mapType: MapTypeIMAGE (.IMAGE)

    mapURL

    mapWidth, mapHeight

    siteId: Site id for that map

    orientation

    Important Note:
    We have removed the auto download image feature from the MSTMap Object. You will not see the mstMap.Image property. Please use mapURL to download the image on App side.

    //objective-c
    -(void)mistManager:(MSTCentralManager *)manager didUpdateMap:(MSTMap *)map at:(NSDate *)dateUpdated{
       if(map != nil)
       {
          self.ppm = map.ppm;
          if (self.currentMap.mapId != map.mapId) {
             self.currentMap = map;
             [self addFloorMap:self.currentMap.mapURL];
          }
          else{
             [self addFloorMap:self.currentMap.mapURL];
          }
       }
    }
    //Swift
    func mistManager(_ manager: MSTCentralManager!, didUpdate map: MSTMap!, at dateUpdated: Date!){
    DispatchQueue.main.async {
          guard let newMap = map, let mapURL = map.mapURL, newMap.mapType == .IMAGE else {
             return
          }
          self.ppm = newMap.ppm
          if let previousMap = self.currentMap {
             if previousMap.mapId != newMap.mapId {
                self.currentMap = newMap
                self.addIndoorMapView(url: mapURL)
             }
          } else {
             self.addIndoorMapView(url: mapURL)
          }
       }
    }

    d. Get Location info:

    Following callback returns location updates of the user device in (X, Y) measured in meters from the map origin:

    //Objective c
    -(void)mistManager: (MSTCentralManager *)manager didUpdateRelativeLocation: (MSTPoint *)relativeLocation inMaps: (NSArray *)maps at: (NSDate *)dateUpdated
    //Swift
    func mistManager(_ manager: MSTCentralManager!, didUpdateRelativeLocation relativeLocation: MSTPoint!, inMaps maps: [Any]!, at dateUpdated: Date!)

    MSTPoint object contains the following variable:

    x, y: user location,

    hasMotion: is the user in motion,

    mstPointType: type MSTPointTypeLE,

    MSTPointTypeLast,

    latency: latency in the network,

    heading: compass heading,

    headingFlag: availability of compass heading.

    e. Lat/Long coordinates from Raw and Snapped DR Locations:(for DR)

    The latitude and longitude coordinates and DR estimates (X, Y) can be found inside drInfo NSDictionary from the following method. *Only available in Dead-Reckoning implementation.

    Raw and Snapped DR Locations

    //Objective C
    -(void)mistManager:(MSTCentralManager *)manager didUpdateDRRelativeLocation:(NSDictionary *)drInfo inMaps:(NSArray *)maps at:(NSDate *)dateUpdated {
       double sX = [[[drInfo objectForKey:@"Snapped"] objectForKey:@"X"] doubleValue];
       double sY = [[[drInfo objectForKey:@"Snapped"] objectForKey:@"Y"] doubleValue];
       double sLat = [[[drInfo objectForKey:@"Snapped"] objectForKey:@"Lat"] doubleValue];
       double sLon = [[[drInfo objectForKey:@"Snapped"] objectForKey:@"Lon"] doubleValue];
       double speed = [[[drInfo objectForKey:@"Snapped"] objectForKey:@"Speed"] doubleValue];
       // using the MSTPoint
       MSTPoint *sPoint = [[MSTPoint alloc] initWithX:sX andY:sY];
    }
    
    
    //Swift
    func mistManager(_ manager: MSTCentralManager!, didUpdateDRRelativeLocation drInfo: [AnyHashable : Any]!, inMaps maps: [Any]!, at dateUpdated: Date!) {
       print(drInfo!)
       guard let drInfo = drInfo,
          let snapped = drInfo["Snapped"] as? [String : Any],
          let sX = snapped["X"] as? Double,
          let sY = snapped["Y"] as? Double,
          let sLon = snapped["Lon"] as? NSNumber,
          let sLat = snapped["Lat"] as? NSNumber,
          let speed = snapped["Speed"] as? NSNumber else {
              print("Error: drInfo empty")
              return
       }
    
       DispatchQueue.main.async {
          let sPoint = MSTPoint.init(x: sX, andY: sY) // location update in X,Y
          sPoint?.sLon = sLon
          sPoint?.sLat = sLat
          sPoint?.sSpeed = speed
          if sPoint != nil{
             self.updatePoint(point:sPoint!)
          }
       }
    }

     

     

    drInfo Json Response :

    {
       "Snapped": {
          "Lat": 37.2950, 
          "Lon": -122.0325,
          "MapId": "2e8b48e5-2b94-422f-84c3-1722bf9baad4",
          "Speed": 0.7509392410618689,
          "X": 16.49580083355138,
          "Y": 22.88201353189894
       },
       "Raw": {
          "Lat": 37.2950, 
          "Lon": -122.0325,
          "MapId": "2e8b48e5-2b94-422f-84c3-1722bf9baad4",
          "Speed": 0.7509392410618689,
          "X": 16.47526853250014,
          "Y": 22.88232462736942
       }
    }

    DR heading in degrees

    Following callback provide the blue-dot direction. If the MSTMap Orientation is set to -1, use the snapped heading value directly. Otherwise, set angle offset by adding the orientation to snapped heading.

    //Objective C
    -(void)mistManager:(MSTCentralManager *)manager didUpdateDRHeading:(NSDictionary *)drInfo {
           double snappedHeading = [[[drInfo objectForKey:@"Snapped"] objectForKey:@"Heading"] doubleValue];
           NSLog(@"Degree: %@", snappedHeading);
    }
    
    
    //Swift
    func mistManager(_ manager: MSTCentralManager!, didUpdateDRHeading drInfo: [AnyHashable : Any]!) {
          guard let drInfo = drInfo,
             let snapped = drInfo["Snapped"] as? [String : Any],
             let sHeading = snapped["Heading"] as? Double else {
                 print("Error: drInfo empty")
                 return
          }
          print("Snapped Heading: \(sHeading)")
    }

 

Sample app Reference:

For more detail, you can see the implementation in the Demo app.

Download the sample app zip file for Non-DR SDK integration.

Download the sample app zip file for DR SDK integration.

 

Documentation for MistSDK callbacks:

For more callback related information refer to the Mist SDK callbacks page.

Release Notes:

Check what’s new in the release notes