Get started with Woosmap for Flutter

Get access to Woosmap services for your native mobile developments on hybrid Flutter development.

  1. Creating your first Application
  2. Android Platform Settings
  3. How to display Map
  4. Accessing various map functions
  5. Customize loader

The Woosmap Flutter plugin is a library that embeds interactive maps directly into your application. You can also add a stores overlay to the map to call out points of interest and get relevant information.

The SDK offers an interface to manage the Indoor Mapview and subscribe to events on the map.

  Android iOS
Support SDK 33+ 13.0+

Creating your first Application

Create your new flutter application as

Shell
        flutter create --platforms=ios,android woosmap
cd woosmap
flutter pub add woosmap_flutter
flutter pub get

    

Create your API Key

In order to use our service from a mobile, you will need to create a Private API Key with the proper restriction in the console. If you don’t know how, you can follow the directions specified in the API Key documentation

Android Platform Settings

This plugin uses Platform Views to embed the Android’s WebView within the Flutter app.

You should however make sure to set the correct minSdkVersion in android/app/build.gradle if it was previously lower than 19:

gradle
        android {
  compileSdkVersion 33
    defaultConfig {
        minSdkVersion 19
        targetSdkVersion 33
    }
}

    

Add the following permission inside the manifest tag in the AndroidManifest.xml file located at android/app/src/main.

xml
        <uses-permission android:name="android.permission.INTERNET"/>

    

Once you create the application and install the woosmap_flutter plugin, you are ready to use the Woosmap feature within the application.

How to display Map

  1. Instantiating a WoosmapMapViewWidget.
lib/map_event_snippet.dart
         WoosmapMapViewWidget.create(
        wooskey: Platform.isAndroid ? "<<YOUR ANDROID PRIVATE KEY>>" : "<<YOUR IOS PRIVATE KEY>>",
        onRef: (p0) async {
          _controller = p0;
        },
        mapOptions: MapOptions(
          center: LatLng(lat: 19.115932, lng: 72.907852),
          zoom: 10
        ),
        click: (message) {
          debugPrint("idle");
        },
        bounds_changed: () {
          debugPrint("idle");
        },
        center_changed: () {
          debugPrint("idle");
        },
        dblclick: (m) {
          debugPrint("idle");
        },
        drag: () {
          debugPrint("idle");
        },
        dragend: () {
          debugPrint("idle");
        },
        dragstart: () {
          debugPrint("idle");
        },
        idle: () {
          debugPrint("idle");
        },
        mousemove: (x) {
          debugPrint("idle");
        },
        mouseout: (x) {
          debugPrint("idle");
        },
        mouseover: (x) {
          debugPrint("idle");
        },
        rightclick: (x) {
          debugPrint("idle");
        },
        zoom_changed: () {
          debugPrint("idle");
        },
      )

    
        import 'package:flutter/widgets.dart';

class AppConstants extends InheritedWidget {
  static AppConstants? of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<AppConstants>();

  const AppConstants({required super.child, super.key});

  final String privateKeyiOS = "<<Your private iOS woosmap key>>";
  final String privateKeyAndroid = "<<Your private Android woosmap key>>";
  @override
  bool updateShouldNotify(AppConstants oldWidget) => false;
}

    
        import 'dart:convert';
import 'dart:core';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:woosmap_flutter/woosmap_flutter.dart';
import './constants.dart';

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

  @override
  State<MapEventsSnippet> createState() => _MapEventsSnippetState();
}

class _MapEventsSnippetState extends State<MapEventsSnippet> {
  WoosmapController? _controller;
  TextEditingController? txtLogController;
  @override
  void initState() {
    super.initState();
    txtLogController = TextEditingController();
    if (_controller != null) {
      debugPrint("info ===> Indoor controller not initialize");
    }
  }

  @override
  void dispose() {
    txtLogController?.dispose();
    super.dispose();
  }

