Skip to content

Search Along Route

In this guide, you will learn how to calculate a route, simulate navigation, and search for landmarks along the route.

Search Along Route - example Flutter screenshot

Setup

First, get an API key token, see the Getting Started guide.

Prerequisites

Make sure you completed the Environment Setup - Flutter Examples guide before starting this guide.

Build and run

Go to the search_along_route directory, within the Flutter examples directory - that is the name of this example project.

Search Along Route - example Flutter screenshot

Note - the gem_kit directory containing the Maps SDK for Flutter should be in the plugins directory of the example, e.g. example_pathname/plugins/gem_kit - see the environment setup guide above.

Run: flutter pub get

Configure the native parts:

First, verify that the ANDROID_SDK_ROOT environment variable is set to the root path of your android SDK.

In android/build.gradle add the maven block as shown, within the allprojects block, for both debug and release builds:

1    allprojects {
2        repositories {
3            google()
4            mavenCentral()
5            maven {
6               url "${rootDir}/../plugins/gem_kit/android/build"
7            }
8        }
9    }

in android/app/build.gradle within the android block, in the defaultConfig block, the android SDK version minSdk must be set as shown below.

Additionally, for release builds, in android/app/build.gradle, within the android block, add the buildTypes block as shown:

Replace example_pathname with the actual project pathname

 1android {
 2    defaultConfig {
 3        applicationId "com.magiclane.gem_kit.examples.example_pathname"
 4        minSdk 21
 5        targetSdk flutter.targetSdk
 6        versionCode flutterVersionCode.toInteger()
 7        versionName flutterVersionName
 8    }
 9    buildTypes {
10        release {
11            minifyEnabled false
12            shrinkResources false
13
14            // TODO: Add your own signing config for the release build.
15            // Signing with the debug keys for now, so `flutter run --release` works.
16            signingConfig signingConfigs.debug
17        }
18    }
19}

In the ios/Podfile configuration file, at the top, set the minimum ios platform version to 14 like this:

platform :ios, '14.0'

We recommend you to run these commands after you copy the gem_kit into your project: flutter clean flutter pub get and cd ios pod install

Then run the project:

flutter run --debug
or
flutter run --release

How it works

Search Along Route - example Flutter screenshot

 1import 'package:gem_kit/core.dart';
 2import 'package:gem_kit/map.dart';
 3import 'package:gem_kit/navigation.dart';
 4import 'package:gem_kit/routing.dart';
 5import 'package:gem_kit/search.dart';
 6
 7import 'package:flutter/material.dart' hide Route;
 8
 9Future<void> main() async {
10  const projectApiToken = String.fromEnvironment('GEM_TOKEN');
11
12  await GemKit.initialize(appAuthorization: projectApiToken);
13
14  runApp(const MyApp());
15}

