Skip to content

KML for Google Maps Visualizations

Mahinour Elsarky edited this page Aug 25, 2024 · 3 revisions

Visualization is a very important part in all Liquid Galaxy applications, and since not everyone can have access to an LG rig, the apps has to function standalone through Google Maps. However, there is no official way for showing KML in Google Maps, but what we can do is tweak the native code for each platform. Since we are working with Android, I am going to explain the steps of uploading KML on Google Maps.

Step 1: Add the KML file in this directory:

Go to the root directory of your project and navigate to android-> app-> src-> main-> res and add a new directory raw where you can add the KML file inside

Step 2: Making Changes to the Native Code

  1. Right-click on android folder of your project-> open in Android studio

You should be able to find this:

  1. Navigate to Gradle Scripts-> build.gradle (google_maps_flutter_android)

  2. Add to the dependencies:

implementation 'com.google.maps.android:android-maps-utils:3.6.0'

  1. In Android studio, navigate to google_maps_flutter_android-> java-> io.flutter.plugins.googlemaps-> GoogleMapController.java

  1. Add the following part of code in Method onMethodCall:
case"map#addKML":
      int resourceId = call.argument("resourceId");
      try {
        KmlLayer kml = new KmlLayer(googleMap, resourceId, context);
        kml.addLayerToMap();
      } catch (XmlPullParserException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }

  1. If you got any errors, make sure you include in the imports above:
import com.google.maps.android.data.kml.KmlLayer;
  1. Navigate to android->app->java->com.example.ai_touristic_info_tool->MainActivity.java and write down the following code:
package com.example.temp

import android.os.Bundle
import android.os.PersistableBundle
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity: FlutterActivity() {
    private val CHANNEL = "flutter.native/helper"
    private var mapId: Int? = null
    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        GeneratedPluginRegistrant.registerWith(FlutterEngine(this))
    }

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine);
        MethodChannel(flutterEngine.dartExecutor, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "map#addKML") {
                val kmlData = getKMLResource()
                val kmlDatalog = loadKMLFromResource(kmlData)
                run {
                    result.success(kmlData)
                }
            } else {
                result.notImplemented()
            }
        }
    }

    private fun loadKMLFromResource(resourceId: Int): String {
        val inputStream = context.resources.openRawResource(resourceId)
        return inputStream.bufferedReader().use { it.readText() }
    }

    private fun getKMLResource(): Int {
        return R.raw.samples;
    }
}

Make sure to rename R.raw.samples; according to your kml file name. Since here the kml file name was samples.kml we wrote down R.raw.samples.

  1. Last step is to add a function addKml in your flutter project for uploading the KML in res directory into google maps
import 'package:flutter/services.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';


/// Adds a KML (Keyhole Markup Language) layer to the Google Map managed by the given [mapController].
///
/// This function interacts with platform-specific code to load and display a KML layer on the map.
/// It uses method channels to communicate with the native Android or iOS code.
///
/// Parameters:
/// - [mapController]: The [GoogleMapController] that manages the Google Map instance.
///
/// Throws:
/// - A [PlatformException] if there is an issue with invoking the method to add the KML layer.
/// - A general exception if any other error occurs during the process.
///
/// Usage:
/// ```dart
/// await addKml(mapController);
/// ```
/// 
Future<void> addKml(GoogleMapController mapController) async {
    var mapId = mapController.mapId;
    const MethodChannel channel = MethodChannel('flutter.native/helper');
    final MethodChannel kmlchannel = MethodChannel('plugins.flutter.dev/google_maps_android_${mapId}');
    try {
      int kmlResourceId = await channel.invokeMethod('map#addKML');
 
      var c = kmlchannel.invokeMethod("map#addKML", <String, dynamic>{
        'resourceId': kmlResourceId,
      });
      print('addKml done${c}');
    } on PlatformException catch (e) {
      throw 'Unable to plot map: ${e.message}';
    }catch(e){
      print("error");
      throw 'Unable to plot map${e}';
    }
  }

Following those steps, you will be able to upload the kml in res directory successfully.

Some Problems with the above approach

  • The above approach only works with 1 KML, and does not support multiple KMLs to be uploaded on Google Maps
  • The above approach does not support dynamic data