  Future<void> reloadMenu() async {
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Woosmap Map (Events)'),
        actions: <Widget>[
          MapEventsMenu(webViewController: _controller),
        ],
      ),
      body: SafeArea(
        child: Column(
          mainAxisSize: MainAxisSize.max,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Expanded(
                child: Align(
                    alignment: const AlignmentDirectional(-1, -1),
                    child: WoosmapMapViewWidget.create(
                      wooskey: Platform.isAndroid
                          ? AppConstants.of(context)?.privateKeyAndroid ?? ""
                          : AppConstants.of(context)?.privateKeyiOS ?? "",
                      onRef: (p0) async {
                        _controller = p0;
                        reloadMenu();
                      },
                      mapOptions: MapOptions(
                          center: LatLng(lat: 19.115932, lng: 72.907852),
                          zoom: 10),
                      click: (message) {
                        txtLogController?.text =
                            "Click, ${txtLogController?.text}";
                      },
                      bounds_changed: () {
                        txtLogController?.text =
                            "bounds_changed, ${txtLogController?.text}";
                      },
                      center_changed: () {
                        txtLogController?.text =
                            "center_changed, ${txtLogController?.text}";
                      },
                      dblclick: (m) {
                        txtLogController?.text =
                            "dblclick, ${txtLogController?.text}";
                      },
                      drag: () {
                        txtLogController?.text =
                            "drag, ${txtLogController?.text}";
                      },
                      dragend: () {
                        txtLogController?.text =
                            "dragend, ${txtLogController?.text}";
                      },
                      dragstart: () {
                        txtLogController?.text =
                            "dragstart, ${txtLogController?.text}";
                      },
                      idle: () {
                        debugPrint("idle");
                        /*txtLogController?.text =
                            "idle, ${txtLogController?.text}";*/
                      },
                      mousemove: (x) {
                        txtLogController?.text =
                            "mousemove, ${txtLogController?.text}";
                      },
                      mouseout: (x) {
                        txtLogController?.text =
                            "mouseout, ${txtLogController?.text}";
                      },
                      mouseover: (x) {
                        txtLogController?.text =
                            "mouseover, ${txtLogController?.text}";
                      },
                      rightclick: (x) {
                        txtLogController?.text =
                            "rightclick, ${txtLogController?.text}";
                      },
                      zoom_changed: () {
                        txtLogController?.text =
                            "zoom_changed, ${txtLogController?.text}";
                      },
                    ))),
            Container(
                width: 100,
                height: 100,
                decoration: const BoxDecoration(
                  color: Color(0xFFDEE6E6),
                ),
                child: Column(mainAxisSize: MainAxisSize.max, children: [
                  Expanded(
                      child: Padding(
                    padding: const EdgeInsetsDirectional.fromSTEB(10, 5, 10, 5),
                    child: TextFormField(
                      controller: txtLogController,
                      minLines: null,
                      maxLines: null,
                      autofocus: true,
                      enabled: false,
                      obscureText: false,
                      decoration: const InputDecoration(
                        labelText: 'Events Log\n',
                        hintText: 'Event fired',
                        enabledBorder: UnderlineInputBorder(
                          borderSide: BorderSide(
                            color: Color(0x00000000),
                            width: 1,
                          ),
                          borderRadius: BorderRadius.only(
                            topLeft: Radius.circular(4.0),
                            topRight: Radius.circular(4.0),
                          ),
                        ),
                        focusedBorder: UnderlineInputBorder(
                          borderSide: BorderSide(
                            color: Color(0x00000000),
                            width: 1,
                          ),
                          borderRadius: BorderRadius.only(
                            topLeft: Radius.circular(4.0),
                            topRight: Radius.circular(4.0),
                          ),
                        ),
                        errorBorder: UnderlineInputBorder(
                          borderSide: BorderSide(
                            color: Color(0x00000000),
                            width: 1,
                          ),
                          borderRadius: BorderRadius.only(
                            topLeft: Radius.circular(4.0),
                            topRight: Radius.circular(4.0),
                          ),
                        ),
                        focusedErrorBorder: UnderlineInputBorder(
                          borderSide: BorderSide(
                            color: Color(0x00000000),
                            width: 1,
                          ),
                          borderRadius: BorderRadius.only(
                            topLeft: Radius.circular(4.0),
                            topRight: Radius.circular(4.0),
                          ),
                        ),
                      ),
                    ),
                  ))
                ]))
          ],
        ),
      ),
    );
  }
}