The dart material package is imported, as well as the required gem_kit packages.

 1class MyApp extends StatelessWidget {
 2  const MyApp({super.key});
 3
 4  @override
 5  Widget build(BuildContext context) {
 6    return const MaterialApp(
 7      debugShowCheckedModeBanner: false,
 8      title: 'Search Along Route',
 9      home: MyHomePage(),
10    );
11  }
12}
 1class MyHomePage extends StatefulWidget {
 2  const MyHomePage({super.key});
 3
 4  @override
 5  State<MyHomePage> createState() => _MyHomePageState();
 6}
 7
 8class _MyHomePageState extends State<MyHomePage> {
 9  late GemMapController _mapController;
10  bool _isSimulationActive = false;
11  bool _areRoutesBuilt = false;
12
13  // We use the handler to cancel the route calculation.
14  TaskHandler? _routingHandler;
15
16  // We use the handler to cancel the navigation.
17  TaskHandler? _navigationHandler;
18
19  @override
20  void dispose() {
21    GemKit.release();
22    super.dispose();
23  }
24
25  @override
26  Widget build(BuildContext context) {
27    return Scaffold(
28      appBar: AppBar(
29        backgroundColor: Colors.deepPurple[900],
30        title: const Text("Search Along Route", style: TextStyle(color: Colors.white)),
31        leading: Row(
32          children: [
33            if (_areRoutesBuilt)
34              IconButton(
35                onPressed: _searchAlongRoute,
36                icon: const Icon(Icons.search, color: Colors.white),
37              ),
38          ],
39        ),
40        actions: [
41          if (!_isSimulationActive && _areRoutesBuilt)
42            IconButton(
43              onPressed: _startSimulation,
44              icon: const Icon(Icons.play_arrow, color: Colors.white),
45            ),
46          if (_isSimulationActive)
47            IconButton(
48              onPressed: _stopSimulation,
49              icon: const Icon(
50                Icons.stop,
51                color: Colors.white,
52              ),
53            ),
54          if (!_areRoutesBuilt)
55            IconButton(
56              onPressed: () => _onBuildRouteButtonPressed(),
57              icon: const Icon(
58                Icons.route,
59                color: Colors.white,
60              ),
61            ),
62        ],
63      ),
64      body: GemMap(
65        onMapCreated: _onMapCreated,
66      ),
67    );
68  }
69
70  void _onMapCreated(GemMapController controller) {
71    _mapController = controller;
72  }

Route Calculation

This section shows how to calculate a route between two landmarks and display it on the map.

 1Future<void> _onBuildRouteButtonPressed() async {
 2  // Define the departure.
 3  final departureLandmark = Landmark.withLatLng(latitude: 37.77903, longitude: -122.41991);
 4
 5  // Define the destination.
 6  final destinationLandmark = Landmark.withLatLng(latitude: 37.33619, longitude: -121.89058);
 7
 8  // Define the route preferences.
 9  final routePreferences = RoutePreferences();
10  _showSnackBar(context, message: 'The route is calculating.');
11
12  _routingHandler =
13      RoutingService.calculateRoute([departureLandmark, destinationLandmark], routePreferences, (err, routes) async {
14    // If the route calculation is finished, we don't have a progress listener anymore.
15    _routingHandler = null;
16
17    ScaffoldMessenger.of(context).clearSnackBars();
18
19    // If there aren't any errors, we display the routes.
20    if (err == GemError.success) {
21      // Get the routes collection from map preferences.
22      final routesMap = _mapController.preferences.routes;
23
24      // Display the routes on map.
25      for (final route in routes!) {
26        routesMap.add(route, route == routes.first, label: route.getMapLabel());
27      }
28
29      _mapController.centerOnRoute(routes.first);
30    }
31
32    setState(() {
33      _areRoutesBuilt = true;
34    });
35  });
36}

Search Along Route

The following code shows how to search for landmarks along the calculated route. The search results are printed to the console.

 1void _searchAlongRoute() {
 2  if (!_areRoutesBuilt) return;
 3
 4  final routes = _mapController.preferences.routes;
 5
 6  // Calling the search along route SDK method.
 7  // (err, results) - is a callback function that gets called when the search is finished.
 8  // err is an error enum, results is a list of landmarks.
 9  SearchService.searchAlongRoute(routes.mainRoute, (err, results) {
10    if (err != GemError.success || results == null) {
11      print("SearchAlongRoute - no results found");
12      return;
13    }
14
15    print("SearchAlongRoute - ${results.length} results:");
16    for (final Landmark landmark in results) {
17      final landmarkName = landmark.name;
18      print("SearchAlongRoute: $landmarkName");
19    }
20  });
21}

Utility Functions

Utility functions are defined to show messages and format route labels.

 1void _showSnackBar(BuildContext context, {required String message, Duration duration = const Duration(hours: 1)}) {
 2  final snackBar = SnackBar(
 3    content: Text(message),
 4    duration: duration,
 5  );
 6
 7  ScaffoldMessenger.of(context).showSnackBar(snackBar);
 8}
 9
10extension RouteExtension on Route {
11  String getMapLabel() {
12    final totalDistance = getTimeDistance().unrestrictedDistanceM + getTimeDistance().restrictedDistanceM;
13    final totalDuration = getTimeDistance().unrestrictedTimeS + getTimeDistance().restrictedTimeS;
14
15    return '${_convertDistance(totalDistance)} \n${_convertDuration(totalDuration)}';
16  }
17
18  String _convertDistance(int meters) {
19    if (meters >= 1000) {
20      double kilometers = meters / 1000;
21      return '${kilometers.toStringAsFixed(1)} km';
22    } else {
23      return '${meters.toString()} m';
24    }
25  }
26
27  String _convertDuration(int seconds) {
28    int hours = seconds ~/ 3600; // Number of whole hours
29    int minutes = (seconds % 3600) ~/ 60; // Remaining whole minutes
30
31    return '${hours}h ${minutes}m';
32  }
33}

In this example, you learned how to calculate a route, simulate navigation, and search for landmarks along the route using the gem_kit package.

Flutter Examples

Maps SDK for Flutter Examples can be downloaded or cloned with Git