Previously, we’ve learned how to create a simple app from the ground app in our Quickstart Guides. In this guide, we will dive-in in the most common configuration steps you must follow to accomplish a successful Situm integration.
Setup native projects #
We have several frameworks that you can use, but each one has different configurations that need to be done before initializing our SDK. Take a look at the “Setup native projects” section in our Quickstart Guides to learn what native Android and iOS files you need to configure for each framework.
Importing Situm SDK #
SDK Initialization #
The first step is to import & initialize Situm SDK. This does not start positioning nor retrieves any resource from Situm Platform: it just allocates the required resources for the SDK to run.
The following snippet shows you how to do it in Flutter and React Native (we recommend to do this as soon as possible on your application’s lifecycle). In Cordova the SDK initializes itself after the import, so you don’t need to take further actions.
// main.dart import 'package:situm_flutter/sdk.dart'; ... class _MyComponent extends StatefulWidget { const _MyComponent(); @override State<_MyComponent> createState() => __MyComponentState(); } class __MyComponentState extends State<_MyComponent> { @override void initState() { SitumSdk().init(); ... super.initState(); } @override Widget build(BuildContext context) { return const Placeholder(); } }
//App.js import SitumPlugin from '@situm/react-native'; ... const App = () => { //Initialize Situm SDK SitumPlugin.init(); ... } export default App;
// index.js document.addEventListener("deviceready", onDeviceReady, false); function onDeviceReady() { // In Cordova there is no init() method, // you can directly authenticate with setApiKey(). cordova.plugins.Situm.setApiKey("SITUM_EMAIL", "SITUM_API_KEY"); ... }
Credentials #
After calling the init() method, you can authenticate with your APIKEY (see docs for Flutter, React Native and Cordova) as follows:
//You may use your API_KEY SitumSdk().setApiKey("SITUM_API_KEY");
//You may use your API_KEY SitumPlugin.setApiKey("SITUM_API_KEY")
#APIKEY based authentication cordova.plugins.Situm.setApiKey("SITUM_EMAIL", "SITUM_API_KEY")
Please note! These init() and setApiKey() are the first methods you must call before retrieving your POIs, retrieving your geofences, starting positioning, starting navigation…
Retrieving your device ID #
Sometimes, you might need to know the anonymous ID that Situm associates to your device. This is important, for instance, if you want to retrieve location data from our REST API for a specific device. To do this, you might use the getDeviceID method (Android, iOS, Cordova, React Native, Flutter).
Configuring the positioning #
There are many ways you may want to configure our SDK to locate users inside your building. Maybe your building has some outdoor zones that cannot be configured with bluetooth beacons, then you may want to prioritize the use of the GPS sensor. Maybe your building is calibrated with both wifi signals and bluetooth beacons, then you must use both wifi and bluetooth sensors.
There are many ways you can configure our positioning system. Take a look at the geolocation mode that best fits your use case, and then configure your positioning configuration before continuing.
Requesting permissions #
Situm positioning system uses the device sensors data to compute geolocation, so you must request the appropriate permissions in Android and iOS.
Android #
Situm Android SDK declares a number of install-time permissions that are strictly required for its operation. These permissions are automatically included when you integrate the SDK. However, you must manually declare the ACCESS_FINE_LOCATION permission in your AndroidManifest.xml as it is not included by the SDK. Additionally, you must request this permission at runtime.
If your building is calibrated with BLE beacons, you will also need to request BLUETOOTH_SCAN & BLUETOOTH_CONNECT permissions at runtime. If your building does not use BLE beacons, you can skip requesting these permissions.
Finally, you can optionally request the POST_NOTIFICATIONS permission to display to the user the Situm foreground service notification.
Permission | Description | Action |
---|---|---|
ACCESS_FINE_LOCATION | Required to positioning with every geolocation mode Situm provides. Also called: Location. | Request at runtime & declare in your AndroidManifest.xml |
BLUETOOTH_SCAN & BLUETOOTH_CONNECT | To scan BLE and also to turn BLE ON/OFF in Android 12 and above. Also called: Nearby Devices. | Request at runtime |
POST_NOTIFICATIONS (OPTIONAL) | Allows to push our foreground service notification inside the notification drawer in Android 13 and above. If not granted, user won’t be able to know that we are running on the background. Nevertheless, notices pertaining to these foreground services will still be visible in the Task Manager, irrespective of the user’s decision on the notification permission. See Android docs for more info. | Request at runtime (optional) |
iOS #
As in Android, iOS apps running Situm will need certain permissions. These permissions can be configured from your App Info.plist in Xcode, by creating the following keys:
Permission | Description |
---|---|
NSLocationAlwaysAndWhenInUseUsageDescription. In XCode: “Privacy – Location Always and When In Use Usage Description”. | Required to positioning with every geolocation mode Situm provides. |
NSLocationWhenInUseUsageDescription. In XCode: “Privacy – Location When In Use Usage | Required to positioning with every geolocation mode Situm provides. |
NSMotionUsageDescription. In Xcode: “Privacy – Motion Usage Description”. | Required to access altimeter information from iOS 17.4. Optional from Situm Sdk version 3.14.1, from that version on, if you disable LocationRequest.useBarometer the permission wont be requested at the expense of lower quality in floor changes. |
You will also need to add a description to each key, which will be shown to the user at the time the app request each specific permission. For example, to ask for Location usage you can add the key “NSLocationWhenInUseUsageDescription” with the description “Location is required to find out where you are”
When to request permissions at runtime #
After declaring the necessary permissions (see above) and integrating our SDK into your project, you’ll need to ask the user for runtime permissions. You can request these permissions right before starting positioning or start positioning directly and rely on the onLocationError() callback to respond in case of missing permissions. Moreover, you might want to start positioning at different points in your application’s lifecycle. Typically, there are 2 common points.
- Start positioning as soon as the app opens: In this case, you will need to request the permissions at the very first moment the user enters the app. This way, you will be able to request location updates from the device as soon as posible. In this case, it is especially important to explain to the user which permissions are needed and why.
- Start positioning when displaying the map: Once the user opens our Map Viewer for wayfinding, you may want to locate him inside your building and, beforehand, requesting the permissions.
In all cases, it’s crucial to explain clearly to the user why these permissions are needed before making the actual request to the operating system. Research shows users are much more comfortable with permission requests if they know why the app needs them.
Here you can see an example implemented in our app Situm Wayfinding:
1. Providing context Explain to the user which permissions will be requested and why. | 2. Actual request Make the request to show the Operating System dialog. | 3.a. Permissions granted Now the app will be fully functional. | 3.b. Permissions denied In this case, you should inform the user that the app will lack important features. |
The following figures illustrates the workflow and set of decisions associated with this process:
Option 1: Start positioning directly and rely on the onLocationError() callback to respond in case of missing permissions:
This is a type of reactive implementation where the main action is starting the positioning. The permission request depends on an error notified by SitumSDK. Situm Wayfinding was implemented this way.
Option 2: Request permissions before starting positioning fits better with your implementation:
In all cases, we strongly recommend following the official best practice guidelines:
- Android: https://developer.android.com/training/permissions/requesting.
- iOS: https://developer.apple.com/design/human-interface-guidelines/privacy.
Enable the sensors #
Situm does require the location and bluetooth sensors of your device enabled to work properly.
NOTE: (Android) Our SDK is able to enable the bluetooth sensor of the user’s device in Android < 13, you may want to implement this feature by setting the “Auto enable BLE during positioning” to true in your positioning configuration.
NOTE: (iOS) By disabling the bluetooth in the iOS control center, our SDK will keep working fine. Only make sure you have enabled the bluetooth sensor in the system preferences as we show in the image.
The users may have these sensors disabled, so detect this issue in your app and notify about these requirement to the users. Make sure you are aware of the status of these sensors to provide a well-built user experience.
Handling location data, status and errors #
In case all is configured correctly and the user is within the building, you can start positioning and receiving the location of the user by the onLocationUpdate() method.
However, something might fail after starting positioning. To be able to diagnose the issue, you’ll also need to listen to the errors and statuses thrown by the onLocationError() and onLocationStatus() callbacks. So implement the following method before calling requestLocationUpdates() to correctly listen and notify all the positioning troubles your app might face:
// Implement these callbacks before calling SitumPlugin.requestLocationUpdates() SitumSdk().onLocationUpdate((location) { debugPrint("""onLocationUpdate()>: buildingIdentifier=${location.buildingIdentifier}, floorIdentifier=${location.floorIdentifier}, coordiantes=${location.coordinate.latitude.toStringAsFixed(5)}, ${location.coordinate.longitude.toStringAsFixed(5)} """); }); SitumSdk().onLocationStatus((status) { debugPrint("onLocationStatus()> $status"); }); SitumSdk().onLocationError((err) { debugPrint("ERR> onLocationError()> ${err.message}"); });
// Implement these callbacks before calling SitumPlugin.requestLocationUpdates() SitumPlugin.onLocationUpdate(location => { console.log( `onLocationUpdate()>:\n` + ` \tbuildingIdentifier=${location.position?.buildingIdentifier},\n` + ` \tfloorIdentifier=${location.position?.floorIdentifier},\n` + ` \tcoordinates=${location.position?.coordinate.latitude.toFixed( 5, )},${location.position?.coordinate.longitude.toFixed(5)}\n` ); }); SitumPlugin.onLocationStatus(status => { console.log( `onLocationStatus()> ${JSON.stringify(status.statusName)}`, ); }); SitumPlugin.onLocationError(err => { console.error(`ERR> onLocationError()> ${JSON.stringify(err)}`); });
cordova.plugins.Situm.onLocationUpdate((location) => { console.info( "onLocationUpdate() > \n" + "\tbuildingIdentifier=" + location.buildingIdentifier + ",\n " + "\tfloorIdentifier=" + location.floorIdentifier + ",\n " + "\tcoordinates=" + location.coordinate.latitude.toFixed(5) + ", " + location.coordinate.longitude.toFixed(5) ); }); cordova.plugins.Situm.onLocationStatus((status) => { console.info("onLocationStatus() > " + status); }); cordova.plugins.Situm.onLocationError((err) => { console.error("ERR > onLocationError() > " + err); });
Callback | Description | Documentation |
---|---|---|
onLocationUpdate() | This callback returns back the user location data, only if: 1. Your project is correctly configured. 2. Your positioning configuration fits the requirements of your building. 3. The user’s device is physically inside the building (or simulating its location inside it). | onLocationUpdate: Android, iOS, Flutter, React Native, Cordova Location object: Android, iOS, Flutter, React Native, Cordova |
onLocationStatus() | This callback notifies the current status of the positioning system. The most common ones are STARTING, CALCULATING, STOPPED and USER_NOT_IN_BUILDING. Not all the platforms throw the same statuses. | onLocationStatus: Android, iOS, Flutter, React Native, Cordova LocationStatus object: Android, iOS, Flutter, React Native, Cordova |
onLocationError() | This callback notifies the posible errors that our SDK might face while trying to locate the user. We explain the most common errors in the “Why didn’t work?” section of this guide. | onLocationError: Android, iOS, Flutter, React Native, Cordova LocationError object: Android, iOS, Flutter, React Native, Cordova |
All together #
Finally, now you can start locating the users of your app in your building. You can do it by calling requestLocationUpdates(). In the following code snippet we demonstrate you all the steps of this guide together, so you can copy & paste it in your files:
import 'dart:io'; import 'package:flutter/material.dart'; // Remember that you need to install the permission_handler package // to execute this code snippet import 'package:permission_handler/permission_handler.dart'; import 'package:situm_flutter/sdk.dart'; import 'package:situm_flutter/wayfinding.dart'; // Input here your API key ... const situmApiKey = "YOUR_APIKEY"; // ... and the building you want visualize const buildingIdentifier = "YOUR_BUILDING_IDENTIFIER"; // Make logs more visible var white = '\x1B[0m'; var green = '\x1B[32m'; var red = '\x1B[31m'; void initializeSitum(MapViewController controller, BuildContext context) async { var situmSdk = SitumSdk(); situmSdk.init(); situmSdk.setApiKey(situmApiKey); situmSdk.setConfiguration(ConfigurationOptions(useRemoteConfig: true)); setPositioningCallbacks(situmSdk, context); await requestPermissions().then((_) { situmSdk.requestLocationUpdates(LocationRequest( buildingIdentifier: buildingIdentifier, useDeadReckoning: false)); }).catchError((err) { debugPrint( "$red ERR> requestPermission()> ${err.toString()} $white"); }); } void setPositioningCallbacks(SitumSdk situmSdk, BuildContext context) { situmSdk.onLocationUpdate((location) { debugPrint("""$green onLocationUpdate()>: buildingIdentifier=${location.buildingIdentifier}, floorIdentifier=${location.floorIdentifier}, coordiantes=${location.coordinate.latitude.toStringAsFixed(5)}, ${location.coordinate.longitude.toStringAsFixed(5)} $white"""); }); situmSdk.onLocationStatus((status) { debugPrint("$green onLocationStatus()> $status $white"); }); situmSdk.onLocationError((err) { debugPrint("$red ERR> onLocationError()> ${err.message} $white"); }); } /// Example of a function that request permissions and check the result: Future<bool> requestPermissions() async { var permissions = <Permission>[ Permission.locationWhenInUse, ]; if (Platform.isAndroid) { permissions.addAll([ Permission.bluetoothConnect, Permission.bluetoothScan, ]); } Map<Permission, PermissionStatus> statuses = await permissions.request(); return statuses.values.every((status) => status.isGranted); }
// 1. Import our plugin import SitumPlugin, {requestPermission} from '@situm/react-native'; // Call this method whenever you want to start positioning const initializeSitum = async () => { // 2. Remember to initialize our SDK and authenticate SitumPlugin.init(); SitumPlugin.setApiKey('YOUR_APIKEY'); SitumPlugin.setUseRemoteConfig(true); // 3. Listen to all the possible errors & statuses SitumPlugin.onLocationStatus(status => { console.log( `onLocationStatus()> ${status.statusName}`, ); }); SitumPlugin.onLocationError(err => { console.error(`ERR> onLocationError()> ${JSON.stringify(err)}`); alert(`${err.message}`); }); // 4. Request the permissions to the user, // then request location updates. // // WARNING! this requestPermission() request both location and bluetooth permissions in Android. // In case you don't use beacons in your building, create your custom method without the bluetooth permissions await requestPermission() .then(() => { SitumPlugin.requestLocationUpdates(); }) .catch(err => { console.error(`ERR> requestPermission()> ${JSON.stringify(err)}`); }); }
document.addEventListener("deviceready", onDeviceReady, false); // Set here your credentials const YOUR_SITUM_EMAIL = 'YOUR_EMAIL'; const YOUR_SITUM_API_KEY = 'YOUR_APIKEY'; const YOUR_BUILDING_IDENTIFIER = 'YOUR_BUILDING_IDENTIFIER'; // Make logs more visible var white = "\x1B[0m"; var green = "\x1B[32m"; var red = "\x1B[31m"; function onDeviceReady() { // 1. Authenticate in our SDK. cordova.plugins.Situm.setApiKey(YOUR_SITUM_EMAIL, YOUR_SITUM_API_KEY); // 2. Set onLocationUpdate(), onLocationStatus() and onLocationError() the callbacks. cordova.plugins.Situm.onLocationUpdate((location) => { console.info( `${green}onLocationUpdate() > \n` + "\tbuildingIdentifier=" + location.buildingIdentifier + ",\n " + "\tfloorIdentifier=" + location.floorIdentifier + ",\n " + "\tcoordinates=" + location.coordinate.latitude.toFixed(5) + ", " + location.coordinate.longitude.toFixed(5) ); }); cordova.plugins.Situm.onLocationStatus((status) => { console.info(`${green}onLocationStatus() > ` + status); }); cordova.plugins.Situm.onLocationError((err) => { console.error(`${red}ERR > onLocationError() > ` + err); }); // 3. Ask the user for permission before positioning. _requestPermissions( () => { cordova.plugins.Situm.requestLocationUpdates({ buildingIdentifier: YOUR_BUILDING_IDENTIFIER, }); }, (errorMessage) => { console.error("ERR> ", JSON.stringify(errorMessage)); } ); } // WARNING! Remember to install the cordova.plugins.diagnostic npm package // Permission request logic. function _requestPermissions(successCb, errorCb) { var isAndroid = navigator.userAgent.match(/Android/i) && navigator.userAgent.match(/Android/i).length > 0; var isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent); if (isAndroid) { cordova.plugins.diagnostic.requestRuntimePermissions( function (permissions) { console.log("EXAMPLE> permissions statuses: ", permissions); successCb(); }, function (error) { errorCb(JSON.stringify(error)); }, [ cordova.plugins.diagnostic.permission.ACCESS_FINE_LOCATION, cordova.plugins.diagnostic.permission.BLUETOOTH_CONNECT, cordova.plugins.diagnostic.permission.BLUETOOTH_SCAN, ] ); } else if (isIOS) { cordova.plugins.diagnostic.getLocationAuthorizationStatus( (status) => { if (status == "authorized") { successCb(); } }, () => { // Do nothing } ); cordova.plugins.diagnostic.requestLocationAuthorization( function (status) { switch (status) { case cordova.plugins.diagnostic.permissionStatus.NOT_REQUESTED: errorCb("Permission not requested"); break; case cordova.plugins.diagnostic.permissionStatus.DENIED_ALWAYS: errorCb("Permission denied"); break; case cordova.plugins.diagnostic.permissionStatus.GRANTED: console.log("Permission granted always"); successCb(); break; case cordova.plugins.diagnostic.permissionStatus.GRANTED_WHEN_IN_USE: console.log("Permission granted only when in use"); successCb(); break; } }, function (error) { errorCb(JSON.stringify(error)); }, cordova.plugins.diagnostic.locationAuthorizationMode.ALWAYS ); } }
After implementing these methods and executing this code in your app, you should be able to see logs with the location of the device:
Why it didn’t work? #
Here are the most common positioning troubles your app may face while locating the user inside your building:
Reason | Codes | Solution |
---|---|---|
Location permission is not granted | Android: MISSING_LOCATION_PERMISSION iOS: 11(kSITLocationErrorLocationAccuracy AuthorizationStatusReducedAccuracy) 10(kSITLocationErrorLocationAuthStatusNotDetermined), 8 (kSITLocationErrorLocationDisabled) Flutter: LOCATION_PERMISSION_DENIED React Native: LOCATION_PERMISSION_DENIED | To fix this problem, remember to ask for the location permission before requesting location updates. In case the user actively denied this permission, explain that we won’t be able to locate or guide him through the building without this permission. |
Bluetooth permission is not granted | Android: MISSING_BLUETOOTH_PERMISSION iOS: (iOS devices do no need the BLE permission) Flutter: BLUETOOTH_PERMISSION_DENIED React Native: BLUETOOTH_PERMISSION_DENIED | To fix this problem, remember to ask for the Bluetooth permission before requesting location updates. In case the user actively denied this permission, explain that we won’t be able to locate or guide him through the building without this permission. |
Location sensor was disabled by the user | Android: LOCATION_DISABLED Flutter: LOCATION_DISABLED React Native: LOCATION_DISABLED | The user has disabled de Location sensor of his device. Try to convice the user to enable it, so the positioning system works as expected. |
Bluetooth sensor was disabled by the user | Android: BLUETOOTH_DISABLED iOS: 6 (kSITLocationErrorBluetoothIsOff) Flutter: BLUETOOTH_DISABLED React Native: BLUETOOTH_DISABLED | The user has disabled de Bluetooth sensor of his device. Try to convice the user to enable it, so the positioning system is able to use beacons to locate the user. |
User is out of the building | Android: USER_NOT_IN_BUILDING iOS: kSITLocationUserNotInBuilding Flutter: USER_NOT_IN_BUILDING React Native: USER_NOT_IN_BUILDING | The positioning system is working perfectly fine, but the user location is outside the building. This status is only returned when using building mode. NOTE: Unlike the errors received in onLocationError(), this status is returned by the onLocationStatus(). |