In this Section, we provide an Android and iOS step-by-step guide to build your first Situm app using Flutter. For more advanced use cases, take a look at our Flutter sample app and at the Plugin Method Reference.
Pre-requisites: install Flutter #
First, you need to set up your Flutter development environment. To get started, please follow instructions under the Flutter installation guide.
After installing Flutter you can directly create an example app with the following command:
$ mkdir flutter_getting_started $ flutter create -t app --platform android,ios flutter_getting_started $ cd flutter_getting_started
Installing the plugin #
Alternative 1: package manager #
Run the following command from the root directory of your Flutter project:
$ flutter pub add situm_flutter
This will add the Situm dependency to your project. Specifically, in your pubspec.yaml file.
Alternative 2: git repository + flutter pub add #
Another way to add the Situm dependency to your Flutter project is by directly adding it using the Situm Github repository (https://github.com/situmtech/flutter.git) with the “flutter pub add” command:
$ flutter pub add situm_flutter_wayfinding --git-url=https://github.com/situmtech/flutter.git
Alternative 3: git repository + pubspec.yaml #
If you prefer to handle the dependencies manually, you can add them to your pubspec.yaml file. This file is located in the root directory of your project and it’s used to manage your project’s dependencies.
You will need to add the following lines under the dependencies section:
situm_flutter: git: url: https://github.com/situmtech/flutter.git
Save the pubspec.yaml file and run the command flutter pub get in the root directory of your project to download and install the package:
$ flutter pub get
Once the package is installed, you can start using it in your code.
Handle runtime permissions #
Starting in situm_flutter version 3.26.0 the SDK can automatically request the necessary permissions for positioning.
You can enable this powerful feature by simply calling the SitumSdk.enableUserHelper method:
situmSdk = SitumSdk(); situmSdk.init(); ... // Tell the native SDK to automatically request permissions and manage // sensor (BLE/Location) issues. situmSdk.enableUserHelper();
This method acts as a convenient shortcut, but if you prefer a more tailored setup, you can customize the behavior through configureUserHelper.
By default, this feature is disabled and entirely optional. If you choose not to use it, you can continue managing permissions just as you have until now, for example using permission_handler:
$ flutter pub add permission_handler
You will also need to follow the setup guide for the permission_handler plugin. The plugin communicates directly with the operating system, which requires adding configurations to specific files in both Android and iOS.
Setup native projects (Android & iOS) #
You will also need to make some changes to the native projects of your Flutter application.
Android #
Add the ACCESS_FINE_LOCATION permission declaration to your AndroidManifest.xml.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Finally, set the minSdkVersion to 21 (or later) and compileSdkVersion to 33 (needed by permission_handler) on your app’s build.gradle file.
Finally, add the following to your gradle.properties file:
android.useAndroidX=true android.enableJetifier=true
iOS #
Remove the “use_frameworks!” directive in the Podfile of your iOS project. This is needed because Situm SDK is a static library:
... target 'Runner' do # This line must be commented or removed: # use_frameworks! use_modular_headers! ...
Run the command pod install in the ios directory of your project so CocoaPods can install the necessary Situm SDK dependencies.
$ cd ios $ pod install $ cd ..
Add the required permissions (more info here) in your app’s Info.plist file:
<key>NSLocationWhenInUseUsageDescription</key> <string>Location is required to find out where you are</string> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>Location is required to find out where you are</string> <key>NSMotionUsageDescription</key> <string>We use your phone sensors (giroscope, accelerometer and altimeter) to improve location quality</string>
And in your Podfile (required by the permission_handler library):
Using SitumSdk.enableUserHelper? Then you can skip this step.
... post_install do |installer| installer.pods_project.targets.each do |target| ... #INCLUDE THIS SNIPPET IN YOUR PODFILE TO CONFIGURE PERMISSION HANDLER PLUGIN target.build_configurations.each do |config| config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', 'PERMISSION_LOCATION=1', 'PERMISSION_SENSORS=1', ] #END OF SNIPPET TO INCLUDE ... end end end
Finally, if you want the our MapViewer (built-in Wayfinding UI) to work offline, you will need to add the underlying web application’s domain inside the entry WKAppBoundDomains, also on Info.plist as follows:
<key>WKAppBoundDomains</key> <array> <string>map-viewer.situm.com</string> </array>
Warning! If you have other Webviews in your app this might affect them. Learn more about this here.
Run your first app! #
The following code contains a fully functional Flutter app. You may copy & paste it in your main.dart file (you may obtain your credentials as explained here, and your building ID as explained here):
import "dart:io"; import 'package:flutter/material.dart'; //Step 1 - Importing Situm import 'package:situm_flutter/sdk.dart'; import 'package:situm_flutter/wayfinding.dart'; //Step 2 - Setting credentials and building identifier //Input here your user credentials ... const situmApiKey = "YOUR-SITUM-API-KEY"; // ... and the building you want visualize const buildingIdentifier = "YOUR-SITUM-BUILDING-IDENTIFIER"; const profile = "YOUR-SITUM-PROFILE"; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Situm Flutter', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: const MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({super.key}); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { MapViewController? mapViewController; @override void initState() { super.initState(); // Initialize SitumSdk class. _useSitum(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: const Text('Situm Flutter'), ), // Step 3 - Showing the building cartography using the MapView body: Center( // MapView widget will visualize the building cartography child: MapView( key: const Key("situm_map"), configuration: MapViewConfiguration( situmApiKey: situmApiKey, profile: profile, buildingIdentifier: buildingIdentifier, ), onLoad: _onLoad, ), ), ); } void _onLoad(MapViewController controller) { // Map successfully loaded: now you can register callbacks and perform // actions over the map. mapViewController = controller; debugPrint("Situm> wayfinding> Map successfully loaded."); controller.onPoiSelected((poiSelectedResult) { debugPrint("Situm> wayfinding> Poi selected: ${poiSelectedResult.poi.name}"); }); } //Step 4 - Positioning void _useSitum() async { var situmSdk = SitumSdk(); // Initialize Situm and set up your credentials. situmSdk.init(); situmSdk.setApiKey(situmApiKey); // Tell the native SDK to automatically request permissions and manage // sensor (BLE/Location) issues. situmSdk.enableUserHelper(); // Set up location callbacks: situmSdk.onLocationUpdate((location) { debugPrint("Situm> sdk> Location updated: ${location.toMap().toString()}"); }); situmSdk.onLocationStatus((status) { debugPrint("Situm> sdk> Status: $status"); }); situmSdk.onLocationError((error) { debugPrint("Situm> sdk> Error: ${error.message}"); }); // Start positioning by requesting location updates: situmSdk.requestLocationUpdates(LocationRequest()); } }
You may run this app by using:
$ flutter run
You should see something like this:

Code explanation: step-by-step #
Step 1 – Importing Situm #
The 1st thing the example does is to import the situm_flutter package, which contains two libraries:
- Wayfinding: visual module for maps, routes, and navigation.
- Sdk: allows you to control the positioning system through the SitumSdk class.
Step 2 – Setting credentials and building identifier #
Right after the import, we set:
- User credentials (email and APIKEY).
- Building identifier. Identifier of the building whose cartography will be shown. It should be the same as the one where you’ll perform positioning.
You may obtain your credentials as explained here, and your building ID as explained here.
Step 3 – Showing the building cartography using the MapView #
Then, the example shows the cartography of the selected building. You may see that the wayfinding library exposes three main classes to this extent:
- MapView. The Flutter widget that you can add to your view hierarchy.
- MapViewConfiguration. Used to set the configuration before you load the MapView. If you have a profile you need to set it here. You can check more about the profile here.
- MapViewController. Allows you to communicate with the map: methods and callbacks are available to perform actions and listen to events (e.g. listen to POI selections, intercept navigation options, etc.)
Note that you need need to wait until the MapViewController is properly loaded, using the onLoad callback as the example does.
Step 4 – Positioning #
You may perform positioning by using the function _useSitum() detailed in the example above.
Initializing SitumSdk #
First, you may initialize SitumSdk on your root stateful widget.
Setting up callbacks #
Then, by setting up callbacks (onLocationUpdate, onLocationStatus, onLocationError), you can listen for location updates, status and errors (after positioning is started).
Requesting permissions #
After that, your app must ask for the following permissions (check our documentation for more details):
- Android: Location and Bluetooth runtime permissions.
- iOS: Location permissions.
The legacy example app calls the following _requestPermissions() function, that in turn uses the package permission_handler to do so.
// Requests positioning permissions using permission_handler: 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); }
Starting positioning #
Finally, start positioning with the Situm SDK, you will need to call the requestLocationUpdates() method. This method takes one argument of the type LocationRequest that will encapsulate the configuration parameters.
In this example, the LocationRequest is empty, meaning that positioning parameters will be drawn from the Remote Configuration, which you may configure in Situm Dashboard.
Visualize the user’s position on the map #
Once the positioning has started, the MapView will automatically start drawing the user’s position on the map. Otherwise, please check that you’ve configured the Remote Configuration properly in Situm Dashboard.
Advanced configuration #
To further configure the user experience see our Advanced Topics section that explains additional capabilities of both Situm SDK and MapView as well as how to configure them on your projects. Topics you can be interested in are: battery efficiency, location cache, working offline with cached data, foreground & background execution, external provider locations, listen to geofences entries & exits, how to provide your iOS app’s privacy manifest.
Legacy configuration #
Prior to version 3.16.0 of situm_flutter, it was also necessary to add the Situm repository to your project’s build.gradle file so Gradle can download the native Situm SDK dependency:
allprojects { repositories { maven { url "https://repo.situm.com/artifactory/libs-release-local" } } }