Getting started on iOS

Installation

Looking for an older version?

You can get an older version of the SDK in the Downloads section.

Project setup

INSITEO 's modules are provided as an iOS library and an iOS bundle. To use them, you will need to link it with your application project. To do that, simply add the InsiteoAPI folder to you project.

iOS project integration

Note: If you plan to use our 3D features, don't forget to add the glsl folder in your application resources.

Frameworks dependencies

Then you will need to add all the wanted frameworks in the Link Binary With Libraries panel. Please also check the framework dependencies below and add any additional required framework. The InsiteoAPI library requires the following frameworks and libraries:

  • Apple CoreBluetooth.framework for location purposes
  • Apple CoreGraphics.framework for rendering purposes
  • Apple CoreLocation.framework for location purposes
  • Apple CoreMotion.framework for location purposes
  • Apple CoreTelephony.framework for analytics purposes
  • Apple CoreText.framework for rendering purposes
  • Apple Foundation.framework
  • Apple OpenAL.framework for rendering purposes
  • Apple OpenGLES.framework for rendering purposes
  • Apple QuartzCore.framework for rendering purposes
  • Apple Security.framework
  • Apple UIKit.framework
  • Apple libc++.dylib
  • Apple libz.dylib
  • Apple libsqlite3.dylib
iOS project dependencies

Requirements

  • The INSITEO library requires iOS 5.1.1 or later.
  • The library is now optimized for armv7 and arm64.
  • Please set C++ Standard Library as libstdc++ in your project settings

Objective-C++

When using some classes such as ISLocationProvider, ISItineraryProvider or ISMap3DView, you will need to tag your implementor as Objective-C++ class (*.mm extension OR specific compiler settings).

Note: The Insiteo library do not use ARC.

Initialization

Start and update the API

Don't forget to set your API key

Before any interaction with Insiteo's API you must set your API KEY via setAPIKey. This key can be found in your INSITEO account on the back office.

The first step to access Insiteo's services, is to initialize our API via the ISInitProvider singleton. This will be done with the startAPIWithServerType and we will give you the data to pass (ie the ISEServerType, the site identifier and the language).

Use the appropriate server type

The initialization process requires a ISEServerType that can take the following values: ISEServerTypeDev, ISEServerTypeTest or ISEServerTypeProd. Depending on its values the downloaded data will be stored under the appropriate folder (respectively 'dev', 'test' and 'release').

Choose your render mode

In order to get ready to use our map module, you will need to specify the render mode you plan to use. You can choose between ISERenderMode2D and ISERenderMode3D. Please note that the default mode is ISERenderMode2D.

You can now safely start Insiteo API by calling startWithServerType. You will be then notified of API initialization through block handlers you specified.

Here is a snippet that will show you how to properly do the initialization process:

//Initialization parameters
int SITE_ID = 365;
NSString * LANGUAGE = @"fr";
    
//Set your API key
[ISInitProvider setAPIKey:@"MY-API-KEY"];

//And start the API
id<ISPCancelable> initTask = [[ISInitProvider instance] startWithServerType:ISEServerTypeProd andSiteId:YOUR_SITE_IDandLanguage:YOUR_LANGUAGE
andStartHandler:^NSArray * (ISInsiteoError * error, NSArray * newPackages) {
    //Check init status
    if (error == nil) {
        //Success!

        //Return all packages to update all data
        return newPackages;
    } else {
        //An error occured
        
        //[1] It means that INSITEO servers could not be reached. If you want to use an INSITEO module, you have to check if your application has enough data to run. This can be done using hasPackageWithPackageType:andServerType on ISInitProvider singleton.
        return nil;
    }
}
andUpdateHandler:^(ISInsiteoError * error) {
    //Check update status
    if (error == nil) {
        //Success! You can now launch your application with all up to date data.
    } else {
        //An error occured, same as [1]
    }
}
andUpdateProgressHandler:^(ISPackageType packageType, Boolean download, int progress, int total) {
    //Here you get the current treated package type and you can know if we are currently downloading or installing it

    //And you can compute total progress to update your loading view for example
    float totalProgress = (float)progress / (float)total;
}
andRenderMode:YOUR_RENDER_MODE];

