Mapbox + Flutter Bloc + Location Package

Ana Polo
Flutter Community
Published in
9 min readApr 6, 2022

--

Hi everyone 👋

This time I would like to talk about Mapbox.

Mapbox is a great service to use maps, is fantastic because you can edit the maps as you want to show them based on your requirements. You could switch between different kinds of layers to show the maps, like outdoors, streets, monochromatic, and so on. For more info, this is the official website: https://www.mapbox.com/

In this example, we are going to use:

  • Mapbox
  • Location package
  • Flutter dot env package
  • Flutter bloc.
  • Very Good CLI to create a new package called location_repository.

Create an account and create a secret access token

1- Go to https://account.mapbox.com/ and create an account

2- Go to https://account.mapbox.com/access-tokens/ and click on the “create a token” button.

3- It’s important to create the secret token with the property download:read.

Then you are going to see your public secret access tokens

Native configurations

Android

1- Go to gradle.properties file and set the secret access token: MAPBOX_DOWNLOADS_TOKEN=YOUR_SECRET_MAPBOX_ACCESS_TOKEN

2- Create a new strings.xml file to set your secret key, to do that, you have to go to android/app/main/res/values and create a new file called strings.xml and set up the information.

3- Configure the permissions on the AndroidManifest.xml file.

4- Change the minSdkVersion to 21 into the module-level build.gradle file.

iOS

1- The first step that you need to do is create a .netrc file in your HOME Mac directory, follow these steps to create:

Open a Terminal

cd ~ (this is to go to the home directory)

touch .netrc (this is to create a file)

open .netrc (open .netrc file)

When the file is open you need to copy/paste this and set your secret password:

Save the data and close the file.

The .netrc file is a plain text file that is used in certain development environments to store credentials used to access remote servers.

2- Configure the public access token:

  • Open the directory Runner.xcworkspace in XCode. Select on the left side the root of the project “Runner”, then on targets select “Runner” and finally you have to select the Info tab. On Custom iOS Targets Properties you need to add a new one called MBXAccessToken with your public token.

If you close XCode and go to your flutter project on the ios/runner/info.plist file you could see a new line like this:

Additionally, you need to add a message to inform the user that the location is mandatory, so you can add a new line into Info.plist like this:

3- Change the platform versión into the Podfile file.

4- Execute the next commands to clean, update and install the new pods:

cd /ios

rm -rf Pods/ Podfile.lock Flutter/Flutter.podspec

pod deintegrate

pod repo update

pod install

Try to execute the app. Are you facing this error?

You should add these lines to the Podfile to fix it.

Okay, at this point the native configurations are done. The next step is to get the device location to set our location on the map.

.ENV File

In this project, I’m going to use the flutter_dotenv package to hide my access token. It’s simple to use, you need to create an assets folder in your root application and then create a .env file.

Inside this folder you are going to put your public Mapbox access token like this:

MAPBOX_ACCESS_TOKEN = 'YOUR PUBLIC ACCESS TOKEN'

Then, to load the file and be able to use it in our application, we need to add this line to our main method.

await dotenv.load(fileName: "assets/.env");

If you need to get the value of our MAPBOX_ACCESS_TOKEN, you need to do it in this way:

dotenv.get('MAPBOX_ACCESS_TOKEN')

To hide this .env file in our Github project we need to add a new line to our .gitnore file:

/assets/.env

Location

In this tutorial we are going to do something different, we are going to create our own package to host all the content related to “location”. This is a good way to have all more structure and clean, and also if you want to use this package in another app you could do it because is independent of the rest of the code.

To create it we are going to use Very Good CLI.

For more info, check this link: https://verygood.ventures/blog/flutter-starter-app-very-good-core-cli.

Location Repository Package

1- Create a packages folder on your root project and open a new terminal on the new folder and put this:

dart pub global activate very_good_cli

very_good create location_repository -t dart_pkg

If you check your packages folder you could notice that there is a new package called “location_repository”.

To use the location we need to add the location package to our location_repository/pubspec.yaml file and run flutter pub get.

Now we can use the location package. To get the user device location we need to check two important things before getting the location:

  • Check if the service is enabled.
  • Check if the user has the necessary permissions (these permissions are the ones we added above).

