Tutorials / How to Make an Android App with a HERE Map
Last Updated: August 11, 2020

Introduction

The HERE SDK for Android allows you to add HERE Location Services to your Android applications. You can add services such as routing, interactive maps, global places search and more to your applications.

What You’ll Learn

After completing this tutorial, you will have learned how to render a map in an Android application using the HERE Android SDK.

What You’ll Need

  • Android Studio installed. In case if you don’t have Android Studio, here is Google’s guide on how to install it.
  • HERE developer account
  • HERE Android SDK (More on how to download that below) 

What You are Going to Build

In this tutorial, you will learn how to setup your application to receive GPS updates and you will learn how to add the HERE SDK for Android to your application. Next you will learn how to add a HERE map into your Android application using HERE SDK for Android and finally locate the position of your device, place a marker on a map and zoom into your current location.

Final output

Here is a screenshot showing the Android application and HERE Map, centered over Hyderabad.

final-android-map

HERE SDK for Android Features

The main features offered by the HERE SDK for Android are:

  • Mapping (Displaying a Map to an End User)
  • Search (Finding Locations for an End User)
  • Directions (Obtaining and Displaying)
  • Turn-by-turn Navigation (Presenting Instructions for Navigating an End User)
  • HERE Positioning (Locating an End User)

You can find more information about all the HERE Android SDK features from this link

For this tutorial we will focus on Mapping.

Acquiring HERE credentials and Downloading the HERE SDK

To acquire the HERE credentials, follow the graphical illustration:

final-android-map

  • Login to here-tech.skawa.fun
  • Select one of your projects
  • Scroll to the HERE SDK for Android section
  • Then, click on Generate App ID and App Code button to generate the credentials needed to access the Android SDK
  • Finally, download the HERE SDK by click on the download link.

Create an Android Project using Android Studio

Let’s get started by creating the Android project. To do that open up Android Studio and click on the Start a new Android Studio project.

final-android-map

In the next screen, choose the Empty Activity.

final-android-map

Now, configure your project as shown below:

final-android-map

Finally, click on the Finish button.

You will be redirected to the new project that was created.

final-android-map

Importing HERE Android SDK into your project

Next, we are going to include the HERE SDK into your Android project. To do this you need to locate the downloaded HERE-sdk.zip file and extract it. Now, copy the HERE-sdk.aar file. Go back to Android Studio, click on the Project view as shown below:

final-android-map

In the project view, navigate to the libs folder and paste the copied HERE-sdk.aar file.

final-android-map

final-android-map

Now that you have added the HERE-sdk.aar files lets tell the project about the HERE SDK by modifying the build.gradle file in the app folder as shown below:

In build.gradle add the following line into the Android { … } section:

    repositories {
        flatDir {
            dirs 'libs'
        }
    }

Next, add the following into the dependencies { … } section:

  implementation 'com.google.androidgms:play-services-location:17.0.0'
  implementation(name:'HERE-sdk', ext:'aar')

final-android-map

Now click on the Sync Now on the top right corner as shown to Sync with Gradle files:

sync-project

Add Required Permissions in the “AndriodManifest.xml”

Up to this point we have added the HERE SDK, but your application will not receive any location information because we have not configured the application to receive location updates.

Before you add the permissions, open the AndroidManifest.xml and add the attribute android:hardwareAccelerated="true" to render the Map smootly as shown below:

<application android:icon="@drawable/icon"
android:label="@string/app_name" android:hardwareAccelerated="true">

The HERE SDK is an online SDK, which means it requires internet connectivity. To give the app internet connectivity you need to add the following permissions to the AndroidManifest.xml file.

  • Write access to external storage
  • Network state
  • Internet Access
  • WIFI state

To add the above permissions to your Android App, copy and paste the following code in the: AndroidManifest.xml before <application> tag:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

Add Your HERE Credentials to Authenticate the App

Now that you have configured the application, we need to configure your HERE API Access credentials so that the HERE SDK can communicate with the HERE Service.

In the AndroidManifest.xml Within the <application></application> block of tags, add the following mark-up directly beneath the <activity></activity> tag:

<meta-data android:name="com.here.android.maps.appid"
android:value="{YOUR_APP_ID}"/>
<meta-data android:name="com.here.android.maps.apptoken"
android:value="{YOUR_APP_CODE}"/>
<meta-data android:name="com.here.android.maps.license.key"
android:value="{YOUR_LICENSE_KEY}"/>

Note: Make sure to replace the HERE Credentials with your own

Within the same <application></application> section in your AndroidManifest.xml file, add the following lines:

<service
  android:name="com.here.android.mpa.service.MapService"
  android:label="HereMapService">
  <intent-filter>
    <!--Note, action name should not be changed.-->
    <action android:name="com.here.android.mpa.service.MapService.v3" />
  </intent-filter>