//Note: The initTask object could be used to cancel the API initialization (see ISPCancelable protocol documentation).

                    
Handle the initialization process in background

The startWithServerType method is asynchronous. Be sure to provide a valid block handler to be notified of init ending.

You can also choose to not update the API automatically, for example if you want to ask the user if he wants to download the new data.

In this case, simply returns nil on the initialization handler and don't pass update block handlers. Just call the update method when you are ready. For more information, please check our sample application.

Map

Map3DView now available!

In the 3.3.0 version, you can now use the ISMap3DView class. Be aware, that you can't use both 2D and 3D in the same running application.

Don't forget to add the glsl folder in your application resources, otherwise the 3D engine won't work.

Packages dependencies

Be aware that you need to have installed at least the following packages:

  • A MAP_DATA_PACKAGE package, which contains maps information such as zoom levels and scales.
  • 2D A TILES_PACKAGE package, which contains .3cm files that will be displayed.
  • 3D A MAP_3D_PACKAGE package, which contains all 3D files.
You can easily check if the package is available on the device with the following method: [[ISInitProvider instance] hasPackageWithPackageType:MAP_DATA_PACKAGE andServerType:SERVER].

Display a MapView

A ISMapView is provided and can be used to display a 2D/3D map component with specific interactive areas. The API also provides advanced features such as additional rendering layouts management (promotional, special areas etc …) or specific events handling. To use this component you have to make sure that you have downloaded all the required packages.

The ISMapView will display a 2D tiled map or 3D plane of the site (depending on your ISERenderMode), and provide common map interaction (such as move, center, and pinch to zoom), animation and more. It also handle the ISZone rendering and touch behavior.

The ISMap2DView uses the Cocos2D Objective-C 2D engine and you can refer to its documentation here.

The ISMap3DView uses the Cocos3D Objective-C 3D engine (based on Cocos2D) and you can refer to its documentation here.

In order to use our MapAPI, you will need to get an ISMapView:

//ISMap2DView initialization
[ISMap2DView getMap2DViewWithFrame:self.mapContentView.frame andMapListener:self andHandler:^(ISMap2DView * map2DView) {
    //At this point, the map view is correctly initialized
    [self.view addSubView:map2DView];
}];

//ISMap3DView initialization
[ISMap3DView getMap3DViewWithFrame:self.mapContentView.frame andMapListener:self andHandler:^(ISMap3DView * map3DView) {
    //At this point, the map view is correctly initialized
    [self.view addSubView:map3DView];
}];


        

Prerequisites

Adding graphical objects on map

The ISMapView also allows you to display custom interactive objects. This can be done by implementing the renderer interface id<ISPRenderer> and the Render Touch Object interface id<ISPRTO> or by simply extending the ISGenericRenderer and ISGenericRTO that already provide common behavior (icon and label rendering, touch handling and so on, you can check their behavior in our SampleApp).

The ISMapView will also detect touches, and dispatch them to all id<ISPRTO>. A listener can be set on the map view, to be notified of clicks on specific id<ISPRTO> class (see ISMapView class documentation).

Adding, removing ISGenericRTO to the ISMapView and listening for their events:
			
//This method will add the rto at a given position
ISGenericRTO * rto = [[ISGenericRTO alloc] initWithName:@"My RTO name" andLabel:@"My RTO" andMetersPosition:givenPosition andWindowDisplayed:YES andLabelDisplayed:YES];
[m_mapView addRTO:rto];
[rto release];

//And to remove it
[m_mapView removeRTO:rto];

//This method will add the rto to the given zone
ISGenericRTO * rto = [[ISGenericRTO alloc] initWithName:zonePoi.externalPoiId andLabel:@"My RTO" andMetersPosition:nil andWindowDisplayed:YES andLabelDisplayed:YES];
[m_mapView addRTO:rto inZone:zonePoi.zoneId];
[rto release];