enum EventMenuOptions {
  fitBounds,
  getBounds,
  getCenter,
  getHeading,
  getTilt,
  getZoom,
  panBy,
  panTo,
  panToBounds,
  setCenter,
  setHeading,
  setTilt,
  setZoom,
}

class MapEventsMenu extends StatelessWidget {
  const MapEventsMenu({
    super.key,
    required this.webViewController,
  });

  final WoosmapController? webViewController;

  @override
  Widget build(BuildContext context) {
    return PopupMenuButton<EventMenuOptions>(
      key: const ValueKey<String>('ShowPopupMenu'),
      onSelected: (EventMenuOptions value) {
        switch (value) {
          case EventMenuOptions.fitBounds:
            _onFitBounds();
            break;
          case EventMenuOptions.getBounds:
            _onGetBounds().then((value) {
              if (value != null) {
                if (!context.mounted) return;
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text(jsonEncode(value.toJson()))),
                );
              }
            });
            break;
          case EventMenuOptions.getCenter:
            _onGetCenter().then((value) {
              if (value != null) {
                if (!context.mounted) return;
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text(jsonEncode(value.toJson()))),
                );
              }
            });
            break;
          case EventMenuOptions.getHeading:
            _onHeading().then((value) {
              if (!context.mounted) return;
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text(jsonEncode(value))),
              );
            });
            break;
          case EventMenuOptions.getTilt:
            _onTilt().then((value) {
              if (!context.mounted) return;
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text(jsonEncode(value))),
              );
            });
            break;
          case EventMenuOptions.getZoom:
            _onZoom().then((value) {
              if (!context.mounted) return;
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Zoom ${jsonEncode(value)}')),
              );
            });
            break;
          case EventMenuOptions.panBy:
            _onPanBy();
            break;
          case EventMenuOptions.panTo:
            _onPanTo();
            break;
          case EventMenuOptions.panToBounds:
            _onPanToBounds();
            break;
          case EventMenuOptions.setCenter:
            _onSetCenter();
            break;
          case EventMenuOptions.setHeading:
            _onSetHeading();
            break;
          case EventMenuOptions.setTilt:
            _onSetTilt();
            break;
          case EventMenuOptions.setZoom:
            _onSetZoom();
            break;
        }
      },
      itemBuilder: (BuildContext context) => <PopupMenuItem<EventMenuOptions>>[
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.fitBounds,
          child: Text('fitBounds'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.getBounds,
          child: Text('getBounds'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.getCenter,
          child: Text('getCenter'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.getHeading,
          child: Text('getHeading'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.getTilt,
          child: Text('getTilt'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.getZoom,
          child: Text('getZoom'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.panBy,
          child: Text('panBy'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.panTo,
          child: Text('panTo'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.panToBounds,
          child: Text('panToBounds'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.setCenter,
          child: Text('setCenter'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.setHeading,
          child: Text('setHeading'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.setTilt,
          child: Text('setTilt'),
        ),
        const PopupMenuItem<EventMenuOptions>(
          value: EventMenuOptions.setZoom,
          child: Text('setZoom'),
        ),
      ],
    );
  }

  Future<void> _onFitBounds() async {
    await webViewController?.fitBounds(
        LatLngBounds(
            ne: LatLng(lat: 48.844437932920535, lng: 2.3743880269761393),
            sw: LatLng(lat: 48.854437932920535, lng: 2.3843880269761393)),
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));
    return;
  }

  Future<LatLng?> _onGetCenter() async {
    LatLng? result;
    result = await webViewController?.getCenter();
    return result;
  }

  Future<LatLngBounds?> _onGetBounds() async {
    LatLngBounds? result;
    result = await webViewController?.getBounds(
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));
    return result;
  }

  Future<double> _onHeading() async {
    double result;
    result = (await webViewController?.getHeading()) as double;
    return result;
  }

  Future<double> _onTilt() async {
    double result;
    result = (await webViewController?.getTilt()) as double;
    return result;
  }

  Future<double> _onZoom() async {
    double result;
    result = (await webViewController?.getZoom()) as double;
    return result;
  }

  Future<void> _onPanBy() async {
    await webViewController?.panBy(20, 10);
    return;
  }

  Future<void> _onPanTo() async {
    await webViewController?.panTo(
        LatLng(lat: 48.844437932920535, lng: 2.3743880269761393),
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));
    return;
  }

  Future<void> _onPanToBounds() async {
    await webViewController?.panToBounds(
        LatLngBounds(
          ne: LatLng(lat: 48.844437932920535, lng: 2.3743880269761393),
          sw: LatLng(lat: 48.854437932920535, lng: 2.3843880269761393)
        ),
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));
    return;
  }

  Future<void> _onSetCenter() async {
    await webViewController?.setCenter(
        LatLng(lat: 48.844437932920535, lng: 2.3743880269761393),
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));
    return;
  }

  Future<void> _onSetHeading() async {
    await webViewController?.setHeading(20);
    return;
  }

  Future<void> _onSetTilt() async {
    await webViewController?.setTilt(5);
    return;
  }

  Future<void> _onSetZoom() async {
    await webViewController?.setZoom(20);
    return;
  }
}

    

Accessing various map functions

lib/map_event_snippet.dart
        await _controller.fitBounds(
        LatLngBounds(
          ne: LatLng(lat: 48.844437932920535, lng: 2.3743880269761393),
          sw: LatLng(lat: 48.854437932920535, lng: 2.3843880269761393)
        ),
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));

    
lib/map_event_snippet.dart
        LatLng result = await _controller.getCenter();

    
lib/map_event_snippet.dart
        LatLngBounds result = await _controller.getBounds(
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));

    
lib/map_event_snippet.dart
        double result = (await _controller.getHeading()) as double;

    
