Skip to content

What is Nearby

This example demonstrates how to create a Flutter app that shows nearby landmarks based on the user’s current position using the gem_kit package.

Nearby Locations - 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

Navigate to the project folder for this example to build and run the application.

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:

allprojects {
    repositories {
        google()
        mavenCentral()
        maven {
           url "${rootDir}/../plugins/gem_kit/android/build"
        }
    }
}

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

android {
    defaultConfig {
        applicationId "com.magiclane.gem_kit.examples.example_pathname"
        minSdk 21
        targetSdk flutter.targetSdk
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
    buildTypes {
        release {
            minifyEnabled false
            shrinkResources false

            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

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

App entry and initialization

const projectApiToken = String.fromEnvironment('GEM_TOKEN');

void main() {
  runApp(const MyApp());
}

This code initializes the projectApiToken with the required authorization token and launches the app.

How It Works

This example app demonstrates the following features:

  • Obtain location permissions and show a map centered on the user’s location.

  • Display nearby landmarks as a list.

  • Allow navigation to a detail page displaying information about nearby landmarks.

Nearby Locations - Flutter screenshot

Map Display and Permissions

The map is displayed and initialized within the MyHomePage widget, which also handles location permissions for Android and iOS.

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late GemMapController _mapController;
  PermissionStatus _locationPermissionStatus = PermissionStatus.denied;
  bool _hasLiveDataSource = false;

  @override
  void dispose() {
    GemKit.release();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.deepPurple[900],
        title: const Text('What\'s Nearby', style: TextStyle(color: Colors.white)),
        actions: [
          IconButton(
            onPressed: () => _onWhatIsNearbyButtonPressed(context),
            icon: const Icon(Icons.question_mark, color: Colors.white),
          ),
        ],
      ),
      body: GemMap(onMapCreated: _onMapCreated, appAuthorization: projectApiToken),
    );
  }

This widget handles the UI, setting up the map and app bar, and uses permission_handler for requesting location permissions.

Fetching Nearby Locations

The WhatIsNearbyPage widget displays a list of nearby landmarks based on the user’s current position.

class WhatIsNearbyPage extends StatefulWidget {
  final Coordinates position;
  const WhatIsNearbyPage({super.key, required this.position});

  @override
  State<WhatIsNearbyPage> createState() => _WhatIsNearbyPageState();
}

class _WhatIsNearbyPageState extends State<WhatIsNearbyPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("What's Nearby", style: TextStyle(color: Colors.white)),
        backgroundColor: Colors.deepPurple[900],
      ),
      body: FutureBuilder(
        future: _getNearbyLocations(),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return const Center(child: CircularProgressIndicator());
          }
          return ListView.separated(
            itemBuilder: (context, index) => NearbyItem(
              landmark: snapshot.data![index],
              currentPosition: widget.position,
            ),
            separatorBuilder: (context, index) => const Divider(height: 0),
            itemCount: snapshot.data!.length,
          );
        },
      ),
    );
  }

  Future<List<Landmark>?> _getNearbyLocations() async {
    final preferences = SearchPreferences(searchAddresses: false)
      ..landmarkCategories = GenericCategories.categories;
    final completer = Completer<List<Landmark>?>();
    SearchService.searchAroundPosition(preferences: preferences, widget.position, (err, result) {
      completer.complete(result);
    });
    return completer.future;
  }

This code searches for nearby landmarks, displaying the results in a ListView.

Displaying Landmark Information

Each nearby landmark is displayed in a list tile showing the name and distance from the current position.

class NearbyItem extends StatefulWidget {
  final Landmark landmark;
  final Coordinates currentPosition;
  const NearbyItem({super.key, required this.landmark, required this.currentPosition});

  @override
  State<NearbyItem> createState() => _NearbyItemState();
}

class _NearbyItemState extends State<NearbyItem> {
  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(
        widget.landmark.categories.first.name,
        style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
        maxLines: 2,
        overflow: TextOverflow.ellipsis,
      ),
      trailing: Text(
        _convertDistance(widget.landmark.coordinates.distance(widget.currentPosition).toInt()),
        style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
      ),
    );
  }

  String _convertDistance(int meters) {
    if (meters >= 1000) {
      return '${(meters / 1000).toStringAsFixed(1)} km';
    } else {
      return '$meters m';
    }
  }

This component formats and displays the name and distance of each landmark.

Flutter Examples

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