//And to remove it
[m_mapView removeRTO:rto fromZone:zoneId];

//Add a listener for this type of IRTO
[m_mapView setRTOListener:rtoListener withRTOClass:[GfxRTO class]];
			
        

Create your own ISPRenderer

A renderer is a class that defines drawing and touch behavior for a certain type of id<ISPRTO>. Once added to the ISMapView a renderer will have its render2D or render3D method call by the map rendering loop to enable to do its rendering operation and it will also be notify when to handle touch events (onTouchDown, onTouchMove, onTouchUp). If you want to use your own customized renderer, you will need to create a class that implements the id<ISPRenderer> interface. Then you will be able to specify your own renderering and touch behavior.

id<ISPRenderer> uses a priority value that will define it's 2D rendering and touch order. Highest priority renderered last (so on the top) and notify by touch first.

To register a new renderer as a map's renderer, simply do like this:
			
//How to add a custom renderer
[mapView addRenderer:aRenderer]];
			
        

Create your own ISPRTO

If you intend to create your own ISPRTO that use CC3Billboard and support iPhone 6 plus resolution, you will need to scale the object by 0.75.
To draw a customized rendering object on the map, you will need to create a class that implements the id<ISPRTO> interface. Then you will be able to specify your object's behavior through methods like:
			
//The 2D method you will need to override in order to manually manage your object rendering
- (void)render2DWithLayer:(CCLayer *)layer andRatio:(double)ratio andOffset:(CGPoint)offset andAngle:(float)angle andPriority:(int)priority;

//The 3D method you will need to override in order to manually manage your object rendering
- (void)render3DWithScene:(CC3Scene *)scene andLayer:(CC3Node *)layer andCurrentMap:(ISMap *)map andRatio:(float)ratio andAngle:(float)angle andPriority:(int)priority;

//Because once added to the world a 3D object will always be drawn it is up to you to remove the object from the world when required
- (void)remove3DFromLayer:(CC3Node *)layer;

//Method that gets called when the IRTO have to handle a touch down event
- (ISETouchObjectResult)onTouchDown:(ISTouch *)touch;
			
        

Where to find my ISPRTO?

All id<ISPRTO> of class corresponding to the custom renderer class, when added via ISMapView, will be put in custom renderer. If you add an id<ISPRTO> and there are no id<ISPRenderer> defined for that specific class, the ISMapView will automatically create a ISGenericRenderer to handle it. So creating your own id<ISPRTO> does not mean that you necessarily have to create you own id<ISPRenderer>.

Zone offsets in 3D

In 3D, you can specify an offset through the z axis still by using the following method addRTO:inZone:withOffset:.

Link with external content

With the Insiteo framework, you can link your content to our zone based system. To do that you will have to register this content through our back office. For example you can link a shop to one of our zone and then, get back this content in your application, simply by requesting our framework.

Insiteo Interactive maps - 2 minutes tutorial
To get all related Insiteo zones for a given external POI, you can use the ISDBHelperMap class like so:

//Get all Zone/POI assocations for a given external identifier
NSArray * zonesPois = [ISDBHelperMap getExternalZonePoisForExtIdPoi:externalPoiId];

        

Note: An array is returned, because you can link a POI to several zones and a zone can contains several POIs.

To get all POIs related to a given Insiteo zone, you can use the ISDBHelperMap class like so:

//Get all external Zone/POI assocations for a given zone identifier
NSArray * zonesPois = [ISDBHelperMap getZonePoisForIdZone:zoneId andExternal:YES];

        

Each method returns an ISZonePoi object which contains a position in meters and an offset (if specified) in order to place your on id<ISPRTO> on our map.

Zone/Poi associations offsets

If you want an offset to be used when drawing an id<ISPRTO> in a ISZone you have to explicitly set it we adding the id<ISPRTO> to the ISMapView.

Best pratices

We recommend you to start and stop the map rendering according to the parent UIViewController state changes.


