05 – A basic Flutter app

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.

Info! Take a look at the migration guide if you are updating your app from the previous Situm Flutter Wayfinding plugin to use this new one.

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_wayfinding:
    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.

Installing other dependencies #

To use Situm in your project, you’ll also need to install the following dependency to handle permissions (see this section for more information):

$ flutter pub add permission_handler

Remember 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.

Info! SitumSDK declares other permissions as well, but you don’t need to declare them in your app.

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

...
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, 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>

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';
import 'package:permission_handler/permission_handler.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";



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,
            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();
    // Set up your credentials
    situmSdk.init();
    situmSdk.setApiKey(situmApiKey);
    // 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}");
    });
    // Check permissions:
    var hasPermissions = await _requestPermissions();
    if (hasPermissions) {
      // Happy path: start positioning using the default options.
      // The MapView will automatically draw the user location.
      situmSdk.requestLocationUpdates(LocationRequest());
    } else {
      // Handle permissions denial.
      debugPrint("Situm> sdk> Permissions denied!");
    }
  }

  // Requests positioning permissions
  Future<bool> _requestPermissions() async {
    var permissions = <Permission>[
      Permission.locationWhenInUse,
    ];
    if (Platform.isAndroid) {
      permissions.addAll([
        Permission.bluetoothConnect,
        Permission.bluetoothScan,
      ]);
    } else if (Platform.isIOS) {
      permissions.add(Permission.bluetooth);
    }
    Map<Permission, PermissionStatus> statuses = await permissions.request();
    return statuses.values.every((status) => status.isGranted);
  }
}

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 two main classes to this extent:

  • MapView. The Flutter widget that you can add to your view hierarchy.
  • 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: Bluetooth permissions.

The example calls the function _requestPermissions(), that in turn uses the package permission_handler to do so.

Please note! You should ask for permissions at the appropriate time in your app’s lifecycle: for example, when the user first starts using the location-based features of your app.

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.

Please note! To stop positioning, call the method situmSdk.removeUpdates(). We recommend to stop positioning if location-based features are not being used in your app, to preserve battery and resources.

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

Subscribe to our newsletter

BASIC INFORMATION ON DATA PROTECTION

Data controller: SITUM TECHNOLOGIES, S.L.
Contact: Data controller: situm@situm.es
Responsible for protection: dpo@situm.es
Purpose and legal basis: To manage the sending of SITUM newsletters only with consent.
Legitimation: Express consent of the interested party.
Recipients: The data will not be passed on to third parties with the exception of legal obligations.
Retention period: As long as the interested party remains subscribed to the newsletter (a link to unsubscribe will be available in each newsletter sent by Situm).
Rights: The interested party may at any time revoke their consent, as well as exercise their rights of opposition, access, conservation, rectification, limitation, deletion of data and not be subject to a decision based only on automated data processing, by writing to SITUM at the addresses indicated.
Additional Information: You can consult additional and detailed information on Data Protection in our privacy policy.

Please, download your copy here

Thank you for downloading our whitepaper. Please do not hesitate to contact us if you would like to know more about how our solutions can help your business. Download whitepaper


Close window