[Huawei Developers] John Wo:
More information like this, you can visit HUAWEI Developer Forum​

Introduction

Huawei Cab Application is to explore more about HMS Kits in real time scenario, we can use this app as reference to CP during HMS integration, and they can understand easily how HMS works in real time scenario, refer previous article.

Dashboard Module

The Dashboard page allows a user to book a cab with help of Huawei location, map and site kits, as follows:

Location kit provides to get the current location and location updates, and it provides flexible location based services globally to the users.

Huawei Map kit is to display maps, it covers map data of more than 200 countries and regions for searching any location address.

Site kit provides with convenient and secure access to diverse, place-related services to users.

Kits covered in Dashboard Module:

1. Location kit

2. Map kit

3. Site kit

4. Ads kit

Third Party API’s:

1. TomTom for Directions API

App Screenshots:

Auto fetch current location and also customize current location button in huawei map.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114403.51628442277875197365562231746124:50510927085113:2800:FBFF8EA7CD7B0F50F42BABB48A42E24BD91A66D424D806FAE6E4DD51367DE20B.jpg"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114403.51628442277875197365562231746124:50510927085113:2800:FBFF8EA7CD7B0F50F42BABB48A42E24BD91A66D424D806FAE6E4DD51367DE20B.jpg[/IMG]

Pick destination you want to travel with marker in the huawei map view.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114433.06442179136969633676355135870963:50510927085113:2800:10ECB315912E48715C58F57595CC52FD206E750B537C02F8CC35F6AD609F72F0.jpg"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114433.06442179136969633676355135870963:50510927085113:2800:10ECB315912E48715C58F57595CC52FD206E750B537C02F8CC35F6AD609F72F0.jpg[/IMG]

Pick destination using HMS Site Kit.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114549.91580656005679017861027348178476:50510927085113:2800:8B898C78E6CD58E61D2A69D95B75C3B175613C76D26CBDEA6DFAC46E33C043A8.jpg"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114549.91580656005679017861027348178476:50510927085113:2800:8B898C78E6CD58E61D2A69D95B75C3B175613C76D26CBDEA6DFAC46E33C043A8.jpg[/IMG]

Draw route between start and end location.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114631.92757411008206627791938950512162:50510927085113:2800:8437F3083A7E500CF036EB16AEFEE21CE6B22D5D831B860A0246E5428BA2B176.jpg"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114631.92757411008206627791938950512162:50510927085113:2800:8437F3083A7E500CF036EB16AEFEE21CE6B22D5D831B860A0246E5428BA2B176.jpg[/IMG]

Huawei Location Kit

HUAWEI Location Kit combines the GPS, Wi-Fi, and base station location functionalities in your app to build up global positioning capabilities, allowing you to provide flexible location-based services targeted at users around globally. Currently, it provides three main capabilities: fused location, activity identification, and geo-fence. You can call one or more of these capabilities as needed.

Huawei Map Kit

The HMS Core Map SDK is a set of APIs for map development in Android. The map data covers most countries outside China and supports multiple languages. The Map SDK uses the WGS 84 GPS coordinate system, which can meet most requirements of map development outside China. You can easily add map-related functions in your Android app, including:

Map display: Displays buildings, roads, water systems, and Points of Interest (POIs).

Map interaction: Controls the interaction gestures and buttons on the map.

Map drawing: Adds location markers, map layers, overlays, and various shapes.

Site Kit

HUAWEI Site Kit provide to users with convenient and secure access to diverse, place-related services.

Ads Kit

Huawei Ads provide developers extensive data capabilities to deliver high quality ad content to users. By integrating HMS ads kit we can start earning right away. It is very useful particularly when we are publishing a free app and want to earn some money from it.

Integrating HMS ads kit does not take more than 10 minuts HMS ads kit currently offers five types of ad format like Banner, Native, Rewarded, Interstitial and Splash ads.

In this article, we will see banner ad also.

Banner Ad: Banner ads are rectangular images that occupy a spot at the top, middle, or bottom within an app's layout. Banner ads refresh automatically at regular intervals. When a user taps a banner ad, the user is redirected to the advertiser's page in most cases.

TomTom for Direction API

TomTom Technology for a moving world. Meet the leading independent location, navigation and map technology specialist.

Follow the steps for TomTom Direction API.

Step1: Visit TomTom Developer Portal. https://developer.tomtom.com/

Step2: Login/Signup.

Step3: Click PRODUCTS and select Directions API

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114722.46804458909542115830746001156958:50510927085113:2800:F7027C03980EA5D69A3C0C1E6C99E898E30EA5E0AB245421ACFCA957BEA9D4C1.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114722.46804458909542115830746001156958:50510927085113:2800:F7027C03980EA5D69A3C0C1E6C99E898E30EA5E0AB245421ACFCA957BEA9D4C1.png[/IMG]