//Insiteo
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [mapView startRendering];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [mapView stopRendering];
}

        

Location

Packages dependencies

If you intend to use the this service you have to make sure that the location package have been properly downloaded. You can easily check if the package is available on the device with the following method: [[ISInitProvider instance] hasPackageWithPackageType:LOCATION_PACKAGE andServerType:SERVER].

iOS 8 compatibility

In order to be iOS 8 fully compatible, you will need to add the NSLocationWhenInUseUsageDescription key in your .plist. You can leave the corresponding value empty or specify a custom message that will be displayed the first time the SDK will ask to use the location service.

Location process

Documentation Documentation Documentation

Get your first location

You can use our LocationAPI to obtain location information. The LocationAPI needs initialization information in order to communicate with our servers. You can easily link this library to the INSITEO map, so the location can be displayed on it.

In order to use our LocationAPI, you will need to create an ISLocationProvider instance. To receive location, you will need to start the ISLocationProvider, with location flags (indicating location behavior) and a id<ISPLocationListener>:

//Start location
[[ISLocationProvider sharedInstance] startLocation:(COMPASS|BLE|MEMS) andLocationListener:aListener];

//Add location renderer to the ISMapView, thus location is displayed on map
[mapView addRenderer:[locProvider renderer]];

                    

Which flags to use

Please contact us to get the appropriate location settings.

Prerequisites

  • The API needs to be initialized.
  • You can now be notified when no registered beacons were detected, which probably means that the user started the location whereas he is not on site.

Available services

Available location-based services are:

  • LBS_MODULE_ITINERARY: this module computes the route between an arrival point, and a departure point (could be the user current location).
  • LBS_MODULE_GEOFENCING: this module detects when user location is in "active" areas, and notify the application that the user entered/stayed in/left these areas.
Get a specific LBS module

To use them, you have to request them from ISLocationProvider with the getLbsModule method. Be aware that a new module is created for each call of getLbsModule.

Itinerary

Packages dependencies

If you intend to use the this service you have to make sure that the itinerary package have been properly downloaded. You can easily check if the package is available on the device with the following method: [[ISInitProvider instance] hasPackageWithPackageType:ITINERARY_PACKAGE andServerType:SERVER].

Enable itinerary rendering

To use location-based services, such as Itinerary or GeoFencing you have to get the module from the location provider. If you want it to be displayed on an INSITEO map, do as below:

//Get the itinerary provider
ISGfxItineraryProvider * itineraryProvider = (ISGfxItineraryProvider *)[locProvider getLbsModule:LBS_MODULE_ITINERARY];

//Get itinerary renderer linked to provider
ISItineraryRenderer * itineraryRenderer = [itineraryProvider renderer];

//Register for itinerary rendering user interaction (such as clicks).
[itineraryRenderer setRenderListener:listener];

//Add renderer so itinerary is displayed on map
[mapView addRenderer:itineraryRenderer];

                    

Request an itinerary between two points

To compute an itinerary between two points, simply do like this:

//Request an itinerary between two points (A on map "1", the other on map "2")
ISItineraryRequest * request = [itineraryProvider requestItineraryWithStartPoint:CGPointMake(50, 50) andStartMapId:1 andEndPoint:CGPointMake(200, 100) andEndMapId:2 andListener:itineraryListener andPMR:NO];

                    

Note: An ISItineraryRequest is returned in order to identify sender through callbacks.

Request an itinerary from user location

To compute an itinerary from the user location, please do like this:

//Request an itinerary from the user location to a point A
ISItineraryRequest * request = [itineraryProvider requestItineraryFromCurrentLocationWithEndPoint:CGPointMake(200, 100) andEndMapId:2 andListener:itineraryListener andPMR:NO];

                    

Request an optimized route

If you want to compute an optimized route between several points, you can proceed as follow:

