Hands on

Getting Started with HERE Maps in an Android Application

By Nic Raboy | 03 December 2018

There are plenty of use-cases as to why you’d want to include maps and location services in your Android application. Maybe you want to build the next great ride sharing application or maybe you need to track dolphins in the ocean in real-time. Including maps in your Android applications has never been easier with the HERE Android SDK and Java.

We’re going to see how to get started with HERE by including a simple, but interactive map in an Android application using Java and Android Studio.

To get an idea of what we hope to accomplish, take a look at the following image:

here-android-sdk

As you can see, there is a map within a fragment on the screen. What isn’t obvious is that pan and zoom works on the map, making it interactive.

Creating a New Android Project with Android Studio

There are many ways to create Android applications, but we’re going to focus on the most popular which is with Android Studio. Assuming that you have Android Studio installed and the appropriate Android Developer Toolkit (ADT) available, we can create a new project.

Choose to create a new project in Android Studio. The first step is rather important for using the HERE Android SDK.

android-studio-new-project-1

Each application that uses the HERE Android SDK must have an appropriately registered Android package name. In our example, the package name is com.example.raboy.myapplication. If you decide to change it, fine, but whatever you choose will have to be supplied to HERE to get your developer tokens.

All of this project linking can be done for free with a HERE developer account.

The next step is to define the deployment platforms.

android-studio-new-project-2

Even though you can still create projects for Android 4.0, you’ll need to be supporting a minimum API of 16 if you wish to use HERE. As of right now the maximum supported API doesn’t really matter.

After defining the target, the next step is to add an activity.

android-studio-new-project-3

For simplicity, we are going to use an Empty Activity, but feel free to choose whatever makes the most sense to you. When it comes to development, we’re going to include the map as a Fragment within the Activity.

The final step towards creating a new Android project is to name the Activity.

android-studio-new-project-4

The defaults are fine for the naming in this example. Before we start including the HERE Android SDK, we should probably make a few revisions to the project’s AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.raboy.myapplication">
    <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:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:hardwareAccelerated="true">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

In the above XML, a few things were added, in particular around the application permissions. The following permissions are required when using HERE Location Services (HLS) in your application:

<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"/>

In addition to various permissions, the application also needs hardware acceleration enabled, which is disabled by default. In the <application> there is the android:hardwareAccelerated="true" attribute which will enable acceleration.

Now we can consider the new Android project ready for the next step of including the HERE Android SDK.

Downloading and Configuring the HERE Android SDK

To use HERE within your Android application, the package name that was previously created must be registered in your HERE Developer Portal. Having a HERE account is free and very easy to configure.

here-developer-portal-android-sdk

After providing your package name, you’ll be given an application id and an application code to be used in the project. However, we’re not going to skip ahead quite yet. Instead, we need to download the SDK from the portal.

Within the archive that was downloaded, there should be a HERE-sdk.aar file, probably within the libs directory. The HERE-sdk.aar file should be placed in your project’s app/libs directory.

With the SDK in place, we need to apply the application id and application code values found in the portal. Open the project’s AndroidManifest.xml file and include the following lines:

<meta-data android:name="com.here.android.maps.appid" android:value="APP-ID-HERE"/>
<meta-data android:name="com.here.android.maps.apptoken" android:value="APP-CODE-HERE"/>

These lines should be placed within the <application> tags, but not as attributes. To get an idea of what your final AndroidManifest.xml file should look like, see the XML below.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.raboy.myapplication">
    <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:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:hardwareAccelerated="true">
        <meta-data android:name="com.here.android.maps.appid" android:value="APP-ID-HERE"/>
        <meta-data android:name="com.here.android.maps.apptoken" android:value="APP-CODE-HERE"/>
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

We’re not quite done configuring the HERE Android SDK. While it is in our project and the appropriate tokens are in place, it hasn’t been imported to be used in our code. To import the AAR file, it needs to be included in our Gradle configuration.

Open the project’s .build.gradle file and include the following:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.raboy.myapplication"
        minSdkVersion 16
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    repositories {
        flatDir {
            dirs 'libs'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation(name:'HERE-sdk', ext:'aar')
    implementation 'org.locationtech.jts:jts-core:1.15.0'
    implementation 'com.google.code.gson:gson:2.8.0'
}

To be clear on what has changed between our version and the original, we first added a path as a possible repository for libraries:

repositories {
    flatDir {
        dirs 'libs'
    }
}

What we’re doing is we’re saying that Gradle should look in the libs directory when building in addition to any of the remote repositories that are configured by default.

Now that the libs directory is linked up to Gradle, we need to define the AAR library that we had moved over:

implementation(name:'HERE-sdk', ext:'aar')

At this point in time the SDK is installed, configured, and ready for development. To sum it up, we applied our package name, copied our application id and application code, downloaded the AAR file, and configured Gradle to use the AAR file as a local dependency.

Displaying an Interactive Map within the Mobile Application

The difficult part, in regards to configuring our project, is behind us. Now we can focus on actually developing with HERE, and it actually isn’t very difficult.

As of right now we have a single Activity. This Activity has XML as well as Java. Starting with the XML, we need to create a Fragment to hold our map. Open the project’s activity_main.xml file and include the following:

<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" >

    <fragment
        class="com.here.android.mpa.mapping.MapFragment"
        android:id="@+id/mapfragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

Take note of the class and the id that we’ve given the Fragment. Using this information, we can take a look at the corresponding MainActivity.java file. Inside the Java file, include the following:

package com.example.raboy.myapplication;

import android.support.v7.app.AppCompatActivity;
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.MapFragment;

public class MainActivity extends AppCompatActivity {

    private Map map = null;
    private MapFragment mapFragment = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.mapfragment);
        mapFragment.init(new OnEngineInitListener() {
            @Override
            public void onEngineInitializationCompleted(OnEngineInitListener.Error error) {
                if (error == OnEngineInitListener.Error.NONE) {
                    map = mapFragment.getMap();
                    map.setCenter(new GeoCoordinate(37.7397, -121.4252, 0.0), Map.Animation.NONE);
                    map.setZoomLevel((map.getMaxZoomLevel() + map.getMinZoomLevel()) / 2);
                }
            }
        });
    }

}

Inside the onCreate method we are setting the view of our XML file and we are obtaining the Fragment of our map based on the id. Just because we have a map Fragment doesn’t mean that it is immediately ready for use. We need to call the init method and listen for when the map is ready.

@Override
public void onEngineInitializationCompleted(OnEngineInitListener.Error error) {
    if (error == OnEngineInitListener.Error.NONE) {
        map = mapFragment.getMap();
        map.setCenter(new GeoCoordinate(37.7397, -121.4252, 0.0), Map.Animation.NONE);
        map.setZoomLevel((map.getMaxZoomLevel() + map.getMinZoomLevel()) / 2);
    }
}

When the map is ready, assuming that the engine received no errors, we can set the center coordinates as well as the zoom. While this example doesn’t drop any markers on the map, we do end up with a map that we can pan and zoom with as part of the user experience.

Conclusion

You just saw how to get started with the HERE Android SDK for mobile development. A lot of the material found in the above tutorial was taken from the official documentation, but I’ve added my own spin on it from experiencing the setup myself.

Like I mentioned previously, the most consuming part is configuring the SDK itself, not necessarily trying to develop with HERE Location Services.