Step 4: Route API, as follows: https://developer.tomtom.com/routing-api/routing-api-documentation-routing/calculate-route

Step5: Click MY DASHBOARD and Copy Key and Use it in your application.

Integration Preparations

To integrate HUAWEI Map, Site, Location and Ads Kit, you must complete the following preparations:

Create an app in AppGallery Connect.

Create a project in Android Studio.

Generate a signing certificate.

Generate a signing certificate fingerprint.

Configure the signing certificate fingerprint.

Add the app package name and save the configuration file.

Add the AppGallery Connect plug-in and the Maven repository in the project-level build.gradle file.

Configure the signature file in Android Studio.

Configuring the Development Environment

Enabling HUAWEI Map, Site, Location and Ads Kit.

1. Sign in to AppGallery Connect, select My apps, click an app, and navigate to Develop > Overview > Manage APIs.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114805.81067085778889667365700663440946:50510927085113:2800:9DEDF58DBA7418AE46AF1E5FDA59D5D98C52BFF2679CA1543C109CC8CB560ADA.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911114805.81067085778889667365700663440946:50510927085113:2800:9DEDF58DBA7418AE46AF1E5FDA59D5D98C52BFF2679CA1543C109CC8CB560ADA.png[/IMG]

2. Click agconnect-services.json to download the configuration file.

3. Copy the agconnect-services.json file to the app's root directory.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911115108.96858929719149810849072329242658:50510927085113:2800:258E97B2591A3CD4730CB146B2F6A9B6E856CEDDFECB5A9F4589D4B45995675B.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911115108.96858929719149810849072329242658:50510927085113:2800:258E97B2591A3CD4730CB146B2F6A9B6E856CEDDFECB5A9F4589D4B45995675B.png[/IMG]

4. Open the build.gradle file in the root directory of your Android Studio project.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911115146.01861446935724591520796660203152:50510927085113:2800:945A8685103CFEBB33F201012F2BCE2A3AB1BA7ECAF5609E6E732E37944F16FF.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911115146.01861446935724591520796660203152:50510927085113:2800:945A8685103CFEBB33F201012F2BCE2A3AB1BA7ECAF5609E6E732E37944F16FF.png[/IMG]

5. Configure the following information in the build.gradle file.

buildscript {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
classpath 'com.huawei.agconnect:agcp:1.3.2.301'
}
}
allprojects {
repositories {

google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'}
}
}

6. Open the build.gradle file in the app directory.

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911115339.36125153895613610348001249422234:50510927085113:2800:48F5BDEFC4B02E2D31009DFB8EFB62A755513CE3B44531BE375EC9CCE639749A.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/700/618/2640091000001700618.20200911115339.36125153895613610348001249422234:50510927085113:2800:48F5BDEFC4B02E2D31009DFB8EFB62A755513CE3B44531BE375EC9CCE639749A.png[/IMG]

7. Add Dependencies in app level build.gradle.

apply plugin: 'com.huawei.agconnect'dependencies {
implementation 'com.huawei.hms:maps:5.0.1.300'
implementation 'com.huawei.hms:location:5.0.0.302'
implementation 'com.huawei.hms:site:5.0.0.300'
implementation 'com.huawei.hms:ads-lite:13.4.30.307'
}

8. Apply for relevant permissions in sections at the same level as the application section in the AndroidManifest.xml file.

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

9. Add Huawei MapView and Banner Ad in layout file: activity_maview.xml

<!--MapView-->
<com.huawei.hms.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:cameraTargetLat="51"
map:cameraTargetLng="10"
map:cameraZoom="8.5"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true" />

<!--BannerView-->
<com.huawei.hms.ads.banner.BannerView
android:id="@+id/hw_banner_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
hwads:adId="@string/banner_ad_id"
android:layout_alignParentTop="true"
hwads:bannerSize="BANNER_SIZE_360_57" />

10. Add the configuration for calling the MapView to the activity.

class DashboardFragment : Fragment(), OnMapReadyCallback, ReverseGeoCodeListener {private var hMap: HuaweiMap? = null
private var mMapView: MapView? = null
private var pickupLat: Double = 0.0
private var pickupLng: Double = 0.0
private var dropLat: Double = 0.0
private var dropLng: Double = 0.0
private var mPolyline: Polyline? = null
private var mMarkerDestination: Marker? = nulloverride fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) // create fusedLocationProviderClient
mFusedLocationProviderClient = LocationServices.getFusedLocation ProviderClient(activity) mapView?.onCreate(savedInstanceState)
mapView?.onResume()
mapView?.getMapAsync(this)}