//Request an optimized route between several waypoints (an ISItineraryOptimizedRequest is returned)
ISItineraryOptimizedRequest * optimizedRequest = [itineraryProvider requestOptimizedItineraryWithWaypoints:waypoints andOptimMode:ISEOptimizationModeNearestNeighbourShortestPath andKeepFirstPosition:YES andKeepLastPosition:NO andListener:itineraryListener andPMR:NO];

                    
Note: 3D rendering is not properly handle for optimized request.

Note: You can specify if you want to keep the first position, last position, or both.

Note: There are multiple optimization modes available but we highly recommend to keep ISEOptimizationModeNearestNeighbourShortestPath as the default one.

Recomputation

When using the itinerary service along with the location you can refresh the route according to the user's position in the following way:

//Method called when the user position changed
- (void)onItineraryChangedWithRequest:(ISItineraryBaseRequest *)request andDistanceToItinerary:(float)distanceToItinerary {
    //You can check if the distance between the user location and the computed itineray needs a recomputation
    if (distanceToItinerary > MAX_RECOMPUTATION_DISTANCE) {
        //Recompute the itinerary
        [request recompute];
    }
}

                    

Note: We usually use 10.0 meters as MAX_RECOMPUTATION_DISTANCE.

Geofencing

Packages dependencies

If you intend to use the this service you have to make sure that the geofencing package have been properly downloaded. You can easily check if the package is available on the device with the following method: [[ISInitProvider instance] hasPackageWithPackageType:GEOFENCING_PACKAGE andServerType:SERVER].

Start the Geofencing module

To start the Geofencing module, simply do like so:

//Get the geofencing module from the location provider
ISGeofenceProvider * geofenceProvider = [m_locationProvider getLbsModule:LBS_MODULE_GEOFENCING];
    
//"Start" geofencing
[geofenceProvider setListener:listener];

                    

Understand geonotifications

After starting the module, your listener will be notified with 3 arrays of ISGeoFenceArea.
  • The first one contains all zones the user just entered
  • The second one contains all zones where the user still is and has spent a certain time .
  • The third one contains all zones the user just left.

//Method alled when geofencing module has new data available
- (void)onGeofenceDataUpdateWithEnteredAreas:(NSArray *)enteredAreas andStayedAreas:(NSArray *)stayedAreas andLeftAreas:(NSArray *)leftAreas {
    //Entered areas
	for (ISGeofenceArea * geoArea in enteredAreas) {
        NSLog(@"User entered area %@", geoArea.GUID);
    }

    //Stayed areas
    for (ISGeofenceArea * geoArea in stayedAreas) {
        NSLog(@"User still is in area %@", geoArea.GUID);
    }

    //Left areas
    for (ISGeofenceArea * geoArea in leftAreas) {
        NSLog(@"User has left area %@", geoArea.GUID);
    }
}

                    

Dynamic geofencing

In the last version of our API, geopush content can be added to the ISGeofenceProvider directly from your application in addition to the one fetched from the server. This enables, for example, your content to be more accurate to a specific user's behaviour or using context.

  • The created ISGeofenceArea's polygon will be based on the specific ISZone parameters that have to be provided in the back office.
  • If the ISGeofenceArea parameters (ie width, enteredTime, enteredEnabled ... ) are not set they will be fetched from the configuration file. This configuration file defines those parameters by ISMap and not by ISZone.
  • If the creation succeeded the ISGeofenceArea will be automatically added to the ISGeofenceProvider.

Adding content to a specific zone or for a specific zone/poi association

To add a geopush content to a specific ISZone or ISZonePoi, you can use the methods shown below. A polygon based on the ISZone parameters and the provided ISGeofenceArea width will be created and this ISGeofenceArea will be automatically added to the ISGeofenceProvider.

//For a ISZone

- (ISGeofenceArea *)addGeofenceAreaWithZoneId:(int)zoneId andLabel:(NSString *)label andMessage:(NSString *)message;

- (ISGeofenceArea *)addGeofenceAreaWithZoneId:(int)zoneId andPolygon:(NSMutableArray *)polygon andLabel:(NSString *)label andMessage:(NSString *)message;

...

//For a ISZonePoi association

