[Huawei Developers] Vivi Jiang:
Filling in addresses is a task that users of lifestyle apps and mini programs that provide services such as group buying, takeout, package delivery, housekeeping, logistics, and moving services often have to perform. Generally, this requires users to manually fill in their address information, for example, selecting California, Los Angeles, and Hollywood Blvd in sequence using several drop-down list boxes and then manually entering their names and phone numbers. This process usually takes some time and is prone to input error.

Wouldn't it be handy if there was an automatic way for users to fill in addresses quickly and accurately? With HMS Core Location Kit's fused location and geocoding capabilities, a lifestyle app can automatically pinpoint the current location of a user or obtain the street address of a map location, and fill that information in the address box. Thanks to this, users are freed from the hassle of having to manually enter addresses, as well preventing human error. In this article, I will explain how you can easily integrate this feature into your app and provide you with sample code.

Demo​

View attachment 5585365

Development Procedure​

Prepare for the development​

1. Sign in to AppGallery Connect and click My projects. Find your project, go to Project settings > Manage APIs, and toggle on the Location Kit switch. Then, click the app for which you need to configure the signing certificate fingerprint, and go to Project settings > General information. In the App information area, click Add next to SHA-256 certificate fingerprint, and enter the SHA-256 certificate fingerprint.

2. Go to Project settings > General information. In the App information area, click agconnect-services.json to download the configuration file. Then, copy the configuration file to the app's root directory.

3. Configure the project-level build.gradle file.

buildscript {
repositories {
google()
jcenter()
maven { url 'https://developer.huawei.com/repo/' }
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.2'
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}

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

Configure the app-level build.gradle file.

plugins {
id 'com.android.application'
id 'com.huawei.agconnect'
}

Add the following build dependency in the dependencies block in the app-level build.gradle file:

implementation 'com.huawei.hms:location:6.3.0.300'

Check permissions​

1. Declare the ACCESS_COARSE_LOCATION (approximate location permission), ACCESS_FINE_LOCATION (precise location permission), and ACCESS_BACKGROUND_LOCATION permissions in the AndroidManifest.xml file.

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

2. Dynamically apply for related location permissions (according to requirements for dangerous permissions in Android 6.0 or later).

if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "android 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 = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}

Obtain the location result​

1. Set location parameters, including the location update interval and location type

mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
mSettingsClient = LocationServices.getSettingsClient(this);
mLocationRequest = new LocationRequest();
// Set the location update interval, in milliseconds.
mLocationRequest.setInterval(5000);
// Set the priority.
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

2. Call the getSettingsClient() method to obtain a SettingsClient instance, and call checkLocationSettings() to check the device location settings.

LocationSettingsRequest locationSettingsRequest = builder.build();
// Before requesting location updates, call checkLocationSettings to check the device location settings.
Task<LocationSettingsResponse> locationSettingsResponseTask =
mSettingsClient.checkLocationSettings(locationSettingsRequest);

After checking that the device location function is enabled, call requestLocationUpdates() to request location updates.

locationSettingsResponseTask.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
@Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
Log.i(TAG, "check location settings success");
mFusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i(TAG, "requestLocationUpdatesWithCallback onSuccess");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "requestLocationUpdatesWithCallback onFailure:" + e.getMessage());
}
});
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.e(TAG, "checkLocationSetting onFailure:" + e.getMessage());
int statusCode = 0;
if (e instanceof ApiException) {
statusCode = ((ApiException) e).getStatusCode();
}
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
// When startResolutionForResult is called, a popup will
// appear, asking the user to grant relevant permissions.
if (e instanceof ResolvableApiException) {
ResolvableApiException rae = (ResolvableApiException) e;
rae.startResolutionForResult(MainActivity.this, 0);
}
} catch (IntentSender.SendIntentException sie) {
Log.e(TAG, "PendingIntent unable to execute request.");
}
break;
default:
break;
}
}
});

Obtain the address of the current location through reverse geocoding​

After obtaining the longitude and latitude of a location, pass them to the geocoding service (GeocoderService) to obtain a geocoding request object. Then, call the getFromLocation method and set request (GetFromLocationRequest) parameters to obtain the address of the location.

if (null == mLocationCallback) {
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
List<Location> locations = locationResult.getLocations();
if (!locations.isEmpty()) {
ExecutorUtil.getInstance().execute(new Runnable() {
@Override
public void run() {
Locale locale = new Locale("zh", "CN");
GeocoderService geocoderService = LocationServices.getGeocoderService(MainActivity.this, locale);
GetFromLocationRequest getFromLocationRequest = new GetFromLocationRequest(locations.get(0).getLatitude(), locations.get(0).getLongitude(), 1);
geocoderService.getFromLocation(getFromLocationRequest)
.addOnSuccessListener(new OnSuccessListener<List<HWLocation>>() {
@Override
public void onSuccess(List<HWLocation> hwLocation) {
printGeocoderResult(hwLocation);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.i(TAG, e.getMessage());
}
});
}
});
}
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
if (locationAvailability != null) {
boolean flag = locationAvailability.isLocationAvailable();
Log.i(TAG, "onLocationAvailability isLocationAvailable:" + flag);
}
}
};
}

Finally, display the obtained address on the screen to complete the implementation.

References​

>> Location Kit official website

>> Location Kit Development Guide

>> Reddit to join developer discussions

>> GitHub to download the sample code

>> Stack Overflow to solve integration problems