fun initBannerAds() {
// Obtain BannerView based on the configuration in layout.
val adParam: AdParam = AdParam.Builder().build()
hw_banner_view.loadAd(adParam)
}

override fun onMapReady(map: HuaweiMap) {
Log.d(TAG, "onMapReady: ")
hMap = map hMap?.isMyLocationEnabled = true
hMap?.uiSettings?.isMyLocationButtonEnabled = false
getLastLocation()
hMap?.setOnCameraMoveStartedListener {
when (it) {
HuaweiMap.OnCameraMoveStartedListener.REASON_GESTURE -> {
Log.d(TAG, "The user gestured on the map.")
val midLatLng: LatLng = hMap?.cameraPosition!!.target
Log.d("Moving_LatLng ", "" + midLatLng)
dropLat = midLatLng.latitude
dropLng = midLatLng.longitude
val task = MyAsyncTask(this, false)
task.execute(midLatLng.latitude, midLatLng.longitude) }
HuaweiMap.OnCameraMoveStartedListener
.REASON_API_ANIMATION -> {
Log.d(TAG, "The user tapped something on the map.")
}
HuaweiMap.OnCameraMoveStartedListener
.REASON_DEVELOPER_ANIMATION -> {
Log.d(TAG, "The app moved the camera.")
}
}
}
}

11. Add the life cycle method of the MapView

override fun onStart() {
super.onStart()
mMapView?.onStart()
}

override fun onStop() {
super.onStop()
mMapView?.onStop()
}
override fun onDestroy() {
super.onDestroy()
mMapView?.onDestroy()
}

override fun onPause() {
mMapView?.onPause()
super.onPause()
}

override fun onResume() {
super.onResume()
mMapView?.onResume()
}

override fun onLowMemory() {
super.onLowMemory()
mMapView?.onLowMemory()
}

12. Check permissions to let the user allow App to access user location from android 6.0

if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "sdk < 28 Q")
if (checkSelfPermission(
this,
ACCESS_FINE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
this,
ACCESS_COARSE_LOCATION
) != PERMISSION_GRANTED
) {
val strings = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION)
requestPermissions(this, strings, 1)
}
} else {
if (checkSelfPermission(
this@RequestLocationUpdatesWithCallbackActivity,
ACCESS_FINE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
this@RequestLocationUpdatesWithCallbackActivity, ACCESS_COARSE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
this@RequestLocationUpdatesWithCallbackActivity,
"android.permission.ACCESS_BACKGROUND_LOCATION"
) != PERMISSION_GRANTED
) {
val strings = arrayOf(
ACCESS_FINE_LOCATION,
ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"
)
requestPermissions(this, strings, 2)
}
}

13. In you activity you need to handle the response by this way.

Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 1) {
if (grantResults.size > 1 && grantResults[0] == PERMISSION_GRANTED && grantResults[1] == PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION successful")
} else {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed")
}
}
if (requestCode == 2) {
if (grantResults.size > 2 && grantResults[2] == PERMISSION_GRANTED && grantResults[0] == PERMISSION_GRANTED && grantResults[1] == PERMISSION_GRANTED) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful")
} else {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed")
}
}
}

You can perform subsequent steps by referring to the RequestLocationUpdatesWithCallbackActivity.kt file.

14. Create a location provider client and device setting client.

// create fusedLocationProviderClient
fusedLocationProviderClient=LocationServices.getFusedLocationProviderClient(this)
// create settingsClient
settingsClient = LocationServices.getSettingsClient(this)

15. Create a location request.

mLocationRequest = LocationRequest().apply {
// set the interval for location updates, in milliseconds
interval = 1000
needAddress = true
// set the priority of the request
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}

16. Create a result callback.

mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
if (locationResult != null) {
val locations: List<Location> =
locationResult.locations
if (locations.isNotEmpty()) {
for (location in locations) {
LocationLog.i(TAG,"onLocationResult location[Longitude,Latitude,Accuracy]:${location.longitude} , ${location.latitude} , ${location.accuracy}")
}
}
}
}
override fun onLocationAvailability(locationAvailability: LocationAvailability?) {
locationAvailability?.let {
val flag: Boolean = locationAvailability.isLocationAvailable
LocationLog.i(TAG, "onLocationAvailability isLocationAvailable:$flag")
}
}
}

17. Request location updates.