- (ISGeofenceArea *)addGeofenceAreaWithZonePoi:(ISZonePoi *)zonePoi andLabel:(NSString *)label andMessage:(NSString *)message;

- (ISGeofenceArea *)addGeofenceAreaWithZonePoi:(ISZonePoi *)zonePoi andPolygon:(NSMutableArray *)polygon andLabel:(NSString *)label andMessage:(NSString *)message;

...

                    

Adding content for a given position

To add a geopush content at a specific ISPosition, you can use the methods shown below. A square of size the on the given in parameter (or by default 4 time the size defined in the configuration file) and center on the given position will be created.

- (ISGeofenceArea *)addGeofenceAreaWithGUID:(NSString *)guid andCenter:(ISPosition *)center andLabel:(NSString *)label andMessage:(NSString *)message;

- (ISGeofenceArea *)addGeofenceAreaWithGUID:(NSString *)guid andCenter:(ISPosition *)center andLabel:(NSString *)label andMessage:(NSString *)message andEventTime:(float)eventTime;

...

                    

Removing a dynamic geofence area

To remove a ISGeofenceArea from the ISGeofenceProvider call the appropriate remove method based on how it was added.

- (void)removeGeofenceAreaWithGuid:(NSString *)guid;

- (void)removeGeofenceAreaWithZoneId:(int)zoneId;

- (void)removeGeofenceAreaWithZonePoi:(ISZonePoi *)zonePoi;

- (void)removeGeofenceAreaWithArea:(ISGeofenceArea *)area;

                    

Geofencing rendering

You can now view your ISGeofenceArea on your ISMapView. Like all other LBS services, you will have to retrieve its id<ISPRenderer> and pass it to the ISMapView. All the geofencing zone will be displayed ie the one define on the back office that one created dynamically.

Note: 3D rendering is not available for this module.

Analytics

Packages dependencies

If you intend to use the this service you have to make sure that the analytics package have been properly downloaded. You can easily check if the package is available on the device with the following method: [[ISInitProvider instance] hasPackageWithPackageType:ANALYTICS_PACKAGE andServerType:SERVER].

Production vs Development

In order to be able to differentiate data from an application in a testing environment from a release one Insiteo's SDK uses the [ISCommonConstants getDebugMode].
You should make sure to set this tag to false for your release version.

Starting the Analytics service

In order to use the analytics service you have to make sure it gets started during the API initialization. If you did not specify the analytics behavior in the API initialization method the service will be started automatically if the packages depedencies prerequisite is met. Otherwise this will depends on the value passed as the analyticsAutoStart as true will try to start it and false will keep it turned off and no data will be stored during the session.

Location events

If you have decided to use the analytics service then the user's location will be automatically sent for datamining analysis. In order to avoid internet requests overload location will be aggregated according to a given frequency that can be set in the back office.

Generic events

For any other type of events you would like to keep track of you can use the ISAnalyticsGenericEvent. This event enables you to add up to 2 NSString, 2 int, 2 double, 2 ISPosition and a label to match most cases.


ISAnalyticsGenericEvent * zoneEvent = [[ISAnalyticsGenericEvent alloc] initWithEventType:@"generic_event"];

[zoneEvent setSParam1:@"product a"];
[zoneEvent setPositions:[NSArray arrayWithObject:aLocation.position]];

[[ISAnalyticsManager instance] addGenericEvent:zoneEvent];

                    

Insiteo's API already trace some basic events among them:

  • Location start and stop
  • Geofence entered, stayed and left
  • Map changes, zone clicks and id<ISPRTO> added with ISZonePoi
  • Itinerary requests

Tracking products displayed on map

If you want to trace when a product is added to the map you can use addRTO:inZonePoi:. This will generate a ISAnalyticsGenericEvent with the String1 set with the external id of the Poi defined in the ISZonePoi.

Completing a generic event

In can be useful in some cases to add information to a ISAnalyticsGenericEvent for that you must set a ISPAnalyticsListener that will be notified everytime a new generic event is added. Returning false in this method will dismiss the event.