<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: António Valente</title>
    <description>The latest articles on DEV Community by António Valente (@biklas7).</description>
    <link>https://dev.to/biklas7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F426330%2Fe0ab2065-a5bc-4b12-ba17-0faca9054193.jpeg</url>
      <title>DEV Community: António Valente</title>
      <link>https://dev.to/biklas7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/biklas7"/>
    <language>en</language>
    <item>
      <title>How to Customize Your Cluster Markers on Flutter Google Maps</title>
      <dc:creator>António Valente</dc:creator>
      <pubDate>Wed, 08 Jul 2020 16:19:18 +0000</pubDate>
      <link>https://dev.to/coletiv/how-to-customize-your-cluster-markers-on-flutter-google-maps-k50</link>
      <guid>https://dev.to/coletiv/how-to-customize-your-cluster-markers-on-flutter-google-maps-k50</guid>
      <description>&lt;p&gt;If you’ve been following our blog and read our recent posts about &lt;a href="https://flutter.dev/"&gt;Flutter&lt;/a&gt; and the &lt;a href="https://pub.dev/packages/google_maps_flutter"&gt;Google Maps package&lt;/a&gt;, I’m sure you now know how to cluster markers, but how do you customize or make them dynamic?&lt;br&gt;
&lt;br&gt;&lt;br&gt;
This is a follow-up article of &lt;a href="https://dev.to/blog/how-to-cluster-markers-on-google-maps-using-flutter/"&gt;How to Cluster Markers on Google Maps using Flutter&lt;/a&gt; so I will not get into the details about clustering the markers. Instead, &lt;strong&gt;I will tell you how I was able to customize the cluster markers by adding a dynamic child counter that updates depending on the zoom level.&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
This was missing in the previous article, and since some of you asked for it here I am! 😎 Without further wait, let’s get into it! 💪&lt;br&gt;
&lt;br&gt;&lt;br&gt;
So, how do you customize the markers? Unfortunately, the official Google Maps package &lt;a href="https://github.com/flutter/flutter/issues/26863"&gt;doesn’t support clusters&lt;/a&gt;, and the &lt;a href="https://github.com/flutter/flutter/issues/24213"&gt;markers aren’t event widgets&lt;/a&gt; so we must resort to drawing on the &lt;a href="https://api.flutter.dev/flutter/dart-ui/Canvas-class.html"&gt;canvas&lt;/a&gt;… wait! Isn’t that scary? 😱&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Flutter makes it easy so it’s nothing to be afraid of. The following code contains the solution I found:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:google_maps_flutter/google_maps_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BitmapDescriptor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getClusterMarker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;clusterSize&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;clusterColor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;textColor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;PictureRecorder&lt;/span&gt; &lt;span class="n"&gt;pictureRecorder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PictureRecorder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Canvas&lt;/span&gt; &lt;span class="n"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Canvas&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pictureRecorder&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Paint&lt;/span&gt; &lt;span class="n"&gt;paint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Paint&lt;/span&gt;&lt;span class="o"&gt;()..&lt;/span&gt;&lt;span class="na"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clusterColor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;TextPainter&lt;/span&gt; &lt;span class="n"&gt;textPainter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TextPainter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;textDirection:&lt;/span&gt; &lt;span class="n"&gt;TextDirection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ltr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;drawCircle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;textPainter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TextSpan&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;text:&lt;/span&gt; &lt;span class="n"&gt;clusterSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
    &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;fontSize:&lt;/span&gt; &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;fontWeight:&lt;/span&gt; &lt;span class="n"&gt;FontWeight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bold&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;textColor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;),&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;textPainter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;textPainter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;paint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;textPainter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;textPainter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;),&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;pictureRecorder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endRecording&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toImage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toInt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toInt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toByteData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;format:&lt;/span&gt; &lt;span class="n"&gt;ImageByteFormat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;png&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;BitmapDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asUint8List&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First, we set up the &lt;a href="https://api.flutter.dev/flutter/dart-ui/PictureRecorder-class.html"&gt;PictureRecorder&lt;/a&gt;, &lt;a href="https://api.flutter.dev/flutter/dart-ui/Canvas-class.html"&gt;Canvas&lt;/a&gt;, &lt;a href="https://api.flutter.dev/flutter/dart-ui/Paint-class.html"&gt;Paint&lt;/a&gt;, and &lt;a href="https://api.flutter.dev/flutter/painting/TextPainter-class.html"&gt;TextPainter&lt;/a&gt; with proper colors and text direction, then we simply get the radius and draw a circle on the canvas.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Next is the text, we want it to be the cluster size counter text and we add some style to it. In the end, we simply end the picture recorder and convert it to an image and then to a bitmap descriptor needed for the marker icon.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