private fun requestLocationUpdatesWithCallback() {
try {
val builder = LocationSettingsRequest.Builder()
builder.addLocationRequest(mLocationRequest)
val locationSettingsRequest = builder.build()
// check devices settings before request location updates.
//Before requesting location update, invoke checkLocationSettings to check device settings.
val locationSettingsResponseTask: Task<LocationSettingsResponse> = settingsClient.checkLocationSettings(locationSettingsRequest)

locationSettingsResponseTask.addOnSuccessListener { locationSettingsResponse: LocationSettingsResponse? ->
Log.i(TAG, "check location settings success {$locationSettingsResponse}")
// request location updates
fusedLocationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener {
LocationLog.i(TAG, "requestLocationUpdatesWithCallback onSuccess")
}
.addOnFailureListener { e ->
LocationLog.e(TAG, "requestLocationUpdatesWithCallback onFailure:${e.message}")
}
}
.addOnFailureListener { e: Exception ->
LocationLog.e(TAG, "checkLocationSetting onFailure:${e.message}")
when ((e as ApiException).statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
val rae = e as ResolvableApiException
rae.startResolutionForResult(
this@RequestLocationUpdatesWithCallbackActivity, 0
)
} catch (sie: SendIntentException) {
Log.e(TAG, "PendingIntent unable to execute request.")
}
}
}
} catch (e: Exception) {
LocationLog.e(TAG, "requestLocationUpdatesWithCallback exception:${e.message}")
}
}

18. Remove location updates.

private fun removeLocationUpdatesWithCallback() {
try {
fusedLocationProviderClient.removeLocationUpdates(mLocationCallback)
.addOnSuccessListener {
LocationLog.i(
TAG,
"removeLocationUpdatesWithCallback onSuccess"
)
}
.addOnFailureListener { e ->
LocationLog.e(
TAG,
"removeLocationUpdatesWithCallback onFailure:${e.message}"
)
}
} catch (e: Exception) {
LocationLog.e(
TAG,
"removeLocationUpdatesWithCallback exception:${e.message}"
)
}
}

19. Reverse Geocoding

companion object {
private const val TAG = "MapViewDemoActivity"
private const val MAPVIEW_BUNDLE_KEY = "MapViewBundleKey"
class MyAsyncTask internal constructor(
private val context: DashboardFragment,
private val isStartPos: Boolean
) : AsyncTask<Double, Double, String?>() {

private var resp: String? = null
lateinit var geocoding: Geocoding

override fun onPreExecute() {

}

override fun doInBackground(vararg params: Double?): String? {
try {
geocoding = Geocoding()
geocoding.reverseGeoCodeListener = context
geocoding.reverseGeocoding(
"reverseGeocode",
"YOUR_API_KEY",
params[0],
params[1],
isStartPos
)
} catch (e: InterruptedException) {
e.printStackTrace()
} catch (e: Exception) {
e.printStackTrace()
}
return resp
} override fun onPostExecute(result: String?) {

}

override fun onProgressUpdate(vararg values: Double?) {

}
}
}

20. Geocoding class for converting latlng into Address

class Geocoding {
var reverseGeoCodeListener: ReverseGeoCodeListener? = null
val ROOT_URL = "https://siteapi.cloud.huawei.com/mapApi/v1/siteService/"
val conection =
"?key="
val JSON = MediaType.parse("application/json; charset=utf-8")

open fun reverseGeocoding(serviceName: String, apiKey: String?, lat: Double?, lng: Double?, isStartPos: Boolean) {
var sites: String = ""
val json = JSONObject()
val location = JSONObject()
try {
location.put("lng", lng)
location.put("lat", lat)
json.put("location", location)
json.put("language", "en")
json.put("politicalView", "CN")
json.put("returnPoi", true)
Log.d("MapViewDemoActivity",json.toString())
} catch (e: JSONException) {
Log.e("error", e.message)
}
val body : RequestBody = RequestBody.create(JSON, json.toString())
val client = OkHttpClient()
val request = Request.Builder()
.url(ROOT_URL + serviceName + conection + URLEncoder.encode(apiKey, "UTF-8"))
.post(body)
.build()
client.newCall(request).enqueue(object : Callback {
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
var str_response = response.body()!!.string()
val json_response:JSONObject = JSONObject(str_response)
val responseCode:String = json_response.getString("returnCode")
if (responseCode.contentEquals("0")) {
Log.d("ReverseGeocoding", str_response)
var jsonarray_sites: JSONArray = json_response.getJSONArray("sites")

var i:Int = 0
var size:Int = jsonarray_sites.length()

var json_objectdetail:JSONObject=jsonarray_sites.getJSONObject(0)
sites = json_objectdetail.getString("formatAddress")
Log.d("formatAddress", sites)
reverseGeoCodeListener?.getAddress(sites, isStartPos)
} else{
sites = "No Result"
Log.d("formatAddress", "")
reverseGeoCodeListener?.onAdddressError(sites)
}
}

override fun onFailure(call: Call, e: IOException) {
sites = "No Result"
Log.e("ReverseGeocoding", e.toString())
reverseGeoCodeListener?.onAdddressError(sites)
}
})
}
}

This is not the end. For full content, you can visit https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0201352135916100198&fid=0101187876626530001