Google Maps Flutter com KML

Bruno Zaranza
5 min readJul 3, 2020

--

Por enquanto, apenas para Android, buscando solução para iOS.

Aqui na empresa, estamos aos poucos migrando os nossos apps para Flutter. Uma coisa que usamos muito aqui, são mapas e seus recursos. Mas batemos de frente com um problema, que para nós é grave. O Google Maps para Flutter não está implementado para adicionar arquivos KML.

Esse artigo vai mostrar a você a solução que encontrei para adicionar KML no Google Maps para Android, que é relativamente simples. Mas ainda estou buscando a solução para iOS, já que não consegui seguir a mesma lógica que funcionou no Android.

Vou considerar que adicionar o mapa ao seu app Flutter não é o problema e que com isso já tá tudo resolvido. A documentação do próprio plugin é clara e objetiva. Então vamos direto ao ponto.

Primeiro vá nos arquivos de Android Nativo, no diretório android>app>src>main>res e crie um novo diretório raw, dentro dele coloque seu arquivo kml, como mostra a imagem a seguir:

Figura 1. Diretório para arquivo kml

Agora precisamos colocar esse kml dentro do mapa que foi gerado a partir do plugin google_maps_flutter no Android Nativo. Ficou confuso? Calma…

O que nós precisamos são códigos específicos para cada plataforma para chamar o método de adicionar o kml que iremos criar diretamente no plugin. Como já mencionei, por enquanto, só consegui no Android (essa solução dá erro no iOS). Então vamos abrir o projeto Android Nativo que foi gerado pelo Flutter, assim teremos acesso ao código do plugin, como mostra a Figura 2.

Figura 2. Aplicativo nativo android e os módulos usados no projeto

Como você pode perceber, o que o Flutter faz com os plugins, é gerar um módulo dentro do app nativo para cada plugin que você usa, agora nós podemos abrir os arquivos do módulo google_maps_flutter .

Como fazemos no nativo, vamos adicionar a dependência necessária para adicionar KMLs ao mapa no módulo do Google Maps, localize e abra o build.gradle do módulo do Google Maps.

Figura 3. Arquivo gradle do módulo de mapa

Nas dependências de projeto do módulo do Google Maps, adicione a seguinte linha e sincronize o projeto, como mostra a Figura 4.

implementation 'com.google.maps.android:android-maps-utils:2.0.1'
Figura 4. Adição do grable da lib necessária para adição de KML no Google Maps

Agora, nos arquivos do módulo Google Maps, vamos encontrar as chamadas de método, que são as chamadas transmitidas pelo Flutter no canal de comunicação entre as plataformas. Intuitivamente, vi que era na classe GoogleMapController.java , como mostra a Figura 5.

Figura 5. Classe onde se encontram as chamadas de métodos feitas pelo Flutter

Agora é só localizar o método onMethodCall , como o nome diz, são as chamadas de método feitas pelo Flutter e implementar a adição de KML como o código a seguir, como mostra a Figura 6.

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();
}
break;
Figura 6. Método de chamadas entre o canal de comunicação entre Flutter e módulo Google Maps

Feito isso, seu app já está apto a adicionar kml no mapa. Note que o nome do método que criei foi map#addKML . Mas como fazer isso agora lá do Flutter? Como você pode perceber, é necessário passar como argumento o código id (resourceId) da referência do KML que está dentro do nosso módulo app. Para isso, antes de voltarmos para o nosso código dart, vamos abrir a nossa MainActivity.kt.

Figura 7. MainActivity.kt

Na MainActivity vamos configurar nosso canal canal de comunicação entre plataformas e adicionar nosso método para pegar a referência do KML. (Para saber mais sobre isso, você pode ler a documentação aqui).

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 == "KML") {
result.success(getKMLResource())
} else {
result.notImplemented()
}
}
}

private fun getKMLResource(): Int {
return R.raw.borders;
}
}
Figura 8. Código da MainActivity.kt

Pronto, agora podemos voltar para o nosso projeto Flutter e chamar os métodos de lá. Agora para adicionar o KML, basta usar o código a seguir para chamar os métodos criados tando no módulo app para pegar a referência do KML, como no módulo Google Maps para adicionar o KML no mapa. O código é esse:

static Future<void> addKml(GoogleMapController mapController) async {

const MethodChannel channel = MethodChannel('flutter.native/helper');

try {
int kmlResourceId = await channel.invokeMethod('KML');

return mapController.channel.invokeMethod("map#addKML", <String, dynamic>{
'resourceId': kmlResourceId,
});

} on PlatformException catch (e) {
throw 'Unable to plot map: ${e.message}';
}
}
Figura 9. Chamada dos métodos criados no Flutter

Note que usamos o controller do mapa, que é retornado no widget GoogleMap pelo método onMapCreated para comunicar o canal do plugin com o método que criamos no módulo nativo Android.

O resultado que consegui foi esse:

Essa é uma solução passageira, o plugin certamente irá oferecer isso com o tempo.

Se você tem a solução para iOS, não deixe de nos contar, enquanto isso, tentarei resolver também até o plugin nos ajudar.

--

--