I’ve created a “custom” exception called CurrentLocationFailure to control the different errors messages that we can throw to give to the user more information.

This is the full method.

Also, I created an object called CurrentUserLocation to set the latitude and longitude of the user when the getCurrentLocation method returns the LocationData.

This is the location_repository class:

Features

Now it’s time to go to our lib folder and create the structure to use the location and maps.

We are going to have two folders:

  • Location: here we are going to create a bloc to handle all the logic related to getting the user location.
  • Map: here we are going to handle all the logic related to the maps.

To show a map the first thing that we need to do is to get the user location, to do that we are going to use our package location_repository, so we need to add the dependency to our pubspec.yaml file.

Okay, we have the dependency added and now we can use it to get the user location.

Location

In this feature, we need to create a bloc to use the location repository package and be able to get the user service, permissions, and location. As always we need three classes.

  • Location state class.
  • Location event class.
  • Location bloc class: In this class, we are going to have an instance of our location repository class.

Now we can use this bloc on our Map feature.

Map

Here we are going to have two classes:

  • Map page class: here we are going to initialize our location repository and also the location bloc.
  • Map layout class: here we are going to listen to the different states of our location bloc to show the correct widget.

As you can see, in this class we are going to build the view only if the state of the bloc isLoading, isError, or isSuccess.

  • isLoading: shows a CircularProgressIndicator.
  • isError: shows an error widget. This widget displays an error message with an icon.
  • isSuccess: with this widget, we can show the map and the location of the user.

This is the simulator.

Customize map

As I mentioned at the beginning of the article, Mapbox allows you to modify the maps to do them more uniques, so in this article, I’m going to show you how to do it a little bit.

1- Go to Mapbox studio: https://studio.mapbox.com/

2- Click on the new style button.

3- Choose a style and go inside the editor.

Mapbox Editor

This is the main page of the editor.

In the editor, you could change a lot of things like colors, fonts, icons, and much more. For a quick example, I’m going to change a little bit the colors of the roads and the water on the map.

Then click on publish to publish the changes, as you can see this is the before and after of the map.

Going back to the styles. Now, we have my new style, to use it we need to click on the “share” icon on the right.

In the popup menu, I need to copy the “style url”.

Use customize map

To use the customized map, in our code we need to set up the style for our map, to do that, set the styleString property on the MapSuccessWidget:

Be patient, the map could take around 10 minutes to upload, so if you don’t see the changes immediately, don’t worry! try again later.

Animate camera to a new location

To control this, we need to use our mapController. This controller should be created at the beginning of the class and initialized on the _onMapCreated method.

MapboxMapController? mapController;

_onMapCreated(MapboxMapController controller) async {
mapController = controller;
}

We are going to update the camera position when the user clicks on the map, to do that we need to add to our MapboxMap widget the function onMapClick and implement the following code.

ZoomIn & ZoomOut

Once time again we need to use the mapController to do zoom in and zoom out. I’ve created two FAB buttons to control it.

This is the ZoomInOutWidget:

This is the final result of the MapWidgetSuccess after adding these functionalities:

Testing

In this article, I’m not going to talk about testing but I would like to share with you that there are unit and bloc tests in the location package and also in the main project. In the future I’m going to add the widget test, if you want to collaborate with this part it would be awesome.

Collaboration

Mapbox has countless features to implement, in the future I’m going to add a few more for learning purposes. If you want to participate, please, open a new PR to add more functionality to this app.

Things that I would like to add:

  • Change styles.
  • Custom markers.
  • Update the current location.
  • Search by city or country.
  • Animations.

Additional resource

If you are interested in customizing more your map and also adding some cool animations I highly recommend you this tutorial by Diego Velasquez.

You can find the code here: https://github.com/AnnaPS/maps_flutter

If this content is useful for you, I really appreciate your claps 👏 💙

You can follow me on Twitter: @AnaPolo_dev

https://twitter.com/FlutterComm

--

--

Ana Polo
Flutter Community

Software Engineer at Very Good Ventures. 🦄 Co-Organizer of @FlutterMadrid & @flutter_es communities. The organizer of @es_flutteristas. Github: AnnaPS 💙