lib/map_event_snippet.dart
        double result = (await _controller.getTilt()) as double;

    
lib/map_event_snippet.dart
        double result = (await _controller.getZoom()) as double;

    
lib/map_event_snippet.dart
        await _controller.panBy(20, 10);

    
lib/map_event_snippet.dart
        
await _controller.panTo(
        LatLng(lat: 48.844437932920535, lng: 2.3743880269761393),
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));

    
lib/map_event_snippet.dart
        await _controller.panToBounds(
        LatLngBounds(
          ne: LatLng(lat: 48.844437932920535, lng: 2.3743880269761393),
          sw: LatLng(lat: 48.854437932920535, lng: 2.3843880269761393)
        ),
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));

    
lib/map_event_snippet.dart
        await _controller.setCenter(
        LatLng(lat: 48.844437932920535, lng: 2.3743880269761393),
        WoosPadding(top: 2, left: 2, right: 3, bottom: 3));

    
lib/map_event_snippet.dart
        await _controller.setHeading(20);

    
lib/map_event_snippet.dart
        await _controller.setTilt(5);

    
lib/map_event_snippet.dart
        await _controller.setZoom(20);

    

Customize loader

Plugin allows customization of the loader on the map. To change the loader, you need to add a gif image to the assets or images folder and update the loader setting in the widget as shown below.

lib/map_event_snippet.dart
          WoosmapMapViewWidget.create(
        wooskey: "<<YOUR WOOSMAP KEY>>",
        onRef: (p0) async {
          _controller = p0;
        },
        loader: const AssetImage("assets/spinner.gif"),
        ....
        ....
        ....
      )

    
Was this article helpful?
Have more questions? Submit a request