</service>

Click here to see the final version AndroidManifest.xml

app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.richcontent.heremapapp">

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <application
        android:label="@string/app_name" 
        android:hardwareAccelerated="true"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="com.here.android.maps.appid"
            android:value="{appid}" />
        <meta-data
            android:name="com.here.android.maps.apptoken"
            android:value="{apptoken}" />
        <meta-data
            android:name="com.here.android.maps.license.key"
            android:value="{license.key}" />

        <service
            android:name="com.here.android.mpa.service.MapService"
            android:label="HereMapService">
            <intent-filter>
                <!--Note, action name should not be changed.-->
                <action android:name="com.here.android.mpa.service.MapService.v3" />
            </intent-filter>
        </service>

    </application>

</manifest>

Create a Map Fragment to Display the Map

To display the map, we need a map Fragment. To setup a map fragment, open the exiting layout/activity_main.xml file and start editing it.

  1. Change the layout to the LinearLayout as shown below:
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >

  <TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World"
    tools:context=".MainActivity" />

</LinearLayout>
  1. Add the following mark-up beneath the <TextView/> tag:
<fragment
  class="com.here.android.mpa.mapping.AndroidXMapFragment"
  android:id="@+id/mapfragment"
  android:layout_width="match_parent"
  android:layout_height="match_parent"/>
  1. Remove the text view for the Map only View
 <TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World"
    tools:context=".MainActivity" />

When AndroidXMapFragment is initialized, your application’s MainActivity contains an AndroidXMapFragment UI element (with the mapfragment ID) that owns a Map object.

Implement the HERE Map

Now let’s work on implementing the map. First up you will need to import the HERE Libraries.

To do this, open the MainActiviy.java file and add the following import statements:


import android.app.Activity;
import android.os.Bundle;

import com.here.android.mpa.common.GeoCoordinate;
import com.here.android.mpa.common.OnEngineInitListener;
import com.here.android.mpa.mapping.Map;
import com.here.android.mpa.mapping.AndroidXMapFragment;
import androidx.fragment.app.FragmentActivity;

Now, implement the MainActivity class by extending it with the FragmentActivity.

public class MainActivity extends FragmentActivity {

...

}

With in the MainActivity class, create a reference map object as shown below:

  // map embedded in the map fragment
  private Map map = null;
  // we will use this var
  private static final int REQUEST_CODE_LOCATION_PERMISSION = 1;

Now, create the fragment object as shown below:

// map fragment embedded in this activity
  private AndroidXMapFragment mapFragment = null;

In the onCreate method call the initialize method like below:

note: We will implement the initialize() in the next section


 @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initialize();
  }

Implement the initialize() Method

The following function will render the map in the map fragment. This code will initialize and configure the map into the map UI fragment from above. The initialization code will initialize the map, set the centered position of the map over Vancouver and then zoom to a calculated level.

  private void initialize() {

    // Search for the map fragment to finish setup by calling init().
    mapFragment = (AndroidXMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapfragment);

    // Set up disk cache path for the map service for this application
    // It is recommended to use a path under your application folder for storing the disk cache
    boolean success = com.here.android.mpa.common.MapSettings.setIsolatedDiskCacheRootPath(
      getApplicationContext().getExternalFilesDir(null) + File.separator + ".here-maps");

    if (!success) {
      Toast.makeText(getApplicationContext(), "Unable to set isolated disk cache path.", Toast.LENGTH_LONG);
    } else {
      mapFragment.init(new OnEngineInitListener() {
        @Override
        public void onEngineInitializationCompleted(OnEngineInitListener.Error error) {
          if (error == OnEngineInitListener.Error.NONE) {
            // retrieve a reference of the map from the map fragment
            map = mapFragment.getMap();
            // Set the map center to the Vancouver region (no animation)
            map.setCenter(new GeoCoordinate(49.196261, -123.004773, 0.0),
                Map.Animation.NONE);
            // Set the zoom level to the average between min and max
            map.setZoomLevel((map.getMaxZoomLevel() + map.getMinZoomLevel()) / 2);
            requestPermissions();
          } else {
            System.out.println("ERROR: Cannot initialize Map Fragment");
          }
        }
      });
    }
  }

Finally, put together, your MainActivity.java file should look as below:

package com.richcontent.heremapapp;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import com.here.android.mpa.common.GeoCoordinate;
import com.here.android.mpa.common.OnEngineInitListener;
import com.here.android.mpa.mapping.Map;
import com.here.android.mpa.mapping.AndroidXMapFragment;
import androidx.fragment.app.FragmentActivity;

import java.io.File;

public class MainActivity extends FragmentActivity {

private static final int REQUEST_CODE_LOCATION_PERMISSION = 1;

    // map embedded in the map fragment
    private Map map = null;