And that’s it! Pretty simple isn’t it? To end this article, I will tell you what more has changed from the latest &lt;a href="https://coletiv.com/blog/how-to-cluster-markers-on-google-maps-using-flutter/"&gt;How to Cluster Markers on Google Maps using Flutter&lt;/a&gt; post and we’re finished 🙌.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
We just need to update the way we’re generating the markers like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clusterManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clusters&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;[-&lt;/span&gt;&lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt; &lt;span class="n"&gt;currentZoom&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toInt&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;mapMarker&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapMarker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isCluster&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mapMarker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_getClusterMarker&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;mapMarker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pointsSize&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mapMarker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toMarker&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We’re checking if the map marker is a cluster and if it is we generate the cluster icon with the updated point size to have the correct counter text inside the circle marker. We also tell it which colors we want to use and the width. Just keep in mind that this is now an async operation.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
There are a few more small changes that you can see on our &lt;a href="https://github.com/coletiv/flutter_google_maps_clusters"&gt;flutter google maps clusters&lt;/a&gt; repo. Go on and check it out!&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank you for reading!
&lt;/h2&gt;

&lt;p&gt;Thank you so much for reading, it means a lot to us! Also &lt;strong&gt;don’t forget to follow &lt;a href="https://dev.to/"&gt;Coletiv&lt;/a&gt; on &lt;a href="https://twitter.com/coletivstudio"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.linkedin.com/company/coletiv/"&gt;LinkedIn&lt;/a&gt;&lt;/strong&gt; as we keep posting more and more interesting articles on multiple technologies.&lt;/p&gt;

&lt;p&gt;In case you don’t know, Coletiv is a software development studio from Porto specialized in Elixir, Web, and App (iOS &amp;amp; Android) development. But we do all kinds of stuff. We take care of UX/UI design, software development, and even security for you.&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;&lt;a href="https://coletiv.com/contact"&gt;let’s craft something together?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>tutorial</category>
      <category>googlemaps</category>
      <category>dart</category>
    </item>
    <item>
      <title>How to Cluster Markers on Flutter using Google Maps</title>
      <dc:creator>António Valente</dc:creator>
      <pubDate>Wed, 08 Jul 2020 16:14:50 +0000</pubDate>
      <link>https://dev.to/coletiv/how-to-cluster-markers-on-flutter-using-google-maps-1djo</link>
      <guid>https://dev.to/coletiv/how-to-cluster-markers-on-flutter-using-google-maps-1djo</guid>
      <description>&lt;p&gt;If you’re using &lt;a href="https://pub.dev/packages/google_maps_flutter" rel="noopener noreferrer"&gt;Google Maps&lt;/a&gt; to display markers on your &lt;a href="https://flutter.dev/" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt; app, I’m sure that you will eventually need to cluster those markers. You don’t want users to zoom out and see hundreds of markers spamming the map right?&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Well, as I’m sure you know by now, that feature isn’t supported yet by the official Google Maps package. Check this &lt;a href="https://github.com/flutter/flutter/issues/26863" rel="noopener noreferrer"&gt;issue&lt;/a&gt; to know more.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Rest assured though because I’ve got a solution that might work for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvw69f8ok8h6aajqu8uef.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvw69f8ok8h6aajqu8uef.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Fluster Package Comes to the Rescue
&lt;/h2&gt;

&lt;p&gt;In your search for solutions, you probably bumped into the &lt;a href="https://pub.dev/packages/fluster" rel="noopener noreferrer"&gt;Fluster&lt;/a&gt; package. This package uses a Dart port of &lt;a href="https://github.com/mapbox/supercluster" rel="noopener noreferrer"&gt;supercluster&lt;/a&gt; and works really well, but how do you use it on your Flutter project?&lt;br&gt;
&lt;br&gt;&lt;br&gt;
The &lt;a href="https://pub.dev/packages/fluster#-readme-tab-" rel="noopener noreferrer"&gt;readme&lt;/a&gt; is very brief, doesn’t explain much and the &lt;a href="https://github.com/alfonsocejudo/fluster/blob/master/example/fluster_example.dart" rel="noopener noreferrer"&gt;example&lt;/a&gt; isn’t even a Flutter project. This makes the package very easy to overlook unless you find this &lt;a href="https://github.com/alfonsocejudo/fluster_demo/" rel="noopener noreferrer"&gt;demo project&lt;/a&gt; by the package author, but even with this code, you will struggle to understand how to use it in your project. At least I did. Again, there are no proper readme instructions and the code can be a bit overwhelming at first.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
In this article, I will break down the code and explain it step by step so you can understand and implement a similar solution in your project.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementing Fluster
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Extending the &lt;a href="https://github.com/alfonsocejudo/fluster/blob/master/lib/src/clusterable.dart" rel="noopener noreferrer"&gt;Clusterable&lt;/a&gt; class
&lt;/h3&gt;

&lt;p&gt;Fluster can only handle markers that conform to the Clusterable abstract class so this is a good place to start.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:fluster/fluster.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:google_maps_flutter/google_maps_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:meta/meta.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MapMarker&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;Clusterable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;LatLng&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;BitmapDescriptor&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;MapMarker&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="nd"&gt;@required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nd"&gt;@required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nd"&gt;@required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;isCluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;clusterId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;pointsSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;childMarkerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="nl"&gt;markerId:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;latitude:&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;longitude:&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;isCluster:&lt;/span&gt; &lt;span class="n"&gt;isCluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;clusterId:&lt;/span&gt; &lt;span class="n"&gt;clusterId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;pointsSize:&lt;/span&gt; &lt;span class="n"&gt;pointsSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;childMarkerId:&lt;/span&gt; &lt;span class="n"&gt;childMarkerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Marker&lt;/span&gt; &lt;span class="nf"&gt;toMarker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Marker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="nl"&gt;markerId:&lt;/span&gt; &lt;span class="n"&gt;MarkerId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="nl"&gt;position:&lt;/span&gt; &lt;span class="n"&gt;LatLng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is my implementation. You can see it on Github &lt;a href="https://github.com/coletiv/flutter_google_maps_clusters/blob/master/lib/helpers/map_marker.dart" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Notice how I’ve added the &lt;code&gt;toMarker()&lt;/code&gt; method. This method will come in handy later on, to convert our list of MapMarkers to a list of Markers so our GoogleMap widget doesn’t complain.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Note that you can add more arguments to the class depending on your use case. Like an &lt;code&gt;onTap()&lt;/code&gt; callback or a Marker &lt;code&gt;InfoWindow&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create the List of Markers to be Displayed
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_google_maps_clusters/helpers/map_marker.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:google_maps_flutter/google_maps_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MapMarker&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;markers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LatLng&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;markerLocations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="n"&gt;LatLng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;41.147125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.611249&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="n"&gt;LatLng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;41.145599&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.610691&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LatLng&lt;/span&gt; &lt;span class="n"&gt;markerLocation&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;markerLocations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;markers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;MapMarker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;markerLocations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;markerLocation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
         &lt;span class="nl"&gt;position:&lt;/span&gt; &lt;span class="n"&gt;markerLocation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;markerImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should have a list of locations where you want to place the markers. Create a MapMarker for every location.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Init Fluster
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:fluster/fluster.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_google_maps_clusters/helpers/map_marker.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Fluster&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MapMarker&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Fluster&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MapMarker&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;minZoom:&lt;/span&gt; &lt;span class="n"&gt;minZoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// The min zoom at clusters will show&lt;/span&gt;
   &lt;span class="nl"&gt;maxZoom:&lt;/span&gt; &lt;span class="n"&gt;maxZoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// The max zoom at clusters will show&lt;/span&gt;
   &lt;span class="nl"&gt;radius:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Cluster radius in pixels&lt;/span&gt;
   &lt;span class="nl"&gt;extent:&lt;/span&gt; &lt;span class="mi"&gt;2048&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Tile extent. Radius is calculated with it.&lt;/span&gt;
   &lt;span class="nl"&gt;nodeSize:&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Size of the KD-tree leaf node.&lt;/span&gt;
   &lt;span class="nl"&gt;points:&lt;/span&gt; &lt;span class="n"&gt;markers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// The list of markers created before&lt;/span&gt;
   &lt;span class="nl"&gt;createCluster:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="c1"&gt;// Create cluster marker&lt;/span&gt;
      &lt;span class="n"&gt;BaseCluster&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MapMarker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
         &lt;span class="nl"&gt;position:&lt;/span&gt; &lt;span class="n"&gt;LatLng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="n"&gt;clusterImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;isCluster:&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isCluster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;clusterId:&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;pointsSize:&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pointsSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="nl"&gt;childMarkerId:&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;childMarkerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, you’re creating your Fluster instance. It will handle all the logic of updating the markers and clusters you need to show in your map for a given zoom level. For more information about the parameters used, check out the Fluster &lt;a href="https://github.com/alfonsocejudo/fluster/blob/master/lib/src/fluster.dart" rel="noopener noreferrer"&gt;source code&lt;/a&gt; or the &lt;a href="https://github.com/mapbox/supercluster#options" rel="noopener noreferrer"&gt;supercluster options&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Get Cluster Markers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:fluster/fluster.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_google_maps_clusters/helpers/map_marker.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:google_maps_flutter/google_maps_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Marker&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;googleMarkers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fluster&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clusters&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;currentZoom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toMarker&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you’ll see that handy &lt;code&gt;toMarker()&lt;/code&gt; method coming to action. We’re telling fluster to get the cluster markers within the giving bounding box of &lt;code&gt;[westLng, southLat, eastLng, northLat]&lt;/code&gt; for the current zoom level and converting them to Google Maps Markers. Now we can use that list to show the markers on the map.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Show the Map with Markers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:google_maps_flutter/google_maps_flutter.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;GoogleMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="nl"&gt;initialCameraPosition:&lt;/span&gt; &lt;span class="n"&gt;CameraPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;target:&lt;/span&gt; &lt;span class="n"&gt;LatLng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;41.143029&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.611274&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nl"&gt;zoom:&lt;/span&gt; &lt;span class="n"&gt;currentZoom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="p"&gt;),&lt;/span&gt;
         &lt;span class="nl"&gt;markers:&lt;/span&gt; &lt;span class="n"&gt;googleMarkers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toSet&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
         &lt;span class="nl"&gt;onMapCreated:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// You can init Fluster here&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="nl"&gt;onCameraMove:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Update the markers for the updated position.zoom&lt;/span&gt;
         &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;build(context)&lt;/code&gt; method of your page, you should create your Google Map widget and pass the markers created by fluster and voilà! You will have clusters showing on your map. 👏 👏 👏&lt;br&gt;
&lt;br&gt;&lt;br&gt;
You can use the &lt;code&gt;onMapCreated()&lt;/code&gt; to know when the map is ready to show your markers. Also, make sure to update the markers with the updated zoom level on the &lt;code&gt;onCameraMove()&lt;/code&gt; by calling &lt;code&gt;setState()&lt;/code&gt; or using your favorite state management system, so Fluster knows if it needs to cluster or uncluster some markers.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff3hqrzf2e2otdv38tgek.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff3hqrzf2e2otdv38tgek.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you have all the code needed to implement marker clustering on your GoogleMap widget. Hope you‘ve found this article useful and understood how everything works.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Be sure to check the example project at the &lt;a href="https://github.com/coletiv/flutter_google_maps_clusters" rel="noopener noreferrer"&gt;Coletiv Github account&lt;/a&gt; to see the rest of the code needed to implement clusters on Google Maps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don’t forget to add your Google Maps API key to the project if you want to see it working. Just add it &lt;a href="https://github.com/coletiv/flutter_google_maps_clusters/blob/48a079466dbeeb1673bdcac38ac98cbe76fbd375/android/app/src/main/AndroidManifest.xml#L28" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/coletiv/flutter_google_maps_clusters/blob/48a079466dbeeb1673bdcac38ac98cbe76fbd375/ios/Runner/AppDelegate.swift#L12" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Also, if you want to try some alternatives to handle marker clusters check out &lt;a href="https://pub.dev/packages/flutter_map" rel="noopener noreferrer"&gt;Flutter Map&lt;/a&gt; and &lt;a href="https://pub.dev/packages/flutter_map_marker_cluster" rel="noopener noreferrer"&gt;Flutter Map Marker Cluster&lt;/a&gt; packages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank you for reading! 😊
&lt;/h2&gt;

&lt;p&gt;Thank you so much for reading, it means a lot to us! Also, &lt;strong&gt;don’t forget to follow Coletiv on &lt;a href="https://twitter.com/coletivstudio" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.linkedin.com/company/coletiv/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/strong&gt; as we keep posting more and more interesting articles on multiple technologies.&lt;/p&gt;

&lt;p&gt;In case you don’t know, Coletiv is a software development studio from Porto specialized in Elixir, iOS, and Android app development. But we do all kinds of stuff. We take care of UX/UI design, web development, and even security for you.&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;&lt;a href="https://dev.to/contact"&gt;let’s craft something together?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>tutorial</category>
      <category>googlemaps</category>
      <category>appdev</category>
    </item>
    <item>
      <title>Use Network Images as Marker Icons on Flutter Google Maps</title>
      <dc:creator>António Valente</dc:creator>
      <pubDate>Wed, 08 Jul 2020 16:05:34 +0000</pubDate>
      <link>https://dev.to/coletiv/use-network-images-as-marker-icons-on-flutter-google-maps-fn1</link>
      <guid>https://dev.to/coletiv/use-network-images-as-marker-icons-on-flutter-google-maps-fn1</guid>
      <description>&lt;p&gt;Currently, if you need to use &lt;a href="https://pub.dev/packages/google_maps_flutter"&gt;Google Maps&lt;/a&gt; on your &lt;a href="https://flutter.dev/"&gt;Flutter&lt;/a&gt; app and want to use custom icons for your map markers, you’re limited in terms of options. You can either use an asset or a file as a marker icon and that’s it.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Recently, while working on a project here at &lt;a href="https://coletiv.com/"&gt;Coletiv&lt;/a&gt;, I needed to fetch the images of the markers from a REST API and display them on a Google Maps map.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Since everything is a widget in Flutter, you might think it’s possible to use any widget as a marker icon, and then hook an &lt;a href="https://flutter.dev/docs/cookbook/images/network-image"&gt;Image widget&lt;/a&gt; with the marker and be done with it. But, unfortunately, that’s not possible yet. You can track that feature request in this &lt;a href="https://github.com/flutter/flutter/issues/24213"&gt;Github issue&lt;/a&gt;.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
If you’re willing to let Google Maps go, I recommend that you try the &lt;a href="https://pub.dev/packages/flutter_map"&gt;Flutter Map&lt;/a&gt; package which allows you to use any widget as a marker icon. The problem is that this package only works with Map Tile API’s which are lacking in terms of performance comparing to the native Google Maps library.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Now, let’s check how I’ve implemented this feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  1 - First implementation using &lt;a href="https://pub.dev/packages/http"&gt;HTTP&lt;/a&gt;
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:http/http.dart'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;BitmapDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bodyBytes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Simple enough isn’t it? We have 2 problems with this implementation though. First, you’re performing a network request for every marker every time which can delay the loading. Second, the image is not resized, so we can have markers with different sizes, which is weird.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Let’s solve these problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  2 - Caching the marker images with &lt;a href="https://pub.dev/packages/flutter_cache_manager"&gt;Flutter Cache Manager&lt;/a&gt;
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_cache_manager/flutter_cache_manager.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="n"&gt;markerImageFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;DefaultCacheManager&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getSingleFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;markerImageBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;markerImageFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readAsBytes&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;BitmapDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;markerImageBytes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;DefaultCacheManager&lt;/em&gt; from the &lt;a href="https://pub.dev/packages/flutter_cache_manager"&gt;Flutter Cache Manager&lt;/a&gt; package will handle all the caching logic for you. First, it checks the cache to see if the file was already downloaded or not, and if it was, it will check if the file is old (older than 30 days by default). If the file is recent it will be returned right away but if it needs to be refreshed or doesn’t exist, it will be downloaded and stored in the cache and then returned. You can customize this behavior by implementing the &lt;em&gt;BaseCacheManager&lt;/em&gt; or by doing the caching mechanism yourself.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
With this, you’ll see that the markers load much faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  3 - Resizing the marker images
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:typed_data'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:ui'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter_cache_manager/flutter_cache_manager.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;targetWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="n"&gt;markerImageFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;DefaultCacheManager&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getSingleFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imageUrl&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;markerImageBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;markerImageFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readAsBytes&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Codec&lt;/span&gt; &lt;span class="n"&gt;markerImageCodec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;instantiateImageCodec&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;imageBytes&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;targetWidth:&lt;/span&gt; &lt;span class="n"&gt;targetWidth&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;FrameInfo&lt;/span&gt; &lt;span class="n"&gt;frameInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;imageCodec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNextFrame&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;ByteData&lt;/span&gt; &lt;span class="n"&gt;byteData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;frameInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toByteData&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;format:&lt;/span&gt; &lt;span class="n"&gt;ImageByteFormat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;png&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Uint8List&lt;/span&gt; &lt;span class="n"&gt;resizedMarkerImageBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;byteData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;asUint8List&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;BitmapDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromBytes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resizedMarkerImageBytes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this, you’re resizing the marker image to the &lt;em&gt;targetWidth&lt;/em&gt; and converting it to PNG format which is required by the marker icon &lt;em&gt;BitmapDescriptor.fromBytes&lt;/em&gt; method.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
And that's it! Now you will have a properly resized marker with a network image icon that won’t take forever to load, showing in your Google Map widget. 👏 👏 👏&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is an example project at the &lt;a href="https://github.com/coletiv/flutter_google_maps_clusters"&gt;Coletiv Github account&lt;/a&gt; that uses all this code and also implements Clusters on Google Maps, which is yet another unsupported feature that will be discussed in another article.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Be sure to check it out in the &lt;a href="https://github.com/coletiv/flutter_google_maps_clusters"&gt;flutter google maps clusters&lt;/a&gt; repo, to see all the code with proper syntax highlighting and take a sneak peek at how I've implemented Clusters.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Note: You need to get your &lt;a href="https://cloud.google.com/maps-platform/"&gt;Google Maps API Key&lt;/a&gt; and add it &lt;a href="https://github.com/coletiv/flutter_google_maps_clusters/blob/48a079466dbeeb1673bdcac38ac98cbe76fbd375/android/app/src/main/AndroidManifest.xml#L28"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/coletiv/flutter_google_maps_clusters/blob/48a079466dbeeb1673bdcac38ac98cbe76fbd375/ios/Runner/AppDelegate.swift#L12"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank you for reading! 😊
&lt;/h2&gt;

&lt;p&gt;I hope this guide helps you and your team to save some time with the deployments and remember to &lt;a href="https://twitter.com/fastlanetools"&gt;continuously check Fastlane advancements and updates&lt;/a&gt;. More and more tools will come that may expedite this enduring process of deployment!&lt;/p&gt;

&lt;p&gt;Thank you so much for reading, it means a lot to us! Also, &lt;strong&gt;don’t forget to follow Coletiv on &lt;a href="https://twitter.com/coletivstudio"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.linkedin.com/company/coletiv/"&gt;LinkedIn&lt;/a&gt;&lt;/strong&gt; as we keep posting more and more interesting articles on multiple technologies.&lt;/p&gt;

&lt;p&gt;In case you don’t know, Coletiv is a software development studio from Porto specialized in Elixir, iOS, and Android app development. But we do all kinds of stuff. We take care of UX/UI design, web development, and even security for you.&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;&lt;a href="https://dev.to/contact"&gt;let’s craft something together?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>googlemaps</category>
      <category>tutorial</category>
      <category>example</category>
    </item>
    <item>
      <title>Android GitHub Actions Setup</title>
      <dc:creator>António Valente</dc:creator>
      <pubDate>Wed, 08 Jul 2020 13:02:27 +0000</pubDate>
      <link>https://dev.to/coletiv/android-github-actions-setup-5930</link>
      <guid>https://dev.to/coletiv/android-github-actions-setup-5930</guid>
      <description>&lt;p&gt;Here at &lt;a href="https://coletiv.com/"&gt;Coletiv&lt;/a&gt;, when starting a new project, we always aim to deliver it following the highest standards of quality. Like so, &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration"&gt;continuous integration&lt;/a&gt; (CI) and &lt;a href="https://en.wikipedia.org/wiki/Continuous_deployment"&gt;continuous deployment&lt;/a&gt; (CD) are some of the first things we focus on before starting to code. That way we are sure that our code is always checked, tested, and meets our quality standards before being deployed.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
For Android specifically, we always used services like &lt;a href="https://coletiv.com/blog/android-build-times-travis-ci/"&gt;TravisCI&lt;/a&gt; or &lt;a href="https://circleci.com/"&gt;CircleCI&lt;/a&gt; for this task, but since we are heavy users of &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt; we couldn’t wait to experiment with &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; and check if it would be a better option for our projects. And guess what? It’s amazing!&lt;br&gt;
&lt;br&gt;&lt;br&gt;
Here is how we set up GitHub Actions on our Android projects.&lt;/p&gt;
&lt;h2&gt;
  
  
  Workflow Overview
&lt;/h2&gt;

&lt;p&gt;We always have two types of &lt;a href="https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions"&gt;workflows&lt;/a&gt;, one for testing and code checking and one for deploying. The first always runs on pull requests and the last only runs when the code is merged to master or develop.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that we usually create multiple &lt;a href="https://developer.android.com/studio/build/build-variants"&gt;build variants&lt;/a&gt; for different environments. In this example, we’re running the commands for the staging build variant. You should change all the commands to your correct variant name or remove the staging word from them if you don’t need to use variants.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Testing Workflow
&lt;/h3&gt;

&lt;p&gt;The purpose of this workflow is to run some &lt;a href="https://en.wikipedia.org/wiki/Lint_(software)"&gt;lint checks&lt;/a&gt; and to run our tests. Here is the list of jobs that it performs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Decode our Google services config file (if you’re not using Google services or Firebase you can remove this job).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run Kotlin lint check.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run Android lint check.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run unit tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run instrumented tests.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Testing Workflow&lt;/span&gt;

&lt;span class="c1"&gt;# Step 1: Choose the branch or branches you want to run this workflow&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;testing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Lint Check and Testing&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone Repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up JDK &lt;/span&gt;&lt;span class="m"&gt;1.8&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.8&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 2: Decode Google services configuration file&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Decode google-services.json&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;FIREBASE_CONFIG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.FIREBASE_CONFIG }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo $FIREBASE_CONFIG &amp;gt; app/google-services.json&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 3: Check the code with ktlint, you can remove this job if you don't use ktlint&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Kotlin Linter&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew ktlintStagingDebugCheck&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 3: Check the code with Android linter&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Android Linter&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew lintStagingDebug&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 4: Yun your unit tests&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Unit Tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew testStagingDebugUnitTest&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 4: Assemble debug apk to send to firebase test lab&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Assemble Debug APK&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew assembleStagingDebug&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 4: Assemble debug test apk to send to firebase test lab&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Assemble Debug Test APK&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew assembleStagingDebugAndroidTest&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 4: Run instrumented tests on firebase test lab&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests on Firebase Test Lab&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;asadmansr/Firebase-Test-Lab-Action@v1.0&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;arg-spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.github/test-lab-config-staging.yml:android-pixel-4'&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;SERVICE_ACCOUNT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SERVICE_ACCOUNT }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let’s go step by step to explain everything.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Tell GitHub when do you want to run this workflow. In this case, I’m saying that I want it to run on pull requests to the develop branch. You can tell it to run on any branch you like, just replace/add the name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Skipping a bit further, since we’re using the Google services, you need to go to the settings to add a new &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets"&gt;secret&lt;/a&gt;. Just create a new secret paste the content of your Google services JSON file there and choose a name. Our name for this secret is FIREBASE_CONFIG.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We want to perform some checks to the code. For this, we’re using Ktlint and the built-in &lt;a href="https://developer.android.com/studio/write/lint"&gt;Android linter&lt;/a&gt;. To configure Ktlint check &lt;a href="https://github.com/pinterest/ktlint"&gt;this&lt;/a&gt; and &lt;a href="https://github.com/JLLeitschuh/ktlint-gradle"&gt;this&lt;/a&gt;. If you don’t need to run Kotlin checks delete the Kotlin linter job.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, we are creating jobs to run our tests. Running unit tests is pretty straightforward but running instrumented tests is really a pain because you need an emulator or real device to run them. You can go two ways here. Create a job to create and start an emulator on the CI machine (check &lt;a href="https://github.com/marketplace/actions/android-emulator"&gt;this&lt;/a&gt;) or run them on &lt;a href="https://firebase.google.com/docs/test-lab/android/overview"&gt;Firebase Test Lab&lt;/a&gt;. We’ve chosen the last one and we’re using the awesome &lt;a href="https://github.com/marketplace/actions/firebase-test-lab-action"&gt;Firebase Test Lab Action&lt;/a&gt;. For more info on how to do this follow the &lt;a href="https://github.com/asadmansr/Firebase-Test-Lab-Action/blob/master/docs/SIMPLE_USAGE.md"&gt;guide&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;android-pixel-4&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;instrumentation&lt;/span&gt;
  &lt;span class="c1"&gt;# Specify the path to the debug and test apks generated early&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app/build/outputs/apk/staging/debug/app-staging-debug.apk&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app/build/outputs/apk/androidTest/staging/debug/app-staging-debug-androidTest.apk&lt;/span&gt;
  &lt;span class="na"&gt;device&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flame&lt;/span&gt;
      &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;29&lt;/span&gt;
      &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;en'&lt;/span&gt;
      &lt;span class="na"&gt;orientation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;portrait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Deploy Workflow
&lt;/h3&gt;

&lt;p&gt;Assuming that you have the develop and master &lt;a href="https://help.github.com/en/github/administering-a-repository/configuring-protected-branches"&gt;branches protected&lt;/a&gt; and that you ran the testing workflow before doing a merge to these main branches, this workflow is very simple. It only needs to publish our app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Workflow&lt;/span&gt;

&lt;span class="c1"&gt;# Step 1: Choose the branch or branches you want to run this workflow&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;develop&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone Repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up JDK &lt;/span&gt;&lt;span class="m"&gt;1.8&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.8&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 2: Decode Google services configuration file&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Decode google-services.json&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;FIREBASE_CONFIG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.FIREBASE_CONFIG }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo $FIREBASE_CONFIG &amp;gt; app/google-services.json&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 3: Decode the service account json key, needed on the next job&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Decode service account key&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;SERVICE_ACCOUNT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SERVICE_ACCOUNT }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo $SERVICE_ACCOUNT &amp;gt; app/service-account-key.json&lt;/span&gt;

      &lt;span class="c1"&gt;# Step 4: Publish the APK to the Play Store using the release keystore&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish APK&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;RELEASE_KEYSTORE_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrests.RELEASE_KEYSTORE_PASSWORD }}&lt;/span&gt;
          &lt;span class="na"&gt;RELEASE_KEY_ALIAS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrests.RELEASE_KEY_ALIAS }}&lt;/span&gt;
          &lt;span class="na"&gt;RELEASE_KEY_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrests.RELEASE_KEY_PASSWORD }}&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew publishStagingRelease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let’s again go step by step to explain everything.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Tell GitHub when to run this workflow. I’m saying that I want it to run on pushes to the develop branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Like on the testing workflow we need the Google services JSON file so we’re decoding it before running any Gradle task.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We also need to create a Google service account to be able to have publish access in the next job. Check &lt;a href="https://github.com/Triple-T/gradle-play-publisher#service-account"&gt;this&lt;/a&gt; for more info. After creating the account you can download the JSON key and add it to the secrets like you’ve done before with the Google services JSON.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lastly, we are publishing the app using the &lt;a href="https://github.com/Triple-T/gradle-play-publisher"&gt;Gradle Play Publisher&lt;/a&gt; plugin. You’ll need to add some configurations into your Android project to have this task available. For that please follow the instructions &lt;a href="https://github.com/Triple-T/gradle-play-publisher#table-of-contents"&gt;here&lt;/a&gt;. You also must add the release Keystore passwords and alias to the GitHub secrets as those are needed on this job and are sensitive data. Note that we usually have the &lt;a href="https://stackoverflow.com/a/56116822/6937784"&gt;Keystore file on our private repos&lt;/a&gt;, if you don’t want to have it there or you’re working on a public repo, you can also add it to your secrets and then decode it when running the workflow.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I really recommend that you give GitHub Actions a try in your next Android project. It’s easy to create and manage workflows as the syntax is very simple and understandable, the integration with other GitHub services is nice and having your CI builds in the same place of your repository is really a plus. Also, the community is amazing and the number of actions in the &lt;a href="https://github.com/marketplace?type=actions"&gt;GitHub marketplace&lt;/a&gt; grows by the day.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank you for reading!
&lt;/h2&gt;

&lt;p&gt;Thank you so much for reading, it means a lot to us! Also &lt;strong&gt;don’t forget to follow &lt;a href="https://dev.to/"&gt;Coletiv&lt;/a&gt; on &lt;a href="https://twitter.com/coletivstudio"&gt;Twitter&lt;/a&gt; and &lt;a href="https://www.linkedin.com/company/coletiv/"&gt;LinkedIn&lt;/a&gt;&lt;/strong&gt; as we keep posting more and more interesting articles on multiple technologies.&lt;/p&gt;

&lt;p&gt;In case you don’t know, Coletiv is a software development studio from Porto specialised in Elixir, Web, and App (iOS &amp;amp; Android) development. But we do all kinds of stuff. We take care of UX/UI design, software development, and even security for you.&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;&lt;a href="https://coletiv.com/contact"&gt;let’s craft something together?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>github</category>
      <category>githubactions</category>
      <category>cicd</category>
    </item>
  </channel>
</rss>
