Getting started with MapKit for Flutter

This tutorial explains how install and setup MapKit library and create a map with a placemark for a specific location.

Step 1. Get the MapKit API key

Before you can use MapKit SDK in your application, you need the API key.

  1. Go to the Developer Dashboard.

  2. Log in to your Yandex account or create a new one.

  3. Click Connect APIs and choose MapKit Mobile SDK.

  4. Enter information about yourself and your project, select a pricing plan, and click Continue.

  5. After your API key is successfully created, it will be available in the API InterfacesMapKit Mobile SDK tab.

Note

It takes about 15 minutes to activate API keys.

Step 2. Add the MapKit library to your project

The MapKit SDK library is available in the pub.dev repository.

  1. Create a new project or open an existing one, for example, in Visual Studio Code or Android Studio.

  2. Open the project's pubspec.yaml file. In the dependencies section, add the following dependency:

    dependencies:
      # The lite library only contains the map, traffic layer,
      # LocationManager, and UserLocationLayer
      # and lets you download offline maps (in the paid version only).
      yandex_maps_mapkit_lite:
        version: ^4.6.1-beta1
    
    
      # The full library supplements lite version features with car routing,
      # bike routing, pedestrian routing, and public transport routing,
      # search, suggest, geocoding, and panorama display.
      # yandex_maps_mapkit:
      #   version: ^4.6.1-beta1
    
  3. Run pub get to sync the project and apply the changes.

    If synchronization succeeds, the library is automatically added to the project when it is compiled.

Step 3. Provide the API key to MapKit

The MapKit SDK requires you to initialize the library and set up the API key in initMapkit function.

We recommend doing that in your main() function:

import 'package:yandex_maps_mapkit_lite/init.dart' as init;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await init.initMapkit(
    apiKey: 'YOUR_API_KEY'
  ); 
}

Warning

The init.initMapkit(String apiKey) call loads the MapKit's required native libraries.

If you don't want to put your API key under a version control system, you can:

  1. Define compilation-time flag:

    flutter run --dart-define MAPKIT_API_KEY=your_api_key
    

    And use it this way:

    import 'package:yandex_maps_mapkit_lite/init.dart' as init;
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
    
      final mapkitApiKey = String.fromEnvironment('MAPKIT_API_KEY');
    
      await init.initMapkit(
        apiKey: mapkitApiKey
      ); 
    }
    
  2. You can also use ENVied package or create .dart file, which would contain a global variable with API key.

Note

Make sure your files containing API keys are ignored by your VCS.

Step 4. Add the map

  1. Add YandexMap to widgets tree:

    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
    
      await init.initMapkit(
        apiKey: 'YOUR_API_KEY'
      );
    
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
    
      MapWindow? _mapWindow;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: YandexMap(onMapCreated: (mapWindow) => _mapWindow = mapWindow)
          )
        );
      }
    }
    
  2. When the map becomes visible or invisible to the user, send onStart and onStop events to Mapkit using mapkit.onStart() and mapkit.onStop methods respectively.
    Otherwise, Mapkit will not be able to display the map and will stop processing it when the application becomes invisible to the user.

Build and run your application. There's an example of the Activity with the tappable map:

Map with the smallest zoom

Maps support multiple actions by default: move, rotate, change the zoom, and tilt.

Without additional setup, the map will be shown with the smallest possible zoom for the user's screen.

To change a map's position or zoom, use the Map.moveWithAnimation method:

map.move(
  CameraPosition(
    Point(latitude: 55.751225, longitude: 37.629540),
    zoom: 17.0,
    azimuth: 150.0,
    tilt: 30.0
  )
);

The Map.moveWithAnimation call accepts the CameraPosition argument, which fully defines the map's position, zoom, tilt, and azimuth.

There's an example of the Activity after applying the move to the map:

Map after applied move

Step 5. Note the following

MapKit stores weak references to the Listener objects passed to it. You need to store references to them in memory yourself:

final class MapCameraListenerImpl implements MapCameraListener {
  // ......
}

final class SomeMapScopedClass {

  final MapWindow _mapWindow;
  final MapCameraListener _cameraListener = MapCameraListenerImpl();

  SomeMapScopedClass(this._mapWindow);

  void addListener() {
    _mapWindow.map.addCameraListener(_cameraListener);
  }
}

Note

By default, the methods of any Listener objects and platform interfaces are called on the main thread unless the method documentation specifies otherwise.

Step 6. Display a placemark on the map

Let's modify the application such that you can show a tappable placemark on the map.

  1. Add a png resource for the placemark image to the project.

    For example, we have the image, and it is accessible by the assets/ic_pin.png identificator.

    Icon placemark

  2. Add the placemark for the Map.mapObjects collection to the specific location.

    Use ImageProvider.fromImageProvider to create an ImageProvider instance to get placemark image.

    final imageProvider = ImageProvider.fromImageProvider(const AssetImage("assets/ic_pin.png"));
    final placemark = mapWindow.map.mapObjects.addPlacemark()
      ..geometry = Point(latitude: 59.935493, longitutde: 30.327392)
      ..setICon(imageProvider);
    
  3. To subscribe to created placemark's taps use MapObject.addTapListener method.

    final class MapObjectTapListenerImpl implements MapObjectTapListener {
    
      @override
      bool onMapObjectTap(MapObject mapObject, Point point) {
        log("Tapped the point ${point.longitude}, ${point.latitude}");
        return true;
      }
    }
    
    final listener = MapObjectTapListenerImpl();
    placemark.addTapListener(listener);
    

Build and run your application. There's a placemark with your custom image on the map. Tap the placemark, and the message toast will show up:

Map after placemark was tapped