Related
Assigning App Permissions
To use the activity identification service in versions earlier than Android Q, following permission is already defined in plugin.xml file
Code:
<!--Activity Identification-->
<config-file target="AndroidManifest.xml" parent="/*">
<!--...-->
<uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION"/>
<!--...-->
</config-file>
To use the activity identification service in Android Q and later versions, following permission is already defined in plugin.xml file
Code:
<!--Activity Identification-->
<config-file target="AndroidManifest.xml" parent="/*">
<!--...-->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<!--...-->
</config-file>
Using the Activity Identification Class
The Java class defined for Activity Identification service of Location Kit is HMSActivityIdentification.
To use it on Cordova, you should initialise the Activity Identification service of Location Kit with HMSActivityIdentification.init() method before using other methods of HMSActivityIdentification.
Code:
// Initialize LocationKit
HMSLocationKit.init();
HMSActivityIdentification.init();
Registering Receiving of Activity Identification Updates
To use the activity identification service, you need to register receiving of activity identification updates to check the current user status, such as walking, bicycling, and motionless.
You can create activity identification updates using the createActivityIdentificationUpdates(duration) method.
This method has an input parameter indicating the update interval, and returns the sent request ID in the response.
Code:
const activityIdentificationUpdateRequests = [];
const activityIdentificationUpdates = await HMSActivityIdentification.createActivityIdentificationUpdates(2000);
console.log({activityIdentificationUpdates});
//This id later used to remove the created updates.
activityIdentificationUpdateRequests.push(activityIdentificationUpdates.requestCode);
You can use the registerHMSEvent(eventName, handler) method to listen to and receive data from activity identification events.
Code:
activityIdentificationUpdateRequests.forEach(async requestCode => {
const result = await HMSActivityIdentification.deleteActivityIdentificationUpdates(requestCode);
console.log({requestCode, result});
});
activityIdentificationUpdateRequests.length = 0; // clear the array
Registering Receiving of Activity Conversion Updates
The function of detecting activity conversions (activity entering and exit) is provided, for example, to detect user status change from standing still to walking or walking to running etc.
You can create activity conversion updates using the createActivityConversionUpdates(conversionRequest) method.
This method has an input parameter, which is an object specifying which type of activity and which type of conversions should be detected. The following is an example of the object.
Code:
const activityConversions = [
// STILL
{
conversionType: HMSActivityIdentification.ActivityConversions.ENTER_ACTIVITY_CONVERSION,
activityType: HMSActivityIdentification.Activities.STILL },
{
conversionType: HMSActivityIdentification.ActivityConversions.EXIT_ACTIVITY_CONVERSION,
activityType: HMSActivityIdentification.Activities.STILL
},
// ON FOOT
{
conversionType: HMSActivityIdentification.ActivityConversions.ENTER_ACTIVITY_CONVERSION,
activityType: HMSActivityIdentification.Activities.FOOT
},
{
conversionType: HMSActivityIdentification.ActivityConversions.EXIT_ACTIVITY_CONVERSION,
activityType: HMSActivityIdentification.Activities.FOOT
},
// RUNNING
{
conversionType: HMSActivityIdentification.ActivityConversions.ENTER_ACTIVITY_CONVERSION,
activityType: HMSActivityIdentification.Activities.RUNNING
},
{
conversionType: HMSActivityIdentification.ActivityConversions.EXIT_ACTIVITY_CONVERSION,
activityType: HMSActivityIdentification.Activities.RUNNING
}
];
The createActivityConversionUpdates method returns a response containing the request ID.
Code:
const activityConversionUpdateRequests = [];
const activityConversions = [
//...
];
const activityConversionResult = await HMSActivityIdentification.createActivityConversionUpdates(activityConversions);
console.log({activityConversionResult});
//This id later used to remove the created
updates.activityConversionUpdateRequests.push(activityConversionResult.requestCode);
You can use the registerHMSEvent(eventName, handler) method to listen to and receive data from activity conversion events.
Code:
registerHMSEvent(HMSActivityIdentification.Events.ACTIVITY_CONVERSION_RESULT, (result) => {
console.log('new activity conversion');
});
You can remove activity conversion updates using the deleteActivityConversionUpdates(requestCode) method.
Code:
activityConversionUpdateRequests.forEach(async requestCode => {
const result = await HMSActivityIdentification.deleteActivityConversionUpdates(requestCode);
console.log({requestCode, result});
});
activityConversionUpdateRequests.length = 0; // clear the array
More information like this, you can visit HUAWEI Developer Forum
Original link: https://forums.developer.huawei.com/forumPortal/en/topicview?tid=0202330537081990041&fid=0101187876626530001
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Article Introduction
In this article we are going to cover HUAWEI Map Kit JavaScript API introduction. Next we going to implementing HUAWEI Map in Ionic/Cordova project. Lastly we will implement HUAWEI Map Kit JavaScript into Native Application.
Technology Introduction
HUAWEI Map Kit provides JavaScript APIs for you to easily build map apps applicable to browsers.
It provides the basic map display, map interaction, route planning, place search, geocoding, and other functions to meet requirements of most developers.
Restriction
Before using the service, you need to apply for an API key on the HUAWEI Developers website. For details, please refer to "Creating an API Key" in API Console Operation Guide. To enhance the API key security, you are advised to restrict the API key. You can configure restrictions by app and API on the API key editing page.
Generating API Key
Go to HMS API Services > Credentials and click Create credential.
Click API key to generate new API Key.
In the dialog box that is displayed, click Restrict to set restrictions on the key to prevent unauthorized use or quota theft. This step is optional.
The restrictions include App restrictions and API restriction.
App restrictions: control which websites or apps can use your key. Set up to one app restriction per key.
API restrictions: specify the enabled APIs that this key can call.
After setup App restriction and API restriction API key will generate.
The API key is successfully created. Copy API Key to use in your project.
Huawei Web Map API introduction
1. Make a Basic Map
Code:
function loadMapScript() {
const apiKey = encodeURIComponent(
"API_KEY"
);
const src = `https://mapapi.cloud.huawei.com/mapjs/v1/api/js?callback=initMap&key=${apiKey}`;
const mapScript = document.createElement("script");
mapScript.setAttribute("src", src);
document.head.appendChild(mapScript);
}
function initMap() { }
function initMap() {
const mapOptions = {};
mapOptions.center = { lat: 48.856613, lng: 2.352222 };
mapOptions.zoom = 8;
mapOptions.language = "ENG";
const map = new HWMapJsSDK.HWMap(
document.getElementById("map"),
mapOptions
);
}
loadMapScript();
Note: Please update API_KEY with the key which you have generated. In script url we are declaring callback function, which will automatically initiate once Huawei Map Api loaded successfully.
2. Map Interactions
Map Controls
Code:
var mapOptions = {};
mapOptions.center = {lat: 48.856613, lng: 2.352222};
mapOptions.zoom = 10;
scaleControl
mapOptions.scaleControl = true; // Set to display the scale.
mapOptions.scaleControlOptions = {
units: "imperial" // Set the scale unit to inch.
};
zoomSlider
Code:
mapOptions.zoomSlider = true ; // Set to display the zoom slider.
zoomControl
Code:
mapOptions.zoomControl = false; // Set not to display the zoom button.
rotateControl (Manage Compass)
Code:
mapOptions.rotateControl = true; // Set to display the compass.
navigationControl
Code:
mapOptions.navigationControl = true; // Set to display the pan button.
copyrightControl
Code:
mapOptions.copyrightControl = true; // Set to display the copyright information.
mapOptions.copyrightControlOptions = {value: "HUAWEI",} // Set the copyright information.
locationControl
Code:
mapOptions.locationControl= true; // Set to display the current location.
Camera
Map moving: You can call the map.panTo(latLng)
Map shift: You can call the map.panBy(x, y)
Zoom: You can use the map.setZoom(zoom) method to set the zoom level of a map.
Area control: You can use map.fitBounds(bounds) to set the map display scope.
Map Events
Map click event:
Code:
map.on('click', () => {
map.zoomIn();
});
Map center change event:
Code:
map.onCenterChanged(centerChangePost);
function centerChangePost() {
var center = map.getCenter();
alert( 'Lng:'+map.getCenter().lng+'
'+'Lat:'+map.getCenter().lat);
}
Map heading change event:
Code:
map.onHeadingChanged(headingChangePost);
function headingChangePost() {
alert('Heading Changed!');
}
Map zoom level change event:
Code:
map.onZoomChanged(zoomChangePost);
function zoomChangePost() {
alert('Zoom Changed!')
}
3. Drawing on Map
Marker:
You can add markers to a map to identify locations such as stores and buildings, and provide additional information with information windows.
Code:
var map;
var mMarker;
function initMap() {
var mapOptions = {};
mapOptions.center = {lat: 48.856613, lng: 2.352222};
mapOptions.zoom = 8;
map = new HWMapJsSDK.HWMap(document.getElementById('map'), mapOptions);
mMarker = new HWMapJsSDK.HWMarker({
map: map,
position: {lat: 48.85, lng: 2.35},
zIndex: 10,
label: 'A',
icon: {
opacity: 0.5
}
});
}
Marker Result:
Marker Clustering:
The HMS Core Map SDK allows you to cluster markers to effectively manage them on the map at different zoom levels. When a user zooms in on the map to a high level, all markers are displayed on the map. When the user zooms out, the markers are clustered on the map for orderly display.
Code:
var map;
var markers = [];
var markerCluster;
var locations = [
{lat: 51.5145160, lng: -0.1270060},
{ lat : 51.5064490, lng : -0.1244260 },
{ lat : 51.5097080, lng : -0.1200450 },
{ lat : 51.5090680, lng : -0.1421420 },
{ lat : 51.4976080, lng : -0.1456320 },
···
{ lat : 51.5061590, lng : -0.140280 },
{ lat : 51.5047420, lng : -0.1470490 },
{ lat : 51.5126760, lng : -0.1189760 },
{ lat : 51.5108480, lng : -0.1208480 }
];
function initMap() {
var mapOptions = {};
mapOptions.center = {lat: 48.856613, lng: 2.352222};
mapOptions.zoom = 3;
map = new HWMapJsSDK.HWMap(document.getElementById('map'), mapOptions);
generateMarkers(locations);
markerCluster = new HWMapJsSDK.HWMarkerCluster(map, markers);
}
function generateMarkers(locations) {
for (let i = 0; i < locations.length; i++) {
var opts = {
position: locations[i]
};
markers.push(new HWMapJsSDK.HWMarker(opts));
}
}
Cluster markers Result:
Information Window:
The HMS Core Map SDK supports the display of information windows on the map. There are two types of information windows: One is to display text or image independently, and the other is to display text or image in a popup above a marker. The information window provides details about a marker.
Code:
var infoWindow;
function initMap() {
var mapOptions = {};
mapOptions.center = {lat: 48.856613, lng: 2.352222};
mapOptions.zoom = 8;
var map = new HWMapJsSDK.HWMap(document.getElementById('map'), mapOptions);
infoWindow = new HWMapJsSDK.HWInfoWindow({
map,
position: {lat: 48.856613, lng: 2.352222},
content: 'This is to show mouse event of another marker',
offset: [0, -40],
});
}
Info window Result:
Ground Overlay
The builder function of GroundOverlay uses the URL, LatLngBounds, and GroundOverlayOptions of an image as the parameters to display the image in a specified area on the map. The sample code is as follows:
Code:
var map;
var mGroundOverlay;
function initMap() {
var mapOptions = {};
mapOptions.center = {lat: 48.856613, lng: 2.352222};
mapOptions.zoom = 8;
map = new HWMapJsSDK.HWMap(document.getElementById('map'), mapOptions);
var imageBounds = {
north: 49,
south: 48.5,
east: 2.5,
west: 1.5,
};
mGroundOverlay = new HWMapJsSDK.HWGroundOverlay(
// Path to a local image or URL of an image.
'huawei_logo.png',
imageBounds,
{
map: map,
opacity: 1,
zIndex: 1
}
);
}
Marker Result:
Ionic / Cordova Map Implementation
In this part of article we are supposed to add Huawei Map Javascript API’s.
Update Index.html to implment Huawei Map JS scripts:
You need to update src/index.html and include Huawei map javacript cloud script url.
Code:
function loadMapScript() {
const apiKey = encodeURIComponent(
"API_KEY"
);
const src = `https://mapapi.cloud.huawei.com/mapjs/v1/api/js?callback=initMap&key=${apiKey}`;
const mapScript = document.createElement("script");
mapScript.setAttribute("src", src);
document.head.appendChild(mapScript);
}
function initMap() { }
loadMapScript();
Make new Map page:
Code:
ionic g page maps
Update maps.page.ts file and update typescript:
Code:
import { Component, OnInit, ChangeDetectorRef } from "@angular/core";
import { Observable } from "rxjs";
declare var HWMapJsSDK: any;
declare var cordova: any;
@Component({
selector: "app-maps",
templateUrl: "./maps.page.html",
styleUrls: ["./maps.page.scss"],
})
export class MapsPage implements OnInit {
map: any;
baseLat = 24.713552;
baseLng = 46.675297;
ngOnInit() {
this.showMap(his.baseLat, this.baseLng);
}
ionViewWillEnter() {
}
ionViewDidEnter() {
}
showMap(lat = this.baseLat, lng = this.baseLng) {
const mapOptions: any = {};
mapOptions.center = { lat: lat, lng: lng };
mapOptions.zoom = 10;
mapOptions.language = "ENG";
this.map = new HWMapJsSDK.HWMap(document.getElementById("map"), mapOptions);
this.map.setCenter({ lat: lat, lng: lng });
}
}
Ionic / Cordova App Result:
Native Application Huawei JS API Implementation
In this part of article we are supposed to add javascript based Huawei Map html version into our Native through webview. This part of implementation will be helpful for developer who required very minimal implementation of map.
Make assets/www/map.html file
Add the following HTML code inside map.html file:
Code:
var map;
var mMarker;
var infoWindow;
function initMap() {
const LatLng = { lat: 24.713552, lng: 46.675297 };
const mapOptions = {};
mapOptions.center = LatLng;
mapOptions.zoom = 10;
mapOptions.scaleControl = true;
mapOptions.locationControl= true;
mapOptions.language = "ENG";
map = new HWMapJsSDK.HWMap(
document.getElementById("map"),
mapOptions
);
map.setCenter(LatLng);
mMarker = new HWMapJsSDK.HWMarker({
map: map,
position: LatLng,
zIndex: 10,
label: 'A',
icon: {
opacity: 0.5
}
});
mMarker.addListener('click', () => {
infoWindow.open();
});
infoWindow = new HWMapJsSDK.HWInfoWindow({
map,
position: LatLng,
content: 'This is to info window of marker',
offset: [0, -40],
});
infoWindow.close();
}
Add the webview in your layout:
Code:
< WebView
android:id="@+id/webView_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Update your Activity class to call html file
Code:
class MainActivity : AppCompatActivity() {
lateinit var context: Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
context = this
val mWebview = findViewById(R.id.webView_map)
mWebview.webChromeClient = WebChromeClient()
mWebview.webViewClient = WebViewClient()
mWebview.settings.javaScriptEnabled = true
mWebview.settings.setAppCacheEnabled(true)
mWebview.settings.mediaPlaybackRequiresUserGesture = true
mWebview.settings.domStorageEnabled = true
mWebview.loadUrl("file:///android_asset/www/map.html")
}
}
Internet permission:
Don’t forget to add internet permissions in androidmanifest.xml file.
Code:
< uses-permission android:name="android.permission.INTERNET" />
< uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
< uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Native app Result:
References:
Huawei Map JavaScript API:
https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/javascript-api-introduction-0000001050164063
Complete Ionic JS Map Project:
https://github.com/salmanyaqoob/Ionic-All-HMS-Kits
Conclusion
Huawei Map JavaSript Api will be helpful for JavaScript developers to implement Huawei Map on cross platforms like “Cordova, Ionic, React-Native” and also helpful for the Native developers to implement under his projects. Developers can also able to implement Huawei Maps on websites.
Thank you very much, very helpful.
More information like this, you can visit HUAWEI Developer Forum
Introduction
Hi everyone, this article provides example of HUAWEI Location Kit using the Cordova and Capacitor for Ionic mobile application. First of all, I would like to talk about the possibilities that HUAWEI Location Kit provides.
About HUAWEI Location Kit
Huawei Location Kit combines the GPS(Global Positioning System), Wi-Fi, and base station locations to help you quickly obtain precise user locations, build up global positioning capabilities, and reach a wide range of users around the globe. Currently, it provides the three main capabilities: Fused Location, Activity Identification, and Geofence.
Fused Location: Quickly obtain the device location based on the Wi-Fi, GPS and base station location data.
Activity Identification: Identifies user motion status through the acceleration sensor, cellular network information, and magnetometer, helping you adjust your app based on user behavior.
Geofence: Allows you to set an interested area through an API so that your app can receive a notification when a specified action such as leaving, entering, or lingering in the area occurs.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
HUAWEI Mobile Services(HMS): Location Kit Advantages
HUAWEI Mobile Services - Location Kit
Ionic Project Demo Using HMS Location Kit
Download the project from the link.
Ionic Project Sample Code
Download the Huawei Location Plugin from the link.
Cordova Huawei Location Plugin
Prerequisites
Install @iONiC/ionic-native/core
Code:
npm install [user=1329689]@iONiC[/user]-native/core --save
# or
# npm install
Ionic Native is a curated set of wrappers for Cordova plugins that make adding any native functionality you need to your Ionic mobile app easy.
Ionic Native wraps plugin callbacks in a Promise or Observable, providing a common interface for all plugins and making it easy to use plugins with Angular change detection.
Using Cordova
Add android platform to the project with using Cordova.
Code:
ionic cordova platform add android
Integrate Huawei Location Plugin to your project with using Cordova.
Code:
# ionic cordova plugin add PATH_TO_CORDOVA_LOCATION_PLUGIN
ionic cordova plugin add ../cordova-plugin-hms-location
Copy the “node_modules @hmscore/cordova-plugin-hms-location/ionic/dist/hms-location” folder from library to “node_modules @iONiC-native” folder under your Ionic project.
Run the project
Code:
ionic cordova run android
Using Capacitor
Integrate Huawei Location Plugin to your project with using npm.
Code:
# npm install <CORDOVA_LOCATION_PLUGIN_PATH>
npm install ../cordova-plugin-hms-location
NPM Package: @hmscore/cordova-plugin-hms-location
Add android platform to the project with using Capacitor.
Code:
ionic capacitor add android
Copy the “node_modules @hmscore/cordova-plugin-hms-location/ionic/dist/hms-location” folder from library to “node_modules @iONiC-native” folder under your Ionic project.
Run the project
Code:
ionic capacitor run android --device
Cordova HMS Location Kit APIs Overview
HMS Location Kit: Cordova APIs Tutorial
Import and Providers: location.module.ts
Code:
/**
* Copyright 2020 Huawei Technologies Co., Ltd.
*
* 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
*
* http://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.
*/
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from [user=1329689]@iONiC[/user]/angular';
import { LocationPageRoutingModule } from './location-routing.module';
import { LocationPage } from './location.page';
import {
HMSFusedLocation,
HMSActivityIdentification,
HMSGeofence,
LocationRequest,
PriorityConstants,
Events,
Activities,
ActivityConversions
} from [user=1329689]@iONiC[/user]-native/hms-location/ngx';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
LocationPageRoutingModule,
],
declarations: [LocationPage],
providers: [
HMSFusedLocation,
HMSActivityIdentification,
HMSGeofence
]
})
export class LocationPageModule {}
Using HMS Location Functions: location.page.ts
Code:
/**
* Copyright 2020 Huawei Technologies Co., Ltd.
*
* 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
*
* http://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.
*/
import { Component, OnInit, NgZone } from '@angular/core';
import { Platform } from [user=1329689]@iONiC[/user]/angular';
import {
HMSFusedLocation,
HMSActivityIdentification,
HMSGeofence,
LocationRequest,
PriorityConstants,
Events,
Activities,
ActivityConversions,
GeofenceRequestConstants
} from [user=1329689]@iONiC[/user]-native/hms-location/ngx';
import { HMSLocationKit } from [user=1329689]@iONiC[/user]-native/hms-location';
const asStr = (x) => JSON.stringify(x, null, 2);
@Component({
selector: 'app-location',
templateUrl: './location.page.html',
styleUrls: ['./location.page.scss'],
})
export class LocationPage implements OnInit {
locationHasPermissionResult = '';
locationRequestPermissionResult = '';
getLastLocationResult = '';
getLocationAvailabilityResult = '';
getLastLocationWithAddressResult = '';
flushLocationsResult = '';
checkLocationSettingsResult = '';
hasActivityPermissionResult = '';
createActivityConversionUpdatesResult = '';
registerActivityConversionUpdatesResult = '';
createActivityIdentificationUpdatesResult = '';
registerActivityIdentificationUpdatesResult = '';
createGeofenceListResult = '';
registerGeofenceUpdatesResult = '';
constructor(
private platform: Platform,
private fusedLocation: HMSFusedLocation,
private activityIdentification: HMSActivityIdentification,
private geofence: HMSGeofence,
private ngZone: NgZone
) {
this.platform.ready().then(() => {
console.log("Platform is ready.");
})
}
ngOnInit() {
HMSLocationKit.init();
}
//
// Fused Location
//
async runFunction(fn: () => any, field: string) {
console.log(`Updating ${field}`);
let result = "";
try {
result = asStr(await fn());
} catch (ex) {
result = asStr(ex);
}
console.log(result);
this[field] = result;
return field;
}
newLocationRequest(): LocationRequest {
return {
id: "locationRequest" + Math.random() * 10000,
priority: PriorityConstants.PRIORITY_HIGH_ACCURACY,
interval: 3,
numUpdates: 1,
fastestInterval: 1000.0,
expirationTime: 1000.0,
expirationTimeDuration: 1000.0,
smallestDisplacement: 0.0,
maxWaitTime: 1000.0,
needAddress: false,
language: "en",
countryCode: "en",
}
}
hasPermission() {
this.runFunction(() => this.fusedLocation.hasPermission(), 'locationHasPermissionResult');
}
requestLocationPermission() {
this.runFunction(() => this.fusedLocation.requestPermission(), 'locationRequestPermissionResult');
}
getLastLocation() {
this.runFunction(() => this.fusedLocation.getLastLocation(), 'getLastLocationResult');
}
getLocationAvailability() {
this.runFunction(() => this.fusedLocation.getLocationAvailability(), 'getLocationAvailabilityResult');
}
getLastLocationWithAddress() {
this.runFunction(() => this.fusedLocation.getLastLocationWithAddress(this.newLocationRequest()), 'getLastLocationWithAddressResult');
}
flushLocations() {
this.runFunction(() => this.fusedLocation.flushLocations(), 'flushLocationsResult');
}
checkLocationSettings() {
this.runFunction(() => this.fusedLocation.checkLocationSettings({
alwaysShow: true,
needBle: true,
locationRequests: []
}), 'checkLocationSettingsResult');
}
//
// Activity Identification
//
hasActivityPermission() {
this.runFunction(() => this.activityIdentification.hasPermission(), 'hasActivityPermissionResult');
}
requestAcitvityPermission() {
this.runFunction(() => this.activityIdentification.requestPermission(), 'locationRequestPermissionResult');
}
createActivityConversionUpdates() {
const activityConversions = [
// STILL
{
conversionType: ActivityConversions.ENTER_ACTIVITY_CONVERSION,
activityType: Activities.STILL
},
{
conversionType: ActivityConversions.EXIT_ACTIVITY_CONVERSION,
activityType: Activities.STILL
},
// ON FOOT
{
conversionType: ActivityConversions.ENTER_ACTIVITY_CONVERSION,
activityType: Activities.FOOT
},
{
conversionType: ActivityConversions.EXIT_ACTIVITY_CONVERSION,
activityType: Activities.FOOT
},
// RUNNING
{
conversionType: ActivityConversions.ENTER_ACTIVITY_CONVERSION,
activityType: Activities.RUNNING
},
{
conversionType: ActivityConversions.EXIT_ACTIVITY_CONVERSION,
activityType: Activities.RUNNING
}
];
this.runFunction(
() => this.activityIdentification.createActivityConversionUpdates(activityConversions),
'createActivityConversionUpdatesResult'
);
}
registerActivityConversionUpdates() {
window.registerHMSEvent(Events.ACTIVITY_CONVERSION_RESULT, (result) =>
this.ngZone.run(() => this.registerActivityConversionUpdatesResult = asStr(result)));
}
createActivityIdentificationUpdates() {
this.runFunction(
() => this.activityIdentification.createActivityIdentificationUpdates(2000),
'createActivityIdentificationUpdatesResult'
);
}
registerActivityIdentificationUpdates() {
window.registerHMSEvent(Events.ACTIVITY_IDENTIFICATION_RESULT, (result) =>
this.ngZone.run(() => this.registerActivityIdentificationUpdatesResult = asStr(result)));
}
//
// Geofences
//
createGeofenceList() {
const geofence1 = {
longitude: 42.0,
latitude: 29.0,
radius: 20.0,
uniqueId: 'geofence' + Math.random() * 10000,
conversions: 1,
validContinueTime: 10000.0,
dwellDelayTime: 10,
notificationInterval: 1,
};
const geofence2 = {
longitude: 41.0,
latitude: 27.0,
radius: 340.0,
uniqueId: 'geofence' + Math.random() * 10000,
conversions: 2,
validContinueTime: 1000.0,
dwellDelayTime: 10,
notificationInterval: 1,
};
this.runFunction(
() => this.geofence.createGeofenceList(
[geofence1, geofence2],
GeofenceRequestConstants.ENTER_INIT_CONVERSION,
GeofenceRequestConstants.COORDINATE_TYPE_WGS_84
),
'createGeofenceListResult'
);
}
registerGeofenceUpdates() {
window.registerHMSEvent(Events.GEOFENCE_RESULT, (result) =>
this.ngZone.run(() => this.registerGeofenceUpdatesResult = asStr(result)));
}
}
HMS Location Kit: location.page.html
Code:
<!--
Copyright 2020 Huawei Technologies Co., Ltd.
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
http://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.
-->
<ion-header>
<ion-toolbar>
<ion-title>HMSLocationKit Demo</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<h1>Fused Location</h1>
<ion-button (click)="hasPermission()">Check Permission</ion-button>
<ion-text>{{ locationHasPermissionResult }}</ion-text>
<ion-button (click)="requestLocationPermission()">Get Permission</ion-button>
<ion-text>{{ locationRequestPermissionResult }}</ion-text>
<ion-button (click)="getLocationAvailability()">Get Location Availability</ion-button>
<ion-text>{{ getLocationAvailabilityResult }}</ion-text>
<ion-button (click)="getLastLocation()">Get Last Location</ion-button>
<ion-text>{{ getLastLocationResult }}</ion-text>
<ion-button (click)="getLastLocationWithAddress()">Get Last Location With Address</ion-button>
<ion-text>{{ getLastLocationWithAddressResult }}</ion-text>
<ion-button (click)="flushLocations()">Flush Locations</ion-button>
<ion-text>{{ flushLocationsResult }}</ion-text>
<ion-button (click)="checkLocationSettings()">Check Location Settings</ion-button>
<ion-text>{{ checkLocationSettingsResult }}</ion-text>
<h1>Activity Identification</h1>
<ion-button (click)="hasActivityPermission()">Check Permission</ion-button>
<ion-text>{{ hasActivityPermissionResult }}</ion-text>
<ion-button (click)="requestAcitvityPermission()">Get Permission</ion-button>
<ion-text>{{ hasPermissionResult }}</ion-text>
<ion-button (click)="createActivityConversionUpdates()">Create Activity Conversion Updates</ion-button>
<ion-text>{{ createActivityConversionUpdatesResult }}</ion-text>
<ion-button (click)="registerActivityConversionUpdates()">Register Activity Conversion Updates</ion-button>
<ion-text>{{ registerActivityConversionUpdatesResult }}</ion-text>
<ion-button (click)="createActivityIdentificationUpdates()">Create Activity Identification Updates</ion-button>
<ion-text>{{ createActivityIdentificationUpdatesResult }}</ion-text>
<ion-button (click)="registerActivityIdentificationUpdates()">Register Activity Identification Updates</ion-button>
<ion-text>{{ registerActivityIdentificationUpdatesResult }}</ion-text>
<h1>Geofences</h1>
<ion-button (click)="createGeofenceList()">Create Geofence List</ion-button>
<ion-text>{{ createGeofenceListResult }}</ion-text>
<ion-button (click)="registerGeofenceUpdates()">Register Geofence Updates</ion-button>
<ion-text>{{ registerGeofenceUpdatesResult }}</ion-text>
</ion-content>
Conclusion
In this article, I explained what is the HUAWEI Location Kit, what capabilities it provides, and how to use it in the Ionic mobile application. If you have any questions, you can write the question in the comment section.
Github link: https://github.com/HMS-Core/hms-cordova-plugin/tree/master/cordova-plugin-hms-location
More information like this, you can visit HUAWEI Developer Forum
Introduction
Hi everyone, this article provides example of HUAWEI Location Kit using the Cordova and Capacitor for Ionic mobile application. First of all, I would like to talk about the possibilities that HUAWEI Location Kit provides.
About HUAWEI Location Kit
Huawei Location Kit combines the GPS(Global Positioning System), Wi-Fi, and base station locations to help you quickly obtain precise user locations, build up global positioning capabilities, and reach a wide range of users around the globe. Currently, it provides the three main capabilities: Fused Location, Activity Identification, and Geofence.
Fused Location: Quickly obtain the device location based on the Wi-Fi, GPS and base station location data.
Activity Identification: Identifies user motion status through the acceleration sensor, cellular network information, and magnetometer, helping you adjust your app based on user behavior.
Geofence: Allows you to set an interested area through an API so that your app can receive a notification when a specified action such as leaving, entering, or lingering in the area occurs.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
HUAWEI Mobile Services(HMS): Location Kit Advantages
HUAWEI Mobile Services - Location Kit
Ionic Project Demo Using HMS Location Kit
Download the project from the link.
Ionic Project Sample Code
Download the Huawei Location Plugin from the link.
Cordova Huawei Location Plugin
Prerequisites
Install @iONiC/ionic-native/core
Code:
npm install [user=1329689]@iONiC[/user]-native/core --save
# or
# npm install
Ionic Native is a curated set of wrappers for Cordova plugins that make adding any native functionality you need to your Ionic mobile app easy.
Ionic Native wraps plugin callbacks in a Promise or Observable, providing a common interface for all plugins and making it easy to use plugins with Angular change detection.
Using Cordova
Add android platform to the project with using Cordova.
Code:
ionic cordova platform add android
Integrate Huawei Location Plugin to your project with using Cordova.
Code:
# ionic cordova plugin add PATH_TO_CORDOVA_LOCATION_PLUGIN
ionic cordova plugin add ../cordova-plugin-hms-location
Copy the “node_modules @hmscore/cordova-plugin-hms-location/ionic/dist/hms-location” folder from library to “node_modules @iONiC-native” folder under your Ionic project.
Run the project
Code:
ionic cordova run android
Using Capacitor
Integrate Huawei Location Plugin to your project with using npm.
Code:
# npm install <CORDOVA_LOCATION_PLUGIN_PATH>
npm install ../cordova-plugin-hms-location
NPM Package: @hmscore/cordova-plugin-hms-location
Add android platform to the project with using Capacitor.
Code:
ionic capacitor add android
Copy the “node_modules @hmscore/cordova-plugin-hms-location/ionic/dist/hms-location” folder from library to “node_modules @iONiC-native” folder under your Ionic project.
Run the project
Code:
ionic capacitor run android --device
Cordova HMS Location Kit APIs Overview
HMS Location Kit: Cordova APIs Tutorial
Import and Providers: location.module.ts
Code:
/**
* Copyright 2020 Huawei Technologies Co., Ltd.
*
* 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
*
* http://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.
*/
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from [user=1329689]@iONiC[/user]/angular';
import { LocationPageRoutingModule } from './location-routing.module';
import { LocationPage } from './location.page';
import {
HMSFusedLocation,
HMSActivityIdentification,
HMSGeofence,
LocationRequest,
PriorityConstants,
Events,
Activities,
ActivityConversions
} from [user=1329689]@iONiC[/user]-native/hms-location/ngx';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
LocationPageRoutingModule,
],
declarations: [LocationPage],
providers: [
HMSFusedLocation,
HMSActivityIdentification,
HMSGeofence
]
})
export class LocationPageModule {}
Using HMS Location Functions: location.page.ts
Code:
/**
* Copyright 2020 Huawei Technologies Co., Ltd.
*
* 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
*
* http://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.
*/
import { Component, OnInit, NgZone } from '@angular/core';
import { Platform } from [user=1329689]@iONiC[/user]/angular';
import {
HMSFusedLocation,
HMSActivityIdentification,
HMSGeofence,
LocationRequest,
PriorityConstants,
Events,
Activities,
ActivityConversions,
GeofenceRequestConstants
} from [user=1329689]@iONiC[/user]-native/hms-location/ngx';
import { HMSLocationKit } from [user=1329689]@iONiC[/user]-native/hms-location';
const asStr = (x) => JSON.stringify(x, null, 2);
@Component({
selector: 'app-location',
templateUrl: './location.page.html',
styleUrls: ['./location.page.scss'],
})
export class LocationPage implements OnInit {
locationHasPermissionResult = '';
locationRequestPermissionResult = '';
getLastLocationResult = '';
getLocationAvailabilityResult = '';
getLastLocationWithAddressResult = '';
flushLocationsResult = '';
checkLocationSettingsResult = '';
hasActivityPermissionResult = '';
createActivityConversionUpdatesResult = '';
registerActivityConversionUpdatesResult = '';
createActivityIdentificationUpdatesResult = '';
registerActivityIdentificationUpdatesResult = '';
createGeofenceListResult = '';
registerGeofenceUpdatesResult = '';
constructor(
private platform: Platform,
private fusedLocation: HMSFusedLocation,
private activityIdentification: HMSActivityIdentification,
private geofence: HMSGeofence,
private ngZone: NgZone
) {
this.platform.ready().then(() => {
console.log("Platform is ready.");
})
}
ngOnInit() {
HMSLocationKit.init();
}
//
// Fused Location
//
async runFunction(fn: () => any, field: string) {
console.log(`Updating ${field}`);
let result = "";
try {
result = asStr(await fn());
} catch (ex) {
result = asStr(ex);
}
console.log(result);
this[field] = result;
return field;
}
newLocationRequest(): LocationRequest {
return {
id: "locationRequest" + Math.random() * 10000,
priority: PriorityConstants.PRIORITY_HIGH_ACCURACY,
interval: 3,
numUpdates: 1,
fastestInterval: 1000.0,
expirationTime: 1000.0,
expirationTimeDuration: 1000.0,
smallestDisplacement: 0.0,
maxWaitTime: 1000.0,
needAddress: false,
language: "en",
countryCode: "en",
}
}
hasPermission() {
this.runFunction(() => this.fusedLocation.hasPermission(), 'locationHasPermissionResult');
}
requestLocationPermission() {
this.runFunction(() => this.fusedLocation.requestPermission(), 'locationRequestPermissionResult');
}
getLastLocation() {
this.runFunction(() => this.fusedLocation.getLastLocation(), 'getLastLocationResult');
}
getLocationAvailability() {
this.runFunction(() => this.fusedLocation.getLocationAvailability(), 'getLocationAvailabilityResult');
}
getLastLocationWithAddress() {
this.runFunction(() => this.fusedLocation.getLastLocationWithAddress(this.newLocationRequest()), 'getLastLocationWithAddressResult');
}
flushLocations() {
this.runFunction(() => this.fusedLocation.flushLocations(), 'flushLocationsResult');
}
checkLocationSettings() {
this.runFunction(() => this.fusedLocation.checkLocationSettings({
alwaysShow: true,
needBle: true,
locationRequests: []
}), 'checkLocationSettingsResult');
}
//
// Activity Identification
//
hasActivityPermission() {
this.runFunction(() => this.activityIdentification.hasPermission(), 'hasActivityPermissionResult');
}
requestAcitvityPermission() {
this.runFunction(() => this.activityIdentification.requestPermission(), 'locationRequestPermissionResult');
}
createActivityConversionUpdates() {
const activityConversions = [
// STILL
{
conversionType: ActivityConversions.ENTER_ACTIVITY_CONVERSION,
activityType: Activities.STILL
},
{
conversionType: ActivityConversions.EXIT_ACTIVITY_CONVERSION,
activityType: Activities.STILL
},
// ON FOOT
{
conversionType: ActivityConversions.ENTER_ACTIVITY_CONVERSION,
activityType: Activities.FOOT
},
{
conversionType: ActivityConversions.EXIT_ACTIVITY_CONVERSION,
activityType: Activities.FOOT
},
// RUNNING
{
conversionType: ActivityConversions.ENTER_ACTIVITY_CONVERSION,
activityType: Activities.RUNNING
},
{
conversionType: ActivityConversions.EXIT_ACTIVITY_CONVERSION,
activityType: Activities.RUNNING
}
];
this.runFunction(
() => this.activityIdentification.createActivityConversionUpdates(activityConversions),
'createActivityConversionUpdatesResult'
);
}
registerActivityConversionUpdates() {
window.registerHMSEvent(Events.ACTIVITY_CONVERSION_RESULT, (result) =>
this.ngZone.run(() => this.registerActivityConversionUpdatesResult = asStr(result)));
}
createActivityIdentificationUpdates() {
this.runFunction(
() => this.activityIdentification.createActivityIdentificationUpdates(2000),
'createActivityIdentificationUpdatesResult'
);
}
registerActivityIdentificationUpdates() {
window.registerHMSEvent(Events.ACTIVITY_IDENTIFICATION_RESULT, (result) =>
this.ngZone.run(() => this.registerActivityIdentificationUpdatesResult = asStr(result)));
}
//
// Geofences
//
createGeofenceList() {
const geofence1 = {
longitude: 42.0,
latitude: 29.0,
radius: 20.0,
uniqueId: 'geofence' + Math.random() * 10000,
conversions: 1,
validContinueTime: 10000.0,
dwellDelayTime: 10,
notificationInterval: 1,
};
const geofence2 = {
longitude: 41.0,
latitude: 27.0,
radius: 340.0,
uniqueId: 'geofence' + Math.random() * 10000,
conversions: 2,
validContinueTime: 1000.0,
dwellDelayTime: 10,
notificationInterval: 1,
};
this.runFunction(
() => this.geofence.createGeofenceList(
[geofence1, geofence2],
GeofenceRequestConstants.ENTER_INIT_CONVERSION,
GeofenceRequestConstants.COORDINATE_TYPE_WGS_84
),
'createGeofenceListResult'
);
}
registerGeofenceUpdates() {
window.registerHMSEvent(Events.GEOFENCE_RESULT, (result) =>
this.ngZone.run(() => this.registerGeofenceUpdatesResult = asStr(result)));
}
}
HMS Location Kit: location.page.html
Code:
<!--
Copyright 2020 Huawei Technologies Co., Ltd.
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
http://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.
-->
<ion-header>
<ion-toolbar>
<ion-title>HMSLocationKit Demo</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<h1>Fused Location</h1>
<ion-button (click)="hasPermission()">Check Permission</ion-button>
<ion-text>{{ locationHasPermissionResult }}</ion-text>
<ion-button (click)="requestLocationPermission()">Get Permission</ion-button>
<ion-text>{{ locationRequestPermissionResult }}</ion-text>
<ion-button (click)="getLocationAvailability()">Get Location Availability</ion-button>
<ion-text>{{ getLocationAvailabilityResult }}</ion-text>
<ion-button (click)="getLastLocation()">Get Last Location</ion-button>
<ion-text>{{ getLastLocationResult }}</ion-text>
<ion-button (click)="getLastLocationWithAddress()">Get Last Location With Address</ion-button>
<ion-text>{{ getLastLocationWithAddressResult }}</ion-text>
<ion-button (click)="flushLocations()">Flush Locations</ion-button>
<ion-text>{{ flushLocationsResult }}</ion-text>
<ion-button (click)="checkLocationSettings()">Check Location Settings</ion-button>
<ion-text>{{ checkLocationSettingsResult }}</ion-text>
<h1>Activity Identification</h1>
<ion-button (click)="hasActivityPermission()">Check Permission</ion-button>
<ion-text>{{ hasActivityPermissionResult }}</ion-text>
<ion-button (click)="requestAcitvityPermission()">Get Permission</ion-button>
<ion-text>{{ hasPermissionResult }}</ion-text>
<ion-button (click)="createActivityConversionUpdates()">Create Activity Conversion Updates</ion-button>
<ion-text>{{ createActivityConversionUpdatesResult }}</ion-text>
<ion-button (click)="registerActivityConversionUpdates()">Register Activity Conversion Updates</ion-button>
<ion-text>{{ registerActivityConversionUpdatesResult }}</ion-text>
<ion-button (click)="createActivityIdentificationUpdates()">Create Activity Identification Updates</ion-button>
<ion-text>{{ createActivityIdentificationUpdatesResult }}</ion-text>
<ion-button (click)="registerActivityIdentificationUpdates()">Register Activity Identification Updates</ion-button>
<ion-text>{{ registerActivityIdentificationUpdatesResult }}</ion-text>
<h1>Geofences</h1>
<ion-button (click)="createGeofenceList()">Create Geofence List</ion-button>
<ion-text>{{ createGeofenceListResult }}</ion-text>
<ion-button (click)="registerGeofenceUpdates()">Register Geofence Updates</ion-button>
<ion-text>{{ registerGeofenceUpdatesResult }}</ion-text>
</ion-content>
Conclusion
In this article, I explained what is the HUAWEI Location Kit, what capabilities it provides, and how to use it in the Ionic mobile application. If you have any questions, you can write the question in the comment section.
Github link: https://github.com/HMS-Core/hms-cordova-plugin/tree/master/cordova-plugin-hms-location
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Introduction
In this series of article, we will learn about Navigation Glove application and also we will learn about integration of the Huawei Direction API in Navigation Glove IoT application. We will learn how to draw polyline on the map.
If you are new to this series of articles, follow my previous articles.
Beginner: Integration of Huawei Account kit in Navigation Glove IoT application Using Kotlin - Part 1
Beginner: Integration of Huawei Map kit in Navigation Glove IoT application Using Kotlin - Part 2
Beginner: Integration of Huawei Site kit in Navigation Glove IoT application Using Kotlin - Part 3
What is Direction API?
Huawei Map Kit provides a set of HTTP/HTTPS APIs, which you can use to build map data functions like route planning, Static map, Raster map.
Directions API is a set of HTTPS-based APIs it is used to plans routes. The direction API returns data in JSON format. You can parse and draw route on the map.
It has following types of routes:
Walking: You can plan route max 150 kilometers.
Cycling: You can plan route max 100 kilometers.
Driving: Driving route gives some following functions:
1. It returns 3 routes for request.
2. It supports 5 waypoints.
3. It gives real time traffic condition.
Using Rest services we are integrating the following.
Direction API
Prerequisite
AppGallery Account
Android Studio 3.X
SDK Platform 19 or later
Gradle 4.6 or later
HMS Core (APK) 4.0.0.300 or later
Huawei Phone EMUI 3.0 or later
Non-Huawei Phone Android 4.4 or later
Service integration on AppGallery.
1. We need to register as a developer account in AppGallery Connect.
2. Create an app by referring to Creating a Project and Creating an App in the Project.
3. Set the data storage location based on the current location.
4. Enabling Map Kit Service on AppGallery Connect.
5. Generating a Signing Certificate Fingerprint.
6. Configuring the Signing Certificate Fingerprint.
7. Get your agconnect-services.json file to the app root directory.
Client development
1. Create android project in android studio IDE.
2. Add the maven URL inside the repositories of buildscript and allprojects respectively (project level build.gradle file).
Code:
maven { url 'https://developer.huawei.com/repo/' }
3. Add the classpath inside the dependency section of the project level build.gradle file.
Code:
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
4. Add the plugin in the app-level build.gradle file.
Code:
apply plugin: 'com.huawei.agconnect'
5. Add the below library in the app-level build.gradle file dependencies section.
Code:
implementation 'com.huawei.hms:maps:4.0.0.302'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.retrofit2:retrofit:2.7.2'
implementation 'com.squareup.retrofit2:converter-gson:2.7.2'
6. Add all the below permissions in the AndroidManifest.xml.
XML:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
7. Sync the project.
By now user has select the Source location and Destination Location. And also we have added marker on the map.
Direction API Code
For direction API, we are using retrofit library to get the direction API.
So first let’s see what will be the Request and what will be response. And also end point.
Method Type: POST
URL:
https://mapapi.cloud.huawei.com/mapApi/v1/routeService/driving?key=
API key
Note: Replace API key with you project API key
Data Format: Request: Content-Type: application/json
Response: Content-Type: application/json
Request Example
POST https://mapapi.cloud.huawei.com/mapApi/v1/routeService/driving?key=API key HTTP/1.1
Content-Type: application/json
Accept: application/json
JSON:
{
"destination":{
"lat":12.982126,
"lng":77.533103
},
"origin":{
"lat":12.9702763,
"lng":77.5373127
}
}
Response
HTTP/1.1 200 OK
Content-type: application/json
Just check it in the Postman or RestClient or any other tools which give response for HTTP request
Now let us set up
Step 1: Create Const class.
package com.huawei.navigationglove.api
object Const {
const val BASE_URL = "https://mapapi.cloud.huawei.com/mapApi/v1/"
}Copy codeCopy code
Step 2: Create ApiClient class.
Java:
package com.huawei.navigationglove.api
import android.content.Context
import android.text.TextUtils
import okhttp3.Interceptor
import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.OkHttpClient
import retrofit2.converter.gson.GsonConverterFactory
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import okhttp3.HttpUrl
import okhttp3.Request
import retrofit2.Retrofit
import java.util.concurrent.TimeUnit
object ApiClient {
private val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(Const.BASE_URL)
.client(setInterceptors())
.addConverterFactory(GsonConverterFactory.create())
.build()
private fun setInterceptors(): OkHttpClient {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BODY
return OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.addInterceptor { chain ->
val url: HttpUrl = chain.request().url.newBuilder()
.addQueryParameter(
"key",
"ADD_YOUR_API_KEY_HERE"
)
.build()
val request = chain.request().newBuilder()
.header("Content-Type", "application/json")
.url(url)
.build()
chain.proceed(request)
}
.addInterceptor(logger)
.build()
}
fun createApiService(): ApiService {
return ApiClient.retrofit.create(ApiService::class.java)
}
fun <S> createService(serviceClass: Class<S>?): S {
return retrofit.create(serviceClass)
}
}
Step 3: Create the ApiService interface.
Java:
package com.huawei.navigationglove.api
import com.huawei.navigationglove.api.request.DirectionRequest
import com.huawei.navigationglove.api.response.DirectionResponse
import io.reactivex.Single
import retrofit2.Call
import retrofit2.http.*
interface ApiService {
@POST("routeService/{type}")
fun getDirectionsWithType(
@Path(value = "type",encoded = true) type : String,
@Body directionRequest: DirectionRequest
): Call<DirectionResponse>
}Copy codeCopy code
Step 4: Create TypeOfDirection Enum to get routes for driving/walking/cycling
package com.huawei.navigationglove.api
enum class TypeOfDirection(val type: String) {
WALKING("walking"),
BICYCLING("bicycling"),
DRIVING("driving")
}
Before creating request and response class, let us add one plugin to convert from JSON to Kotlin data classes
Choose File > Setting > Plugin
Step 5: Now we need to create Request kotlin classes.
Origin.kt
Java:
package com.huawei.navigationglove.api.request
import com.google.gson.annotations.SerializedName
data class Origin(@SerializedName("lng")
val lng: Double = 0.0,
@SerializedName("lat")
val lat: Double = 0.0)
Destination.kt
Java:
package com.huawei.navigationglove.api.request
import com.google.gson.annotations.SerializedName
data class Destination(@SerializedName("lng")
val lng: Double = 0.0,
@SerializedName("lat")
val lat: Double = 0.0)
DirectionRequest.kt
Java:
package com.huawei.navigationglove.api.request
import com.google.gson.annotations.SerializedName
data class DirectionRequest(@SerializedName("origin")
val origin: Origin,
@SerializedName("destination")
val destination: Destination)
Step 6: Now create Response Class. Same as the Request class created.
DirectionResponse.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class DirectionResponse(@SerializedName("routes")
val routes: List<RoutesItem>?,
@SerializedName("returnCode")
val returnCode: String = "",
@SerializedName("returnDesc")
val returnDesc: String = "")
Bounds.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class Bounds(@SerializedName("southwest")
val southwest: Southwest,
@SerializedName("northeast")
val northeast: Northeast)
EndLocation.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class EndLocation(@SerializedName("lng")
val lng: Double = 0.0,
@SerializedName("lat")
val lat: Double = 0.0)
Northeast.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class Northeast(@SerializedName("lng")
val lng: Double = 0.0,
@SerializedName("lat")
val lat: Double = 0.0)
PathItems.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class PathsItem(@SerializedName("duration")
val duration: Double = 0.0,
@SerializedName("durationText")
val durationText: String = "",
@SerializedName("durationInTrafficText")
val durationInTrafficText: String = "",
@SerializedName("durationInTraffic")
val durationInTraffic: Double = 0.0,
@SerializedName("distance")
val distance: Double = 0.0,
@SerializedName("startLocation")
val startLocation: StartLocation,
@SerializedName("startAddress")
val startAddress: String = "",
@SerializedName("distanceText")
val distanceText: String = "",
@SerializedName("steps")
val steps: List<StepsItem>?,
@SerializedName("endLocation")
val endLocation: EndLocation,
@SerializedName("endAddress")
val endAddress: String = "")
PolylineItems.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class PolylineItem(@SerializedName("lng")
val lng: Double = 0.0,
@SerializedName("lat")
val lat: Double = 0.0)
RoutesItem.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class RoutesItem(@SerializedName("trafficLightNum")
val trafficLightNum: Int = 0,
@SerializedName("dstInDiffTimeZone")
val dstInDiffTimeZone: Int = 0,
@SerializedName("crossCountry")
val crossCountry: Int = 0,
@SerializedName("hasRestrictedRoad")
val hasRestrictedRoad: Int = 0,
@SerializedName("hasRoughRoad")
val hasRoughRoad: Int = 0,
@SerializedName("hasTrafficLight")
val hasTrafficLight: Int = 0,
@SerializedName("crossMultiCountries")
val crossMultiCountries: Int = 0,
@SerializedName("dstInRestrictedArea")
val dstInRestrictedArea: Int = 0,
@SerializedName("overviewPolyline")
val overviewPolyline: String = "",
@SerializedName("paths")
val paths: List<PathsItem>?,
@SerializedName("bounds")
val bounds: Bounds,
@SerializedName("hasTolls")
val hasTolls: Int = 0,
@SerializedName("hasFerry")
val hasFerry: Int = 0)
Southwest.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class Southwest(@SerializedName("lng")
val lng: Double = 0.0,
@SerializedName("lat")
val lat: Double = 0.0)
StartLocation.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class StartLocation(@SerializedName("lng")
val lng: Double = 0.0,
@SerializedName("lat")
val lat: Double = 0.0)
StepsItem.kt
Java:
package com.huawei.navigationglove.api.response
import com.google.gson.annotations.SerializedName
data class StepsItem(@SerializedName("duration")
val duration: Double = 0.0,
@SerializedName("orientation")
val orientation: Int = 0,
@SerializedName("durationText")
val durationText: String = "",
@SerializedName("distance")
val distance: Double = 0.0,
@SerializedName("startLocation")
val startLocation: StartLocation,
@SerializedName("instruction")
val instruction: String = "",
@SerializedName("action")
val action: String = "",
@SerializedName("distanceText")
val distanceText: String = "",
@SerializedName("roadName")
val roadName: String = "",
@SerializedName("endLocation")
val endLocation: EndLocation,
@SerializedName("polyline")
val polyline: List<PolylineItem>?)=
Now everything set now call the API.
If your question about originReq and destinationReq follow my previous article. These two request has been created when user selects the source location and destination location.
Java:
navigate.setOnClickListener {
val directionRequest = DirectionRequest(originReq!!, destinationReq!!)
getDirection(directionType, directionRequest)
}Copy codeCopy code
private fun getDirection(directionType: String, directionRequest: DirectionRequest) {
ApiClient.createApiService()
.getDirectionsWithType(directionType, directionRequest)
.enqueue(object : Callback<DirectionResponse> {
override fun onFailure(call: Call<DirectionResponse>, t: Throwable) {
Toast.makeText(
[email protected],
"Failure" + t.localizedMessage + "\n" + t.message,
Toast.LENGTH_SHORT
).show()
}
override fun onResponse(
call: Call<DirectionResponse>,
response: Response<DirectionResponse>
) {
if (response.isSuccessful) {
response.body()?.let {
it.routes?.get(0)?.paths?.get(0)?.let { it1 -> addPolyLines(it1) }
Toast.makeText([email protected], "Success", Toast.LENGTH_SHORT)
.show()
}
//startActivity(Intent([email protected], MapsActivity::class.java))
}
}
})
}
Adding polyline
Java:
var polyLine: Polyline? = null
private fun addPolyLines(path: PathsItem) {
if (polyLine != null) {
polyLine!!.remove()
}
val options = PolylineOptions()
options.add(LatLng(path.startLocation.lat, path.startLocation.lng))
path.steps!!.forEach {
it.polyline!!.forEach { it1 ->
options.add(LatLng(it1.lat, it1.lng))
}
}
options.add(LatLng(path.endLocation.lat, path.endLocation.lng))
options.color(Color.BLACK)
options.width(6f)
polyLine = hMap!!.addPolyline(options)
}
Now let us see the full code.
HomeScreenActivity.kt
Java:
package com.huawei.navigationglove.ui
import android.content.Intent
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import com.huawei.hms.maps.*
import com.huawei.hms.maps.model.*
import com.huawei.hms.site.api.model.Site
import com.huawei.hms.site.widget.SearchIntent
import com.huawei.navigationglove.R
import com.huawei.navigationglove.api.ApiClient
import com.huawei.navigationglove.api.TypeOfDirection
import com.huawei.navigationglove.api.request.Destination
import com.huawei.navigationglove.api.request.DirectionRequest
import com.huawei.navigationglove.api.request.Origin
import com.huawei.navigationglove.api.response.DirectionResponse
import com.huawei.navigationglove.api.response.PathsItem
import kotlinx.android.synthetic.main.activity_home_screen.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.net.URLEncoder
import android.widget.RadioButton
class HomeScreenActivity : AppCompatActivity(), OnMapReadyCallback {
private val TAG = HomeScreenActivity::class.java.name
private val API_KEY: String =
"Add your API Key here"
private var originReq: Origin? = null
private var destinationReq: Destination? = null
var hMap: HuaweiMap? = null
private val searchIntent = SearchIntent()
private var mMarker: Marker? = null
private var mCircle: Circle? = null
private var directionType: String = TypeOfDirection.WALKING.type
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home_screen)
val mSupportMapFragment: SupportMapFragment? =
supportFragmentManager.findFragmentById(R.id.mapfragment_mapfragmentdemo) as SupportMapFragment?
mSupportMapFragment!!.getMapAsync(this)
//Site kit
val apiKey = URLEncoder.encode(
API_KEY,
"utf-8"
)
searchIntent.setApiKey(apiKey)
//Select source location
start.setOnClickListener {
//You can try the below one for older method
//selectSourceLocation()
/*val intent = searchIntent.getIntent(this)
startActivityForResult(intent, SearchIntent.SEARCH_REQUEST_CODE)*/
selectSourceLocation()
}
//Select Destination Location
destination.setOnClickListener {
selectDestinationLocation()
}
navigate.setOnClickListener {
val directionRequest = DirectionRequest(originReq!!, destinationReq!!)
getDirection(directionType, directionRequest)
}
directionTypeGroup.setOnCheckedChangeListener { group, checkedId -> // checkedId is the RadioButton selected
val directionTypeRadioButton = findViewById<View>(checkedId) as RadioButton
when (directionTypeRadioButton.text.toString().toLowerCase()) {
"walking" -> directionType = TypeOfDirection.WALKING.type
"driving" -> directionType = TypeOfDirection.DRIVING.type
"cycling" -> directionType = TypeOfDirection.BICYCLING.type
}
Toast.makeText(applicationContext, directionTypeRadioButton.text, Toast.LENGTH_SHORT)
.show()
}
}
private fun selectSourceLocation() {
val intent = searchIntent.getIntent(this)
sourceLocationLauncher.launch(intent)
}
private var sourceLocationLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val data: Intent? = result.data
if (data != null) {
if (SearchIntent.isSuccess(result.resultCode)) {
val site: Site = searchIntent.getSiteFromIntent(data)
start.text = site.getName()
originReq = Origin(site.location.lng, site.location.lat)
//originReq = Origin(-4.66529, 54.216608)
//Toast.makeText(application, site.getName(), Toast.LENGTH_LONG).show()
val build = CameraPosition.Builder()
.target(LatLng(site.location.lat, site.location.lng)).zoom(16f).build()
val cameraUpdate = CameraUpdateFactory.newCameraPosition(build)
hMap!!.animateCamera(cameraUpdate)
//Setting max and min zoom
//hMap!!.setMaxZoomPreference(10f)
//hMap!!.setMinZoomPreference(1f)
// Marker can be add by HuaweiMap
mMarker = hMap!!.addMarker(
MarkerOptions().position(LatLng(site.location.lat, site.location.lng))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_baseline_location_on_24))
.clusterable(true)
)
mMarker?.showInfoWindow()
// circle can be added to HuaweiMap
/*mCircle = hMap!!.addCircle(
CircleOptions().center(LatLng(28.7041, 77.1025)).radius(45000.0).fillColor(
Color.GREEN))
mCircle?.fillColor = Color.TRANSPARENT*/
}
} else {
Toast.makeText(application, "Unable to find the data", Toast.LENGTH_LONG).show()
}
}
private fun selectDestinationLocation() {
val intent = searchIntent.getIntent(this)
destinationLocationLauncher.launch(intent)
}
private var destinationLocationLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val data: Intent? = result.data
if (data != null) {
if (SearchIntent.isSuccess(result.resultCode)) {
val site: Site = searchIntent.getSiteFromIntent(data)
destination.text = site.getName()
destinationReq = Destination(site.location.lng, site.location.lat)
//destinationReq = Destination(-4.66552, 54.2166)
val build = CameraPosition.Builder()
.target(LatLng(site.location.lat, site.location.lng)).zoom(16f).build()
val cameraUpdate = CameraUpdateFactory.newCameraPosition(build)
hMap!!.animateCamera(cameraUpdate)
mMarker = hMap!!.addMarker(
MarkerOptions().position(LatLng(site.location.lat, site.location.lng))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_baseline_destination_location_on_24))
.clusterable(true)
)
mMarker?.showInfoWindow()
}
} else {
Toast.makeText(application, "Unable to find the data", Toast.LENGTH_LONG).show()
}
}
override fun onMapReady(huaweiMap: HuaweiMap) {
Log.d(TAG, "onMapReady: ")
hMap = huaweiMap
hMap!!.mapType = HuaweiMap.MAP_TYPE_NORMAL
hMap!!.uiSettings.isMyLocationButtonEnabled = true
// Add a polyline (mPolyline) to a map.
/* val mPolyline = hMap!!.addPolyline(
PolylineOptions().add(
LatLng(47.893478, 2.334595),
LatLng(48.993478, 3.434595),
LatLng(48.693478, 2.134595),
LatLng(48.793478, 2.334595)
)
)
// Set the color of the polyline (mPolyline) to red.
mPolyline.color = Color.RED
// Set the width of the polyline (mPolyline) to 10 pixels.
mPolyline.width = 10f*/
//Adding Polygon
/*hMap!!.addPolygon(PolygonOptions().addAll(createRectangle(LatLng(12.9716, 77.5946), 0.1, 0.1))
.fillColor(Color.GREEN)
.strokeColor(Color.BLACK))*/
//Adding Circle on the Map
/*hMap!!.addCircle(CircleOptions()
.center(LatLng(12.9716, 77.5946))
.radius(500.0)
.fillColor(Color.GREEN))*/
}
private fun createRectangle(
center: LatLng,
halfWidth: Double,
halfHeight: Double
): List<LatLng> {
return listOf(
LatLng(center.latitude - halfHeight, center.longitude - halfWidth),
LatLng(center.latitude - halfHeight, center.longitude + halfWidth),
LatLng(center.latitude + halfHeight, center.longitude + halfWidth),
LatLng(center.latitude + halfHeight, center.longitude - halfWidth)
)
}
private fun getDirection(directionType: String, directionRequest: DirectionRequest) {
ApiClient.createApiService()
.getDirectionsWithType(directionType, directionRequest)
.enqueue(object : Callback<DirectionResponse> {
override fun onFailure(call: Call<DirectionResponse>, t: Throwable) {
Toast.makeText(
[email protected],
"Failure" + t.localizedMessage + "\n" + t.message,
Toast.LENGTH_SHORT
).show()
}
override fun onResponse(
call: Call<DirectionResponse>,
response: Response<DirectionResponse>
) {
if (response.isSuccessful) {
response.body()?.let {
it.routes?.get(0)?.paths?.get(0)?.let { it1 -> addPolyLines(it1) }
Toast.makeText([email protected], "Success", Toast.LENGTH_SHORT)
.show()
}
//startActivity(Intent([email protected], MapsActivity::class.java))
}
}
})
}
var polyLine: Polyline? = null
private fun addPolyLines(path: PathsItem) {
if (polyLine != null) {
polyLine!!.remove()
}
val options = PolylineOptions()
options.add(LatLng(path.startLocation.lat, path.startLocation.lng))
path.steps!!.forEach {
it.polyline!!.forEach { it1 ->
options.add(LatLng(it1.lat, it1.lng))
}
}
options.add(LatLng(path.endLocation.lat, path.endLocation.lng))
options.color(Color.BLACK)
options.width(6f)
polyLine = hMap!!.addPolyline(options)
}
}
activity_home_screen.xml
XML:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:map="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=".ui.HomeScreenActivity">
<fragment
android:id="@+id/mapfragment_mapfragmentdemo"
class="com.huawei.hms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:cameraTargetLat="12.9716"
map:cameraTargetLng="77.5946"
map:cameraZoom="10" />
<androidx.cardview.widget.CardView
android:id="@+id/cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:elevation="100dp"
app:cardBackgroundColor="@android:color/white"
app:cardCornerRadius="8dp">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/locationLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="9.5"
android:background="@color/white"
android:orientation="vertical"
android:padding="20dp">
<TextView
android:id="@+id/start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp"
android:background="@android:color/transparent"
android:hint="Choose a starting point..."
android:maxLines="1"
android:textColor="@color/purple_200"
android:textSize="18sp" />
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_marginTop="5dp"
android:layout_marginRight="50dp"
android:layout_marginBottom="5dp"
android:background="@drawable/dottet_line" />
<TextView
android:id="@+id/destination"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:hint="Choose a destination..."
android:maxLines="1"
android:textSize="18sp"
android:textColor="@color/purple_200"/>
</LinearLayout>
<ImageView
android:id="@+id/navigate"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center"
android:layout_marginRight="10dp"
android:layout_weight="0.5"
android:src="@drawable/ic_baseline_send_24" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="@drawable/dottet_line" />
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center"
android:id="@+id/directionTypeGroup"
android:orientation="horizontal">
<RadioButton
android:id="@+id/walking"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:checked="true"
android:text="Walking" />
<RadioButton
android:id="@+id/driving"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:text="Driving" />
<RadioButton
android:id="@+id/cycling"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:text="Cycling" />
</RadioGroup>
</LinearLayout>
</androidx.cardview.widget.CardView>
</FrameLayout>
Result
Tips and Tricks
1. Make sure you are already registered as a Huawei developer.
2. Set min SDK version to 21 or later, otherwise you will get AndriodManifest to merge issue.
3. Make sure you have added the agconnect-services.json file to the app folder.
4. Make sure you have added the SHA-256 fingerprint without fail.
5. Make sure all the dependencies are added properly.
6. If you want location feature in the Map, make sure you add location permission in AndroidManifest.xml file.
7. If you install app in android version 6 or greater than make sure you handled run time permission.
8. Make sure you have encoded your API key with URLEncode UTF-8.
Conclusion
In this article, we have learnt the integration of the Direction API in Navigation Glove application using Android Studio and Kotlin. And also we have learnt how to convert the JSON to kotlin data classes. And also we have learnt the integration of the retrofit in the application.
Reference
Map Kit - Official document
Map Kit - Code lab
Map Kit - Training Video
Map Kit - Direction API