OMH Maps Client Library is an Android SDK that simplifies the integration of maps on both Google Mobile Services (GMS) and non-GMS devices. It provides a unified interface and components for a consistent map experience, eliminating the need for separate codebases for different Android builds. This repository contains a detailed Getting Started guide to help developers learn and effectively implement the OMH Maps Client Library into their Android projects. For a general overview and understanding of the philosophy behind OMH, please visit the official website at https://www.openmobilehub.com.
For instance, the following screenshots showcase multiple devices with Android, both with GMS and Non-GMS. The same app works without changing a single line of code, supporting multiple map provider implementations (Google Maps and OpenStreetMap).
Non-GMS Device Kindle Fire HD 10 Kids |
Non-GMS Android Emulator Image Pixel 6 Pro |
Non-GMS Device Huawei P60 |
GMS Device Pixel 6a |
---|---|---|---|
This section describes how to setup an Android Studio project to use the OMH Maps SDK for Android. For greater ease, a base code will be used within the repository.
Note: To quickly run a full-featured app with all OMH Maps functionality, refer to the Sample App
section and follow the provided steps.
- Android Studio is required. If you haven't already done so, download and install it.
- Ensure that you are using the Android Gradle plugin version 7.0 or later in Android Studio.
To clone the repository and checkout the starter-code
branch, use the following command in your Terminal:
git clone --branch starter-code https://github.com/openmobilehub/omh-maps.git
Complete the required Cloud Console setup following the next steps, for more information see Documentation
- In the Google Maps Cloud Console, on the project selector page, click Create Project to begin creating a new Cloud project, Go to the project selector page.
- Make sure that billing is enabled for your Cloud project, Confirm that billing is enabled for your project.
- To use Google Maps Platform, you must enable the APIs or SDKs you plan to use with your project, Enable the Maps SDK for Android.
- This step only goes through the API Key creation process. If you use your API Key in production, we strongly recommend that you restrict your API key. You can find more information in the product-specific Using API Keys page.
- The API key is a unique identifier that authenticates requests associated with your project for usage and billing purposes. You must have at least one API key associated with your project.
- Go to the Google Maps Platform > Credentials page, Go to the Credentials page.
- On the Credentials page, click Create credentials > API key. The API key created dialog displays your newly created API key.
- Click Close. The new API key is listed on the Credentials page under API keys. (Remember to restrict the API key before using it in production.)
Note: To continue it is necessary to complete the creation of an API key. If you had problems please visit Set up your Google Cloud project.
You should not check your API key into your version control system, so it is recommended
storing it in the local.properties
file, which is located in the root directory of your project.
For more information about the local.properties
file, see Gradle properties files.
-
Open the
local.properties
in the project level directory, and then add the following code. ReplaceYOUR_API_KEY
with your API key.MAPS_API_KEY=YOUR_API_KEY
-
Save the file.
-
In your
maps-starter-sample
module levelAndroidManifest.xml
file, under theapplication
element add themeta-data
element as follows:<manifest ...> <application ...> ... <meta-data android:name="com.google.android.geo.API_KEY" android:value="${MAPS_API_KEY}" /> </application> </manifest>
-
In your "maps-starter-sample" module-level
AndroidManifest.xml
add the required permissions, for more information see permissions.<manifest ...> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application ...> ... </application> </manifest>
To integrate the OMH Maps into your project, it is necessary to add a few Gradle dependencies.
To incorporate OMH Maps into your project, you have two options: utilize the OMH Core Plugin or directly include the OMH Client libraries dependencies. The subsequent instructions will outline the necessary steps for including the OMH Core Plugin as a Gradle dependency.
-
In your
maps-starter-sample" module-level
build.gradleunder the
plugins` element add the plugin id.plugins { ... id("com.openmobilehub.android.omh-core") }
-
Save the file and sync Project with Gradle Files.
In this sample app, we utilize the omhConfig
definition to expand the capabilities of the existing Android Studio variants. For more details, refer to the OMH Core Plugin Docs.
- In your
maps-starter-sample
module-levelbuild.gradle
file add the following code at the end of the file.
...
dependencies {
...
}
omhConfig {
bundle("singleBuild") {
maps {
gmsService {
dependency = "com.openmobilehub.android:maps-api-googlemaps:1.0"
}
nonGmsService {
dependency = "com.openmobilehub.android:maps-api-openstreetmap:1.0"
}
}
}
bundle("gms") {
maps {
gmsService {
dependency = "com.openmobilehub.android:maps-api-googlemaps:1.0"
}
}
}
bundle("nonGms") {
maps {
nonGmsService {
dependency = "com.openmobilehub.android:maps-api-openstreetmap:1.0"
}
}
}
}
In this step, you defined the OMH Core Plugin bundles to generate multiple build variants with specific suffixes as their names. For example, if your project has release
and debug
variants with singleBuild
, gms
, and nonGms
OMH bundles, the following build variants will be generated:
releaseSingleBuild
,releaseGms
, andreleaseNonGms
debugSingleBuild
,debugGms
, anddebugNonGms
-
Define the
Service
. In this example is maps. -
Define the
ServiceDetails
. In this example aregmsService
andnonGmsService
. -
Define the dependency and the path. In this example are
com.openmobilehub.android:maps-api-googlemaps:1.0"
andcom.openmobilehub.android:maps-api-openstreetmap:1.0
.Note: It's important to observe how a single build encompasses both GMS and Non-GMS configurations.
-
Define the
Service
. In this example is maps. -
Define the
ServiceDetails
. In this example isgmsService
. -
Define the dependency and the path. In this example is
com.openmobilehub.android:maps-api-googlemaps:1.0"
.Note: gms build covers only GMS (Google Mobile Services).
-
Define the
Service
. In this example is maps. -
Define the
ServiceDetails
. In this example isnonGmsService
. -
Define the dependency and the path. In this example is
com.openmobilehub.android:maps-api-openstreetmap:1.0
.Note: nonGms build covers only Non-GMS configurations.
-
Save and sync Project with Gradle Files.
-
Now you can select a build variant. To change the build variant Android Studio uses, do one of the following:
- Select
Build
>Select Build Variant...
in the menu. - Select
View
>Tool Windows
>Build Variants
in the menu. - Click the
Build Variants
tab on the tool window bar.
- Select
-
You can select any of the 3 variants for the
:Maps-starter-sample
:singleBuild
variant builds for GMS (Google Mobile Services) and Non-GMS devices without changes to the code.(Recommended)gms
variant builds for devices that has GMS (Google Mobile Services).nonGms
variant builds for devices that doesn't have GMS (Google Mobile Services).
Note: In the rest of this guide, we will use the
debugSingleBuild
variant to demonstrate the same build running on GMS and Non-GMS devices. -
Open
maps-starter-sample
module-levelMainApplication
class and add the required imports below the package name. The file is in the same level as theMainActivity
:import com.omh.android.maps.api.factories.OmhMapProvider
Then initialize the
OmhMapProvider
as follows:class MainApplication : Application() { override fun onCreate() { super.onCreate() OmhMapProvider.Initiator() .addGmsPath(BuildConfig.MAPS_GMS_PATH) .addNonGmsPath(BuildConfig.MAPS_NON_GMS_PATH) .initialize() } }
Important: If you encounter the error "Missing BuildConfig.MAPS_GMS_PATH and BuildConfig.MAPS_NON_GMS_PATH in BuildConfig class". Follow the next steps:
- Sync Project with Gradle Files.
- Select
Build
from the menu at the top in Android Studio. - Click on
Clean Project
and await. - Click on
Rebuild Project
and await.
The main interfaces that you will be interacting with are called OmhMap
, OmhMapView
and OmhLocation
.
It contains all your basic maps and location functions like displaying a marker, map gestures, getting current location and more.
Additionally a fragment OmhMapFragment
is provided, this fragment manages the life cycle of the map.
OmhMapFragment
is the simplest way to place a map in an application.
Fragment has to declare android:name
that sets the class name of the fragment to OmhMapFragment
, which is the fragment type used in the maps fragment file.
- Insert the XML fragment snippet into the
fragment_map.xml
.
...
<fragment
android:id="@+id/fragment_map_container"
android:name="com.omh.android.maps.api.presentation.fragments.OmhMapFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
...
And the complete fragment's layout should look similar to this example:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapFragment">
<fragment
android:id="@+id/fragment_map_container"
android:name="com.omh.android.maps.api.presentation.fragments.OmhMapFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
- Change the variant to
debugSingleBuild
. - Click
Run
for themaps-starter-sample
.
An OmhMap
must be acquired using getMapAsync(OmhOnMapReadyCallback)
. This class automatically initializes the maps system and the view.
-
Implement the
OmhOnMapReadyCallback
interface and override theonMapReady()
method, to set up the map when theOmhMap
object is available:import android.Manifest.permission.ACCESS_COARSE_LOCATION import android.Manifest.permission.ACCESS_FINE_LOCATION import android.content.pm.PackageManager import android.os.Bundle import android.util.Log import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat import com.omh.android.maps.api.factories.OmhMapProvider import com.omh.android.maps.api.presentation.fragments.OmhMapFragment import com.omh.android.maps.api.presentation.interfaces.location.OmhFailureListener import com.omh.android.maps.api.presentation.interfaces.location.OmhSuccessListener import com.omh.android.maps.api.presentation.interfaces.maps.OmhMap import com.omh.android.maps.api.presentation.interfaces.maps.OmhOnMapReadyCallback import com.omh.android.maps.api.presentation.models.OmhMarkerOptions import com.omh.android.maps.starter_sample.databinding.FragmentMapBinding class MapFragment : Fragment(), OmhOnMapReadyCallback { // ... override fun onMapReady(omhMap: OmhMap) { if (!hasPermissions()) { Log.e("permission error", "Not required permissions to get current location") return } val onSuccessListener = OmhSuccessListener { omhCoordinate -> omhMap.moveCamera(omhCoordinate, 15f) val omhMarkerOptions = OmhMarkerOptions().apply { title = "My Current Location" position = omhCoordinate } omhMap.addMarker(omhMarkerOptions) } val onFailureListener = OmhFailureListener { exception -> Log.e("location error", exception.localizedMessage, exception) } // Safe use of 'noinspection MissingPermission' since it is checking permissions in the if condition // noinspection MissingPermission OmhMapProvider.getInstance().provideOmhLocation(requireContext()).getCurrentLocation(onSuccessListener, onFailureListener) } private fun hasPermissions() = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION).all { ContextCompat.checkSelfPermission(requireContext(), it) == PackageManager.PERMISSION_GRANTED } }
-
In your fragment's onViewCreated(view: View, savedInstanceState: Bundle?) method, get the
OmhMapFragment
by calling FragmentManager.findFragmentById(). Then usegetMapAsync()
to register for the map callback:override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Request permissions, this can be done in another way, see https://developer.android.com/training/permissions/requesting registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { // Obtain the OmhMapFragment and get notified when the map is ready to be used. val omhMapFragment = childFragmentManager.findFragmentById(R.id.fragment_map_container) as? OmhMapFragment omhMapFragment?.getMapAsync(this) }.launch(arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION)) }
-
Click
Run
for themaps-starter-sample
menu option (or the play button icon) to run your app and see the map with the device's location.Important: For a better experience and accuracy try a phone with a SIM card.
-
Explore Advanced Features
Complete the guide and access advanced mapping features: camera events, markers, location management, gestures, network utilities, and custom implementations/plugins. Visit Advanced Features for details, examples, and guides. Enhance your mapping experiences. Explore now!
This repository includes a maps-sample that demonstrates the functionality of the OMH Maps Client Library. By cloning the repo and executing the app, you can explore the various features offered by the library. However, if you prefer a step-by-step approach to learn the SDK from scratch, we recommend following the detailed Getting Started guide provided in this repository. The guide will walk you through the implementation process and help you integrate the OMH Maps Client Library into your projects effectively.
- Find complete documentation on the Wiki.
- Check out the API Reference Docs.
OMH Maps SDK is open-source, promoting community collaboration and plugin support from other map providers to enhance capabilities and expand supported map services. More details can be found at https://github.com/openmobilehub/omh-maps/wiki.
Please contribute! We will gladly review any pull requests. Make sure to read the Contributing page first though.
Copyright 2023 Open Mobile Hub
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.