Google Maps for Android Pt 1: Intro & Setup

I’ve always been fascinated by maps. They’re amazing at stoking the imagination about far away places, planning adventures to new areas, and displaying data in a contextual and useful way. Millions of users look up directions, plan their commutes, catch a ride, or find new places using map based apps on their phones every day. Given how useful maps can be, I’ve decided to put together a series of articles covering how to use the Google Maps SDK for Android, as well as touch on the many great things available through maps to enhance the user experience in your mobile apps.

Creating a Starter App

To make things easy, we’ll start by creating a new Android project via Android Studio and selecting the Google Maps Activity template for the first Activity.

Once your project is created, you will need to enable the Maps SDK for Android, as well as generate an API key to access the service. This will require the SHA1 hash of your application’s signing key. You can obtain this by running a command on the keystore file that you are using to sign your app. On a Mac, running the following command in a terminal will generate the SHA1 for your debug signing key:

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

Now that you have the SHA1 for your signing key, you will need to go to the Google Developer Console to enable the Maps SDK, as well as get the API key. Once you’ve gotten to the console page, you will need to create a new project.

After your project is created, click on the search bar and find the API for Maps SDK for Android.

After selecting the item from the search menu, you will be taken to a screen where you can enable the Maps SDK.

With the Maps SDK enabled, select the credentials tab on the left of the screen. You will then want to select Create credentials button and the API key option.

This will generate an API key for you.

Be sure to keep your key secret and safe. I’ve already deleted this one :)

Copy the key and return to your Android Studio project (though don’t close the console webpage, as we will be returning to it in a moment). The template project will have created a file named google_maps_api.xml under the res/values directory. Open it and paste your new API key within the following item where it says YOUR_KEY_HERE.

<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">YOUR_KEY_HERE</string>

Return to the Google API console and click on the RESTRICT KEY button on the popup containing your API key. On the next page that comes up, select Android apps under the Application restrictions header, click the Add Package name and fingerprint button, and then add your app’s package name and the SHA-1 that you generated earlier.

This will prevent any applications other than yours from using this API key to access Google services. Additionally, you can select the API restrictions tab on this page to restrict even your own apps from accessing any APIs that have not been whitelisted. Now that you’re done restricting the use of your API key, you can go back to Android Studio.

At the time of this writing, there is a bug where maps will crash if you try to run this template application. You can fix this by opening the AndroidManifest.xml file and adding the following line within your application node

<uses-library android:name="org.apache.http.legacy" android:required="false"/>

With everything set up, you can install your application on a physical Android phone or an emulator. You should see Google Maps load up and center on Australia with a marker on the city of Sydney. If you click on the marker, a small popup will come up over it that says “Marker in Sydney”. You may also notice a couple of icons in the lower right corner that will take you to the standard Google Maps application.

Convert the Template to AndroidX

One thing that bothers me with the current template is that it’s still using the old support libraries. While it wouldn’t drastically change the functionality of Google Maps or the application, it’s still a good practice to use the recommended tools and classes, as this is what you would need to use in your own applications. Let’s go ahead and switch the app to AndroidX now that we’re up and running. Open your app module’s build.gradle file and remove the following two lines from the dependencies node.

implementation 'com.android.support:appcompat-v7:28.0.0'
androidTestImplementation 'com.android.support.test:runner:1.0.2'

and then replace them with their AndroidX equivalents

implementation 'androidx.appcompat:appcompat:1.0.2'
androidTestImplementation 'androidx.test:runner:1.1.1'

Next, open your gradle.properties file and enable AndroidX by adding the useAndroidX and enableJetifier properties as true.

android.useAndroidX=true
android.enableJetifier=true

After resyncing your application, go into the MapsActivity.kt file and remove the following, now obsolete, import line

import android.support.v7.app.AppCompatActivity

and replace it with the new import

import androidx.appcompat.app.AppCompatActivity

Now that we’ve done a quick migration to AndroidX, you should be able to run your app again and everything should function just like it did before.

How It Works

Now that you have the demo working, let’s dig into the code and go over out how the template is put together. Start by opening your app module’s build.gradle file. You should see that the base maps package from Google Play Services is being brought in to your application, though you will add more packages here in later articles to add functionality to your Google Maps applications.

implementation 'com.google.android.gms:play-services-maps:16.0.0'

If you return to the AndroidManifest.xml file, you’ll also see a meta-data tag added to the app that tells Google Play Services where to find your API key, which was placed earlier in this tutorial.

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />

Next, open the activities_maps.xml file. This file contains a single item: a fragment that supports Google Maps. While the main element is a fragment, you’ll notice that the android:name property is set to the full class name for a SupportMapFragment.

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapsActivity" />

The map will take up the entire viewable fragment area for this demo, however in your own projects, since this is a fragment, you can adjust it to fill only a portion of the screen to fit your needs.

Finally, you will want to return to the MapActivity.kt file to see how our application interacts with the Google Maps service.

The first thing you may notice is that the Activity is implementing the OnMapReadyCallback interface. We’ll come back to this and the required method. As with most apps, the work starts in onCreate(). In order to use Google Maps, you will first need to obtain a reference to your SupportMapFragment in your layout file,

val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment

and then retrieve the map data asynchronously from Google.

mapFragment.getMapAsync(this)

The template application does this by calling getMapAsync() on the SupportMapFragment object and passing in an OnMapReadyCallback that was implemented by the Activity using the keyword this. Once the map data has loaded, the onMapReady() method will receive the GoogleMap object, which is then saved in a class level as an instance variable.

override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap

To wrap up the template app, the view area (also known as the camera) is focused on the city of Sydney, New South Wales, Australia, and a marker is added over the city. We’ll go into how this works and what more can be done in later articles.

val sydney = LatLng(-34.0, 151.0)
mMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))

Wrapping Up

In this article you’ve learned the basics of implementing maps in an application. As you can see from the template app, basic map functionality is relatively easy to add, though there’s also a whole lot more that can be done to make them useful and interesting. As this series of articles continues, you will learn about customizing markers, changing map styles, drawing on the map, building layers, street view, nearby places and a variety of other interesting functionality to make your map based applications awesome.