    // map fragment embedded in this activity
    private AndroidXMapFragment mapFragment = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initialize();
    }

    private void initialize() {
        // Search for the map fragment to finish setup by calling init().
        mapFragment = (AndroidXMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapfragment);

        // Set up disk cache path for the map service for this application
        // It is recommended to use a path under your application folder for storing the disk cache
        boolean success = com.here.android.mpa.common.MapSettings.setIsolatedDiskCacheRootPath(
                getApplicationContext().getExternalFilesDir(null) + File.separator + ".here-maps");

        if (!success) {
            Toast.makeText(getApplicationContext(), "Unable to set isolated disk cache path.", Toast.LENGTH_LONG);
        } else {
            mapFragment.init(new OnEngineInitListener() {
                @Override
                public void onEngineInitializationCompleted(OnEngineInitListener.Error error) {
                    if (error == OnEngineInitListener.Error.NONE) {
                        // retrieve a reference of the map from the map fragment
                        map = mapFragment.getMap();
                        // Set the map center to the Vancouver region (no animation)
                        map.setCenter(new GeoCoordinate(40.730610, -73.935242, 0.0),
                                Map.Animation.NONE);
                        // Set the zoom level to the average between min and max
                        map.setZoomLevel((map.getMaxZoomLevel() + map.getMinZoomLevel()) / 2);
                    requestPermissions();
                    } else {
                        System.out.println("ERROR: Cannot initialize Map Fragment");
                    }
                }
            });
        }
    }
}

Once you run the project, you should see a HERE Map on the device as shown:

final-android-map

Display Current User Location on the Map

To get the current user location, you need to add the location access permissions. Open the app/src/main/AndroidManifest.xml file and add the following location permission before the tag:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

You need to add the below import statements in the MainActivity.java file to access the current user location:

import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import androidx.core.content.ContextCompat;
import android.Manifest;
import androidx.core.app.ActivityCompat;
import androidx.annotation.NonNull;
import android.content.pm.PackageManager;
import com.here.android.mpa.mapping.MapMarker;
import android.os.Looper;

Request Location Permission

Before you access the current user location, you need to request for the permission.

To request for the permission, you need to add the following lines of code to MainActivity.java after the initialize() method:

  // Request user for location access
    private void requestPermissions(){
        if(ContextCompat.checkSelfPermission(
                getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(
                    MainActivity.this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    REQUEST_CODE_LOCATION_PERMISSION
            );
        }else{
          // Get current user location
            getCurrentUserLocation();
        }
    }
// Call back function for location access 
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
       // check for user action
        if(requestCode == REQUEST_CODE_LOCATION_PERMISSION && grantResults.length > 0){
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                 // Get current user location
                getCurrentUserLocation();
            }else{
                Toast.makeText(this, "Permission denied",Toast.LENGTH_SHORT).show();
            }
        }
    }

final-android-map

Now, you got the user permission to access the location.

Get Current User Location and add a Marker

To access current user location, you need to use the LocationServices to get the latitude and longitude. Once you have the GPS coordinates, create a marker using it. Add the below code to MainActivity.java file after the onRequestPermissionsResult method:

   private void getCurrentUserLocation() {
        final LocationRequest locationRequest = new LocationRequest();
        locationRequest.setInterval(10000);
        locationRequest.setFastestInterval(3000);
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        LocationServices.getFusedLocationProviderClient(MainActivity.this)
                .requestLocationUpdates(locationRequest, new LocationCallback(){
                    @Override
                    public void onLocationResult(LocationResult locationResult) {
                        super.onLocationResult(locationResult);
                        LocationServices.getFusedLocationProviderClient(MainActivity.this)
                                .removeLocationUpdates(this);
                        if(locationRequest != null && locationResult.getLocations().size() > 0){
                            int latestLocationIndex = locationResult.getLocations().size() - 1;
                            double lat = locationResult.getLocations().get(latestLocationIndex).getLatitude();
                            double lng = locationResult.getLocations().get(latestLocationIndex).getLongitude();
                            //create a marker
                            MapMarker marker = new MapMarker();
                            marker.setCoordinate(new GeoCoordinate(lat,lng));
                            // Add created marker to the map
                            map.addMapObject(marker);
                            map.setCenter(new GeoCoordinate(lat,lng), Map.Animation.NONE);
                            double level = map.getMinZoomLevel() + map.getMaxZoomLevel() / 2;
                            map.setZoomLevel(level);
                        }
                    }

                }, Looper.getMainLooper());
    }

Run the project

To run the app on a real device or an emulator follow the article How to run Android App on real device or emulator

Once you connect your device to the android studio click on the run button as shown:

run_project

Conclusion

By following the above tutorial you’ve learn how to: - Download and Import the HERE-SDK - Implement the HERE Map using HERE SDK for Android - Get the Current User Location and add a Marker

Next Steps

Check out the following: