More information like this, you can visit HUAWEI Developer Forum
{
"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"
}
An Idea
The Idea behind creating this article is to showcase the power of Huawei Kits. In this article we are going to combine four kits that is Huawei Auth Service, Account kit, Location kit and Site kit to create a movie booking app. Earlier Sujith has already talked about integrating Huawei Auth Service and Account Kit. Refer his article in order to see our process of integrating both kits.
Introduction
Huawei Location Kit combines the GPS, Wi-Fi, and base station location functionalities into our app to build up global positioning capabilities, allowing us to provide flexible location-based services targeted at users around the globe. Currently, it provides three main capabilities: fused location, activity identification, and geofence.
With Huawei Site Kit, your app can provide users with convenient and secure access to diverse, place-related services.
Use Case
We will get user current location using location kit and use this location in site kit to get nearby movie theatres.
In this article, we will see how we have use these two kits and combine them in order to create a movie booking app.
Prerequisite
1. Must have a Huawei Developer Account
2. Must have a Huawei phone with HMS 4.0.0.300 or later
3. Must have a laptop or desktop with Android Studio, Jdk 1.8, SDK platform 26 and Gradle 4.6 installed.
Things Need To Be Done
1) Create a project in android studio.
2) Get the SHA Key. For getting the SHA key we can refer to this article.
3) Create an app in the Huawei app gallery connect.
4) Provide the SHA Key in App Information Section.
5) Provide storage location.
6) Enable Site Kit in Manage API Section.
7) After completing all the above points we need to download the agconnect-services.json from App Information Section. Copy and paste the json file in the app folder of the android project.
8) Enter below class path inside the dependencies of buildscript ( project build.gradle file )
Code:
classpath 'com.huawei.agconnect:agcp:1.3.1.300'
9) Enter below maven url inside the repositories of buildscript and allprojects ( project build.gradle file )
Code:
maven { url 'http://developer.huawei.com/repo/' }
10) Enter below plugin in the app build.gradle file dependencies section.
Code:
implementation 'com.huawei.hms:location:4.0.2.300'
implementation 'com.huawei.hms:site:5.0.0.300'
11) If the project is using progaurd, enter the below code in the progaurd-rules.pro file.
Code:
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.hianalytics.android.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
12) The HUAWEI Ads SDK requires the following permissions:
Code:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
13) Now sync the app.
Demo
In this demo, user will login using their Huawei ID. After that they will view the list of movies released in their respective cities. Once user selects a movie for booking purpose, user can see theatres near to their respective location. After selecting the theatre, user can see seats available for booking.
Getting user location
1) We need to check for permission.
Code:
private void grantPermission(){
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "sdk < 28 Q");
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings =
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
ActivityCompat.requestPermissions(this, strings, 1);
}
} else {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grantResults.length > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed");
}
}
if (requestCode == 2) {
if (grantResults.length > 2 && grantResults[2] == PackageManager.PERMISSION_GRANTED
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed");
}
}
}
2) In order to get user current location, create a FusedLocationProviderClient instance using the onCreate() method of Activity and use the instance to call location-related APIs.
Code:
FusedLocationProviderClient fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
3) The location function of Huawei Location Kit depends on the device location settings. For example, if the location function is disabled on a device, your app cannot obtain the device location. So, it is recommended that your app check whether the device settings meet the location requirements before continuously obtaining the device location. Huawei Location Kit provides the function of checking device location settings. In order to do that, obtain the SettingsClient instance using getSettingsClient(Activity activity) of LocationServices and call the checkLocationSettings(LocationSettingsRequest locationSettingsRequest) API to obtain the device location settings.
Code:
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
4) Create a location information request.
Code:
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setNeedAddress(true);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
5) Finally we need to get last location with address using FusedLocationProviderClient, so that we will be able to make user aware of their city also we need latitude and longitude of their current location in order to get nearby theatres using Huawei Site Kit.
Code:
fusedLocationProviderClient.getLastLocationWithAddress(mLocationRequest)
.addOnSuccessListener(new OnSuccessListener<HWLocation>() {
@SuppressLint("SetTextI18n")
@Override
public void onSuccess(HWLocation hwLocation) {
System.out.println("CITY >>> " + hwLocation.getCity());
lat = hwLocation.getLatitude();
lon = hwLocation.getLongitude();
txtWelcomMsg.setText("You are right now in " +hwLocation.getCity()+ " location. Grab a pop corn and book a movie because It's Show Time.");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
}
});
Getting user nearby theatres
1) We need API key in order to work with Huawei Site Kit. To get API key,
Choose AGC console > My Project > General Information > API Key. Copy this API key and save the key somewhere in your project.
2) Declare a SearchService object and use SearchServiceFactory to instantiate the object. Also the API key which we got from AGC console, need to be encoded using encodeURI.
Code:
try {
SearchService searchService = SearchServiceFactory.create(this, URLEncoder.encode(Constant.API_KEY, "utf-8"));
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "encode apikey error");
}
3) Need to create Coordinate in order to set the location later. We will use user current location latitude and longitude fetched using Huawei Location Kit.
Code:
Coordinate location = new Coordinate(lat, lon);
4) Create a QuerySuggestionRequest object, which is used as the request body for search suggestion. Related parameters are as follows, among which query is mandatory and others are optional:
a) query: search keyword.
b) location: longitude and latitude to which search results need to be biased.
c) radius: search radius, in meters. The value ranges from 1 to 50000. The default value is 50000.
d) bounds: coordinate bounds to which search results need to be biased.
e) poiTypes: List of POI types. The value range is a subset of LocationType.
f) countryCode: code of the country where places are searched, which complies with the ISO 3166-1 alpha-2 standard. Code of the country where places are searched, which complies with the ISO 3166-1 alpha-2 standard.
g) language: language in which search results are displayed. Language in which search results are displayed.
Code:
QuerySuggestionRequest request = new QuerySuggestionRequest();
request.setQuery("Movie theater");
request.setLocation(location);
request.setRadius(50);
request.setCountryCode("IN");
request.setLanguage("en");
QuerySuggestionRequest request2 = new QuerySuggestionRequest();
request2.setQuery("PVR cinemas");
request2.setLocation(location);
request2.setRadius(50);
request2.setCountryCode("IN");
request2.setLanguage("en");
QuerySuggestionRequest request3 = new QuerySuggestionRequest();
request3.setQuery("INOX Movies");
request3.setLocation(location);
request3.setRadius(50);
request3.setCountryCode("IN");
request3.setLanguage("en");
5) Finally create a SearchResultListener object to listen for the search result. Use the created SearchService object to call the querySuggestion() API and pass the created QuerySuggestionRequest and SearchResultListener objects to the API. Obtain the QuerySuggestionResponse object using the created SearchResultListener object. You can obtain a Site object from the QuerySuggestionResponse object and then parse it to obtain specific search results.
Code:
SearchResultListener<QuerySuggestionResponse> resultListener = new SearchResultListener<QuerySuggestionResponse>() {
@Override
public void onSearchResult(QuerySuggestionResponse results) {
if (results == null) {
return;
}
List<Site> sites = results.getSites();
for (Site site : sites) {
theaterNameList.add(site.getName());
}
}
@Override
public void onSearchError(SearchStatus status) {
Log.i("TAG", "Error : " + status.getErrorCode() + " " + status.getErrorMessage());
}
};
searchService.querySuggestion(request, resultListener);
searchService.querySuggestion(request2, resultListener);
searchService.querySuggestion(request3, resultListener);
GitHub
After we complete our series we will provide the github link for your reference
For More Information
https://developer.huawei.com/consumer/en/doc/HMSCore-Guides-V5/introduction-0000001050706106-V5
https://developer.huawei.com/consumer/en/doc/HMSCore-Guides-V5/android-sdk-introduction-0000001050158571-V5
Related
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.
{
"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"
}
Pick destination you want to travel with marker in the huawei map view.
Pick destination using HMS Site Kit.
Draw route between start and end location.
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
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.
2. Click agconnect-services.json to download the configuration file.
3. Copy the agconnect-services.json file to the app's root directory.
4. Open the build.gradle file in the root directory of your Android Studio project.
5. Configure the following information in the build.gradle file.
Code:
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.
7. Add Dependencies in app level build.gradle.
Code:
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.
Code:
<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
Code:
<!--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.
Code:
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
Code:
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
Code:
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(
[email protected],
ACCESS_FINE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
[email protected], ACCESS_COARSE_LOCATION
) != PERMISSION_GRANTED && checkSelfPermission(
[email protected],
"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.
Code:
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.
Code:
// create fusedLocationProviderClient
fusedLocationProviderClient=LocationServices.getFusedLocationProviderClient(this)
// create settingsClient
settingsClient = LocationServices.getSettingsClient(this)
15. Create a location request.
Code:
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.
Code:
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.
Code:
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(
[email protected]uestLocationUpdatesWithCallbackActivity, 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.
Code:
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
Code:
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
Code:
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
When am integrating site getting error code 6? can you explain why
sujith.e said:
When am integrating site getting error code 6? can you explain why
Click to expand...
Click to collapse
Hi, Sujith.e. The possible cause is that the API key contains special characters. You need to encode the special characters using encodeURI.
Introduction
This article provides information to book any trip using Trip Booking Android app. It provides a solution for HMS based multiple kits such as Account Kit, Huawei Ads, Huawei Map Direction Polyline API, Huawei Location, Huawei Map, Huawei Awareness Weather API, and Huawei Analytics to use in Trip Booking.
The following HMS Kits used in this application:
1) Huawei Account Kit: Integrated this kit for login and logout.
2) Huawei Ads: Integrated this kit for better ads experiences so that users can find the better advertisements.
3) Huawei Analytics: Integrated this kit in this application for better analysis.
4) Huawei Map: Integrated this kit for better real time experience of trip booking so that user can identify the location of trip on map.
5) Huawei Direction API: Integrated this API for better trip booking experience such as users can identify the trip direction from his/her location on map.
6) Huawei Awareness Weather API: Integrated this API for weather forecast of trip.
7) Huawei Location: Integrated this Kit to get current location of user so that users can identify from current location to desire trip location.
Note: Refer to the previous articles.
1) Explore the world Trip Booking App, Part-1 login with Huawei ID
2) Explore the world Trip Booking App, Part-2 Ads and Analytics
3) Explore the world Trip Booking App, Part-3 Map and direction API
Prerequisite
1. A computer (desktop or laptop)
2. A Huawei phone, which is used to debug the developed app
3. HUAWEI Analytics Kit 5.0.3.
4. Android SDK applicable to devices using Android API-Level 19 (Android 4.4 KitKat) or higher.
5. Android Studio
6. Java JDK 1.7 or later (JDK 1.8 recommended).
Things Need To Be Done
To integrate HUAWEI HMS Core services, you must complete the following preparations:
1. Create an app in AppGallery Connect.
2. Create an Android Studio project.
3. Add the app package name and save the configuration file.
4. Configure the Maven repository address and AppGallery Connect gradle plug-in.
Weather Awareness API
HUAWEI Awareness Kit provides your app with the ability to obtain contextual information including users' current time, location, behavior, audio device status, ambient light, weather, and nearby beacons. Your app can gain insight into a user's current situation more efficiently, making it possible to deliver a smarter, more considerate user experience.
Integration process
1) Assigning Permissions in the Manifest File
2) Importing API Classes
3) Developing Capabilities
1) Assigning Permissions in the Manifest File
Before calling the weather awareness capability, assign required permissions in the manifest file.
Code:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2) Importing API Classes
To use the weather awareness capability, you need to import the public capability classes of Awareness Kit, and also the weather-related classes.
Code:
import com.huawei.hmf.tasks.OnFailureListener;import com.huawei.hmf.tasks.OnSuccessListener;import com.huawei.hms.kit.awareness.Awareness;
import com.huawei.hms.kit.awareness.status.WeatherStatus;
import com.huawei.hms.kit.awareness.status.weather.Situation;
import com.huawei.hms.kit.awareness.status.weather.WeatherSituation;
3) Developing Capabilities
Obtain the Capture Client object of Awareness Kit.
Code:
public class AwarenessWeather {
private static final String TAG = AwarenessWeather.class.getName();
public CurrentWeather.Current getWeatherSituation(Context context) {
CurrentWeather.Current current = new CurrentWeather().new Current();
Awareness.getCaptureClient(context).getWeatherByDevice()
.addOnSuccessListener(weatherStatusResponse -> {
WeatherStatus weatherStatus = weatherStatusResponse.getWeatherStatus();
WeatherSituation weatherSituation = weatherStatus.getWeatherSituation();
Situation situation = weatherSituation.getSituation();
String weatherInfoStr =
"Time Zone : " + (weatherSituation.getCity().getTimeZone()) + "\n\n" +
"Weather id : " + situation.getWeatherId() + "\n\n" +
"Temperature : " + situation.getTemperatureC() + "℃" +
"/" + situation.getTemperatureF() + "℉" + "\n\n" +
"Wind speed : " + situation.getWindSpeed() + "km/h" + "\n\n" +
"Wind direction : " + situation.getWindDir() + "\n\n" +
"Humidity : " + situation.getHumidity() + "%";
Log.i(TAG, weatherInfoStr);
current.setObservationTime("Day");
current.setTemperature(Math.toIntExact(situation.getTemperatureC()));
current.setIsDay(url);
})
.addOnFailureListener(e -> {
Log.e(TAG, "get weather failed");
});
return current;
}
}
Location Kit
HUAWEI Location Kit combines the GNSS, Wi-Fi, and base station location functionalities into your app to build up global positioning capabilities, allows you to provide flexible location-based services targeted at users around the globe. Currently, it provides three main capabilities: Fused location, Activity identification, and Geofence. You can call one or more of these capabilities as required.
1) Fused location: Provides a set of simple and easy-to-use APIs for your app to quickly obtain the device location based on the GNSS, Wi-Fi, and base station location data.
2) Activity identification: Identifies user motion status through the acceleration sensor, cellular network information, and magnetometer, help to adapt the app to user behavior.
3) Geofence: Allows you to set an interesting area through an API so that your app can receive a notification when a specified action (such as leaving, entering, or staying in the area) occurs.
Integration process
1) Add following dependency in Gradle File.
Code:
implementation 'com.huawei.hms:location:5.0.2.301
2) Assigning App Permissions.
Apply for location permissions in the AndroidManifest.xml file.
Code:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
3) Creating a Location Service Client.
Create a FusedLocationProviderClient instance using the onCreate() method of Activity and use the instance to call location-related APIs.
Code:
private FusedLocationProviderClient fusedLocationProviderClient;
private LocationRequest mLocationRequest;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
}
4) Check permission.
Code:
// check location permisiion
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "sdk < 28 Q");
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings =
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
ActivityCompat.requestPermissions(this, strings, 1);
}
} else {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
if (grantResults.length > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed");
}
}
if (requestCode == 2) {
if (grantResults.length > 2 && grantResults[2] == PackageManager.PERMISSION_GRANTED
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful");
} else {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed");
}
}
}
Huawei Map Direction API
Huawei Map provides Direction API so that user can access all the information related to Map in RESTful API.
Huawei has provided the following API endpoint to access Direction API.
https://mapapi.cloud.huawei.com/mapApi/v1
Huawei provides the following direction API:
1. Walking Route Planning
2. Bicycling Route Planning
3. Driving Route Planning
Implemented the Driving Route API with the help of Retrofit and MVVM.
Retrofit Client
Created MapApiClient class for accessing the Direction API.
Code:
public class MapApiClient {
private final static HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
private static OkHttpClient okHttpClient;
public static Service getClient() {
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
if (okHttpClient == null) {
okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Consants.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
return retrofit.create(Service.class);
}
public interface Service {
@POST("mapApi/v1/routeService/driving")
Single<PolylineResponse> getPolylines(
@Query("key") String apiKey,
@Body PolylineBody polylineBody);
}
}
API Repository
I have created MapApiRepo class for accessing the API client.
Code:
public class MapApiRepo {
private MapApiClient.Service mService;
public MapApiRepo() {
this.mService = MapApiClient.getClient();
}
public Single<PolylineResponse> executeMapApi(PolylineBody polylineBody) {
return mService.getPolylines(Consants.API_KEY, polylineBody);
}
}
ViewModel
I have created MapApiViewModel class for handling the API calls.
Code:
public class MapApiViewModel extends ViewModel {
private final CompositeDisposable disposables = new CompositeDisposable();
private MapApiRepo mapApiRepo = new MapApiRepo();
private MutableLiveData<PolylineResponse> mPolylineLiveData = new MutableLiveData<>();
public LiveData<PolylineResponse> getPolylineLiveData(PolylineBody body) {
disposables.add(mapApiRepo.executeMapApi(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> mPolylineLiveData.setValue(result),
throwable -> mPolylineLiveData.setValue(null)
));
return mPolylineLiveData;
}
@Override
protected void onCleared() {
disposables.clear();
}
}
Drawing Polyline
I have implemented this functionality in the following activity.
Code:
mapApiViewModel.getPolylineLiveData(getPolylineBody()).observe(this, result -> {
Log.d(TAG, result.toString());
getPolylineData(result);
}); private PolylineBody getPolylineBody() {
PolylineBody polylineBody = new PolylineBody();
Origin origin = new Origin();
origin.setLat("30.0444");
origin.setLng("31.2357");
Destination destination = new Destination();
destination.setLat("30.0131");
destination.setLng("31.2089");
polylineBody.setDestination(destination);
polylineBody.setOrigin(origin);
return polylineBody;
}
public void getPolylineData(PolylineResponse polylineResponse) {
List<Routes> routesList = polylineResponse.getRoutes();
List<Paths> paths = new ArrayList<>();
List<Steps> steps = new ArrayList<>();
List<Polyline> polylines = new ArrayList<>();
latLngList = new ArrayList<>();
for (int x = 0; x < routesList.size(); x++) {
//here we can access each array list with main.get(x).
for (Paths paths1 : routesList.get(x).getPaths()) {
paths.add(paths1);
}
for (int y = 0; y < paths.size(); y++) {
for (Steps step :
paths.get(y).getSteps()) {
steps.add(step);
}
}
for (int i = 0; i < steps.size(); i++) {
for (Polyline polyline :
steps.get(i).getPolyline()) {
polylines.add(polyline);
}
}
}
for (int i = 0; i < polylines.size(); i++) {
latLngList.add(new LatLng(Double.valueOf(polylines.get(i).getLat())
, Double.valueOf(polylines.get(i).getLng())));
}
hmap.addPolyline(new PolylineOptions()
.addAll(latLngList)
.color(Color.BLUE)
.width(3));
}
App Development
Created the following package inside the project. In which integrated as Account Kit, Huawei Ads, Huawei Map Direction Polyline API, Huawei Location, Huawei Map, Huawei Awareness Weather API, and Huawei Analytics.
{
"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"
}
PolyLineActivity
In this activity, I have integrated Location kit, Map, and Direction API.
Launch the application
Let us launch our application, see the result
If you have any doubts or queries. Leave your valuable comment in the comment section and do not forget to like and follow me
Conclusion
In this article, I have explained how to integrate Location Kit and Weather Awareness in Trip Booking application and draw a route between origins to destination.
References
Driving Direction API:
https://developer.huawei.com/consumer/en/doc/development/HMSCore-References-V5/directions-driving-0000001050161496-V5
Introduction
This article is based on Multiple HMS services application. I have created Hotel Booking application using HMS Kits. We need mobile app for reservation hotels when we are traveling from one place to another place.
In this article, I am going to implement HMS Location Kit & Shared Preferences.
{
"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"
}
Flutter setup
Refer this URL to setup Flutter.
Software Requirements
1. Android Studio 3.X
2. JDK 1.8 and later
3. SDK Platform 19 and later
4. Gradle 4.6 and later
Steps to integrate service
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 current location.
4. Enabling Required Services: Location Kit.
5. Generating a Signing Certificate Fingerprint.
6. Configuring the Signing Certificate Fingerprint.
7. Get your agconnect-services.json file to the app root directory.
Important: While adding app, the package name you enter should be the same as your Flutter project’s package name.
Note: Before you download agconnect-services.json file, make sure the required kits are enabled.
Development Process
Create Application in Android Studio.
1. Create Flutter project.
2. App level gradle dependencies. Choose inside project Android > app > build.gradle.
Code:
apply plugin: 'com.android.application'
apply plugin: 'com.huawei.agconnect'
Root level gradle dependencies
Code:
maven {url 'https://developer.huawei.com/repo/'}
classpath 'com.huawei.agconnect:agcp:1.4.1.300'
Add the below permissions in Android Manifest file.
Code:
<manifest xlmns:android...>
...
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION" />
<application ...
</manifest>
3. Refer below URL for cross-platform plugins. Download required plugins.
https://developer.huawei.com/consum...y-V1/flutter-sdk-download-0000001050304074-V1
4. After completing all the steps above, you need to add the required kits’ Flutter plugins as dependencies to pubspec.yaml file. You can find all the plugins in pub.dev with the latest versions.
Code:
dependencies:
flutter:
sdk: flutter
shared_preferences: ^0.5.12+4
bottom_navy_bar: ^5.6.0
cupertino_icons: ^1.0.0
provider: ^4.3.3
huawei_location:
path: ../huawei_location/
flutter:
uses-material-design: true
assets:
- assets/images/
5. After adding them, run flutter pub get command. Now all the plugins are ready to use.
6. Open main.dart file to create UI and business logics.
Location kit
HUAWEI Location Kit assists developers in enabling their apps to get quick and accurate user locations and expand global positioning capabilities using GPS, Wi-Fi, and base station locations.
Fused location: Provides a set of simple and easy-to-use APIs for you to quickly obtain the device location based on the GPS, Wi-Fi, 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 behaviour.
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.
Integration
Permissions
First of all we need permissions to access location and physical data.
Create a PermissionHandler instance,add initState() for initialize.
Code:
final PermissionHandler permissionHandler;
@override
void initState() {
permissionHandler = PermissionHandler(); super.initState();
}
Check Permissions
We need to check device has permission or not using hasLocationPermission() method.
Code:
void hasPermission() async {
try {
final bool status = await permissionHandler.hasLocationPermission();
if(status == true){
showToast("Has permission: $status");
}else{
requestPermission();
}
} on PlatformException catch (e) {
showToast(e.toString());
}
}
If device don’t have permission,then request for Permission to use requestLocationPermission() method.
Code:
void requestPermission() async {
try {
final bool status = await permissionHandler.requestLocationPermission();
showToast("Is permission granted");
} on PlatformException catch (e) {
showToast(e.toString());
}
}
Fused Location
Create FusedLocationPrvoiderClient instance using the init() method and use the instance to call location APIs.
Code:
final FusedLocationProviderClient locationService
@override
void initState() {
locationService = FusedLocationProviderClient(); super.initState();
}
getLastLocation()
Code:
void getLastLocation() async {
try {
Location location = await locationService.getLastLocation();
setState(() {
lastlocation = location.toString();
print("print: " + lastlocation);
});
} catch (e) {
setState(() {
print("error: " + e.toString());
});
}
}
getLastLocationWithAddress()
Create LocationRequest instance and set required parameters.
Code:
final LocationRequest locationRequest;
locationRequest = LocationRequest()
..needAddress = true
..interval = 5000;
void _getLastLocationWithAddress() async {
try {
HWLocation location =
await locationService.getLastLocationWithAddress(locationRequest);
setState(() {
String street = location.street;
String city = location.city;
String countryname = location.countryName;
currentAddress = '$street' + ',' + '$city' + ' , ' + '$countryname';
print("res: $location");
});
showToast(currentAddress);
} on PlatformException catch (e) {
showToast(e.toString());
}
}
Location Update using Call back
Create LocationCallback instance and create callback functions in initstate().
Code:
LocationCallback locationCallback;
@override
void initState() {
locationCallback = LocationCallback(
onLocationResult: _onCallbackResult,
onLocationAvailability: _onCallbackResult,
);
super.initState();
}
void requestLocationUpdatesCallback() async {
if (_callbackId == null) {
try {
final int callbackId = await locationService.requestLocationUpdatesExCb(
locationRequest, locationCallback);
_callbackId = callbackId;
} on PlatformException catch (e) {
showToast(e.toString());
}
} else {
showToast("Already requested location updates.");
}
}
void onCallbackResult(result) {
print(result.toString());
showToast(result.toString());
}
I have created Helper class to store user login information in locally using shared Preferences class.
Code:
class StorageUtil {
static StorageUtil _storageUtil;
static SharedPreferences _preferences;
static Future<StorageUtil> getInstance() async {
if (_storageUtil == null) {
var secureStorage = StorageUtil._();
await secureStorage._init();
_storageUtil = secureStorage;
}
return _storageUtil;
}
StorageUtil._();
Future _init() async {
_preferences = await SharedPreferences.getInstance();
}
// get string
static String getString(String key) {
if (_preferences == null) return null;
String result = _preferences.getString(key) ?? null;
print('result,$result');
return result;
}
// put string
static Future<void> putString(String key, String value) {
if (_preferences == null) return null;
print('result $value');
return _preferences.setString(key, value);
}
}
Result
Tips & Tricks
1. Download latest HMS Flutter plugin.
2. To work with mock location we need to add permissions in Manifest.XML.
3. Whenever you updated plugins, click on pug get.
Conclusion
We implemented simple hotel booking application using Location kit in this article. We have learned how to get Lastlocation, getLocationWithAddress and how to use callback method, in flutter how to store data into Shared Preferences in applications.
Thank you for reading and if you have enjoyed this article, I would suggest you to implement this and provide your experience.
Reference
Location Kit URL
Shared Preferences URL
Read full article
Goodjob
Thank you
I thought huawei doesn't support flutter. I guess it should as it is Android only.
good
Wow
Nice.
I thought its not doable
Interesting.
Like
{
"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
If you are new to series of this article, follow the below article.
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
Beginner: Integration of Huawei Direction API in Navigation Glove IoT application Using Kotlin - Part 4
Beginner: Connecting to Smart Gloves Using Bluetooth in Navigation Glove IoT application Using Kotlin - Part 5
Beginner: Integration of Huawei Analytics kit and Crash service in Navigation Glove IoT application Using Kotlin - Part 6
Click to expand...
Click to collapse
In this series of article, we will learn about Navigation Glove application and also we will learn about integration of the Huawei Location kit in Navigation Glove IoT application.
One of the major features of android framework is Location Kit. You can see, the Location Kit is widely used in lot of apps those provides services like food ordering, Taxi booking, health tracking, social networking and also finance and lot more. The Location Kit is part of Huawei Mobile service and in the same kit geofencing and activity recognition are included.
Most Android devices allowed to determine the current geo location. This can be done via a GPS (Global Positioning System) module, via cell tower triangulation and via wifi networks.
The Location SDK for Android combines the Global Navigation Satellite System (GNSS), Wi-Fi, and base station location functionalities into your app to build up global positioning capabilities, allowing you to provide flexible location-based services for global users.
Function of Location Kit
Fused Location
Activity Identification
Geofence
High-Precision Location
Indoor Location
Geocoding
In this article, we will learn only about the Fused Location. Most of the developer does not know about the location permission. Follow the details about when we need what kind of permission.
ACCESS_COARSE_LOCATION: approximate location permission, which provides location information accurate to the city block level.
ACCESS_FINE_LOCATION: precise location permission, which allows your app to obtain the user location which is more accurate than that obtained based on the ACCESS_COARSE_LOCATION permission.
ACCESS_BACKGROUND_LOCATION: background location permission, which allows your app to obtain the user location when it runs in the background in Android 10 (API level: 29). In Android 10 or later, this permission is a dangerous permission and needs to be dynamically applied for. In versions earlier than Android 10, your app can obtain the user location regardless of whether it runs in the foreground or background, as long as it is assigned the ACCESS_COARSE_LOCATION permission.
Supported Platforms
Android
HarmonyOS (Java)
iOS (Objective C)
Rest API
Prerequisite
AppGallery Account
Android Studio 3.X
SDK Platform 19 or later
Gradle 5.4.1 or later
HMS Core (APK) 4.0.0.300 or later
Huawei Phone EMUI 5.0 or later
Non-Huawei Phone Android 5.1 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 Location Kit Service on AppGallery.
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:location:5.1.0.301'
6. Add all the below permission in the AndroidManifest.xml.
XML:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
7. If your app needs to locate continuously the device when it runs in the background in Android 10 or later, declare the ACCESS_BACKGROUND_LOCATION permission in the AndroidManifest.xml file. This step is optional.
Java:
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
8. Sync the project.
Now let’s learn the coding part.
Fused Location
Step 1: If you are running application Android 6 or later first check the permission.
Java:
private fun checkPermission() {
// check location permission
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "sdk < 28 Q")
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
ActivityCompat.requestPermissions(this, strings, 1)
}
} else {
if (ActivityCompat.checkSelfPermission(
[email protected],
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
[email protected],
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
[email protected],
"android.permission.ACCESS_BACKGROUND_LOCATION"
) != PackageManager.PERMISSION_GRANTED
) {
val strings = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"
)
ActivityCompat.requestPermissions([email protected], strings, 2)
}
}
}
Step 2: Handle the permission result
Java:
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 1) {
if (grantResults.size > 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED
) {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION successful")
requestLocationUpdatesWithCallback()
} else {
Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed")
}
}
if (requestCode == 2) {
if (grantResults.size > 2 && grantResults[2] == PackageManager.PERMISSION_GRANTED && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.i(
TAG,
"onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful"
)
requestLocationUpdatesWithCallback()
} else {
Log.i(TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed")
}
}
}
Step 3: Declare the following variable like LocationCallBack, LocationRequest, SettingClient, FusedLocationProviderClient
Java:
private var mLocationCallback: LocationCallback? = null
private var mLocationRequest: LocationRequest? = null
private lateinit var settingsClient: SettingsClient
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
Step 4: initialize the fusedLocationProvideClient in onCreate(()
Java:
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
Step 5: Initialize the SettingClient in onCreate()
Java:
settingsClient = LocationServices.getSettingsClient(this)
Step 6: Initialize the LocationRequest in onCreate()
Java:
mLocationRequest = LocationRequest().apply {
interval = 1000
needAddress = true
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
Step 7: Initialize the LocationCallBak in the onCreate()
Java:
mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
if (locationResult != null) {
val locations: List<Location> = locationResult.locations
if (locations.isNotEmpty()) {
for (location in locations) {
Log.i(TAG,
"onLocationResult location[Longitude,Latitude,Accuracy]:${location.longitude} , ${location.latitude} , ${location.accuracy}"
)
}
strLocation = """ Latitude:${locationResult.lastLocation.latitude} Longitude${locationResult.lastLocation.longitude} """.trimIndent()
Log.d(TAG, strLocation)
Log.d(TAG, "Country:" + locationResult.lastHWLocation.county);
Log.d(TAG, "CountryCode:" + locationResult.lastHWLocation.countryCode);
Log.d(TAG, "State:" + locationResult.lastHWLocation.state);
Log.d(TAG, "Postal Code:" + locationResult.lastHWLocation.postalCode);
Log.d(TAG, "Latitude:" + locationResult.lastHWLocation.latitude);
Log.d(TAG, "Longitude:" + locationResult.lastHWLocation.longitude);
Toast.makeText([email protected], strLocation, Toast.LENGTH_LONG).show()
onLocationChanged(locationResult.lastLocation)
val latlng = LatLng(
locationResult.lastLocation.latitude,
locationResult.lastLocation.longitude
)
updateDatToSmartGlove(latlng)
}
}
}
override fun onLocationAvailability(locationAvailability: LocationAvailability?) {
locationAvailability?.let {
val flag: Boolean = locationAvailability.isLocationAvailable
Log.i(TAG, "onLocationAvailability isLocationAvailable:$flag")
}
}
}
Step 8: Get the last know location.
Java:
/**
* Obtain the last known location
*/
private fun getLastLocation() {
try {
val lastLocation =
fusedLocationProviderClient.lastLocation
lastLocation.addOnSuccessListener(OnSuccessListener { location ->
if (location == null) {
Log.i(TAG, "getLastLocation onSuccess location is null")
[email protected]
}
Log.i(
TAG,
"getLastLocation onSuccess location[Longitude,Latitude]:${location.longitude},${location.latitude}"
)
Toast.makeText(this,"",Toast.LENGTH_SHORT).show()
[email protected]
}).addOnFailureListener { e: Exception ->
// Guide users to install or upgrade the HMS Core when the HMS Core (APK) is not installed on Huawei mobile phones.
if (e is ResolvableApiException) {
val apiException = e
Log.e(
TAG,
"getLastLocation onFailure:" + apiException.statusCode
)
try {
apiException.startResolutionForResult([email protected]Activity, 2009)
} catch (ex: IntentSender.SendIntentException) {
Log.e(
TAG, "getLastLocation sendIntentException:${ex.message}"
)
}
} else {
Log.e(
TAG,
"getLastLocation onFailure:" + e.message
)
}
}
} catch (e: Exception) {
Log.e(TAG, "getLastLocation exception:${e.message}")
}
}
Step 9: If you need location update with every X seconds, then you need to request location update with callback.
Java:
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 {
Log.i(TAG, "requestLocationUpdatesWithCallback onSuccess")
}
.addOnFailureListener { e ->
Log.e(
TAG,
"requestLocationUpdatesWithCallback onFailure:${e.message}"
)
}
}
.addOnFailureListener { e: Exception ->
Log.e(TAG, "checkLocationSetting onFailure:${e.message}")
when ((e as ApiException).statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
val rae = e as ResolvableApiException
rae.startResolutionForResult(
[email protected], 0
)
} catch (sie: IntentSender.SendIntentException) {
Log.e(TAG, "PendingIntent unable to execute request.")
}
}
}
} catch (e: Exception) {
Log.e(TAG, "requestLocationUpdatesWithCallback exception:${e.message}")
}
}
Step 10: Once location update is not required anymore, then you need to remove the location update with callback.
Java:
private fun removeLocationUpdatesWithCallback() {
try {
fusedLocationProviderClient.removeLocationUpdates(mLocationCallback)
.addOnSuccessListener {
Log.i(
TAG,
"removeLocationUpdatesWithCallback onSuccess"
)
}
.addOnFailureListener { e ->
Log.e(
TAG,
"removeLocationUpdatesWithCallback onFailure:${e.message}"
)
}
} catch (e: Exception) {
Log.e(
TAG,
"removeLocationUpdatesWithCallback exception:${e.message}"
)
}
}
Result
Tips and Tricks
1. Make sure you are already registered as a Huawei developer.
2. Set min SDK version to 19 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. Make sure all necessary permissions are added in the AndroidManifest.xml.
Conclusion
In this article, we have learnt the integration of the Huawei Location Kit in Smart Gloves mobile application using Android Studio and Kotlin. In this article, we understood about Huawei Location, Functions of Huawei Location and FusedLocation, Last know location and also we have learnt location update with callback and also removing the location update with callback.
Reference
Location Kit - Official document
Location Kit - Code lab
Location Kit - Training Video
Route planning is a very common thing that all of us do in our daily lives. Route planning in apps allows users to enter a location that they want to go to and then select an appropriate route based on various factors such as the estimated time of arrival (ETA), and is applicable to a wide range of scenarios. In a travel app for example, travelers can select a starting point and destination and then select an appropriate route. In a lifestyle app, users can search for nearby services within the specified scope and then view routes to these service locations. In a delivery app, delivery riders can plan optimal routes to facilitate order pickup and delivery.
So, how do we go about implementing such a useful function in an app? That's exactly what I'm going to introduce to you today. In this article, I'll show you how to use HMS Core Site Kit (place service) and Map Kit (map service) to build the route planning function into an app. First, I will use the place search capability in the place service to build the function of searching for nearby places in a specific geographical area by entering keywords. During actual implementation, you can choose whether to specify a geographical area for place search. Then, I will use the route planning capability in the map service to build the function of planning routes to destination places and showing the planned routes on an in-app map. In order to quickly pinpoint the precise location of a user device, I will use the fused location capability which implements precise positioning by combining GNSS, Wi-Fi, and base station data. In addition, the map service provides map data covering over 200 countries and regions and supports hundreds of languages, helping provide the best user experience possible for users all over the world. On top of this, the map service can plan routes for different modes of transport based on the real-time traffic conditions, and calculate the ETAs of the planned routes.
DemoThe map service supports three transport modes: driving, cycling, and walking. It can quickly plan several appropriate routes based on the selected transport mode, and show the distances and ETAs of these routes. The figure below shows the route planning effects for different transport modes.
{
"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"
}
Route planning effects for different transport modes
On top of this, the map service allows users to choose the shortest route or fastest route based on the traffic conditions, greatly improving user experience.
Preferred route choosing
Integration Procedure1. Register as a developer and create an app in AppGallery Connect.
1) Visit AppGallery Connect to register as a developer.
2) Create an app, add the SHA-256 signing certificate fingerprint, enable Map Kit and Site Kit, and download the agconnect-services.json file of your app.
2. Integrate the Map SDK and Site SDK.
1) Copy the agconnect-services.json file to the app's root directory of your project.
Go to allprojects > repositories and configure the Maven repository address for the SDK.
Go to buildscript > repositories and configure the Maven repository address for the SDK.
If you have added the agconnect-services.json file to your app, go to buildscript > dependencies and add the AppGallery Connect plugin configuration.
Code:
buildscript {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.huawei.agconnect:agcp:1.3.1.300'
}
}
allprojects {
repositories {
maven { url 'https://developer.huawei.com/repo/' }
google()
jcenter()
}
}
2) Add build dependencies in the dependencies block.
Code:
dependencies {
implementation 'com.huawei.hms:maps:{version}'
implementation 'com.huawei.hms:site:{version}'
}
3) Add the following configuration to the file header:
Code:
apply plugin: 'com.huawei.agconnect'
4) Copy your signing certificate file to the app directory of your project, and configure the signing information in android in the build.gradle file.
Code:
signingConfigs {
release {
// Signing certificate.
storeFile file("**.**")
// KeyStore password.
storePassword "******"
// Key alias.
keyAlias "******"
// Key password.
keyPassword "******"
v2SigningEnabled true
v2SigningEnabled true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
debuggable true
}
debug {
debuggable true
}
}
Main Code and Used Functions1. Keyword search: Call the keyword search function in the place service to search for places based on entered keywords and display the matched places.
Code:
SearchResultListener<TextSearchResponse> resultListener = new SearchResultListener<TextSearchResponse>() {
// Return search results upon a successful search.
@Override
public void onSearchResult(TextSearchResponse results) {
List<Site> siteList;
if (results == null || results.getTotalCount() <= 0 || (siteList = results.getSites()) == null
|| siteList.size() <= 0) {
resultTextView.setText("Result is Empty!");
return;
}
mFirstAdapter.refresh(siteList);
StringBuilder response = new StringBuilder("\n");
response.append("success\n");
int count = 1;
AddressDetail addressDetail;
Coordinate location;
Poi poi;
CoordinateBounds viewport;
for (Site site : siteList) {
addressDetail = site.getAddress();
location = site.getLocation();
poi = site.getPoi();
viewport = site.getViewport();
response.append(String.format(
"[%s] siteId: '%s', name: %s, formatAddress: %s, country: %s, countryCode: %s, location: %s, poiTypes: %s, viewport is %s \n\n",
"" + (count++), site.getSiteId(), site.getName(), site.getFormatAddress(),
(addressDetail == null ? "" : addressDetail.getCountry()),
(addressDetail == null ? "" : addressDetail.getCountryCode()),
(location == null ? "" : (location.getLat() + "," + location.getLng())),
(poi == null ? "" : Arrays.toString(poi.getPoiTypes())),
(viewport == null ? "" : viewport.getNortheast() + "," + viewport.getSouthwest())));
}
resultTextView.setText(response.toString());
Log.d(TAG, "onTextSearchResult: " + response.toString());
}
// Return the result code and description upon a search exception.
@Override
public void onSearchError(SearchStatus status) {
resultTextView.setText("Error : " + status.getErrorCode() + " " + status.getErrorMessage());
}
};
// Call the place search API.
searchService.textSearch(request, resultListener);
2. Walking route planning: Call the route planning API in the map service to plan walking routes and display the planned routes on a map.
Code:
NetworkRequestManager.getWalkingRoutePlanningResult(latLng1, latLng2,
new NetworkRequestManager.OnNetworkListener() {
@Override
public void requestSuccess(String result) {
generateRoute(result);
}
@Override
public void requestFail(String errorMsg) {
Message msg = Message.obtain();
Bundle bundle = new Bundle();
bundle.putString("errorMsg", errorMsg);
msg.what = 1;
msg.setData(bundle);
mHandler.sendMessage(msg);
}
});
ConclusionRoute planning is a very useful function for mobile apps in various industries. With this function, mobile apps can provide many useful services for users, thus improving the stickiness of their users.
In this article I demonstrated how integrating Map Kit and Site Kit is an effective way to implement route planning into an app. The whole implementation process is straightforward, empowering developers to implement route planning for their apps with ease.