1. Introduction
Overview
Location Kit combines the 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. In this codelab, you will learn how to call
capabilities of Location Kit to create an Android app (codelab
app).
The following figure shows the basic architecture of the
app. The codelab app will use the integrated Location SDK to call the
location service in HMS Core (APK).
What You Will Create
In this codelab, you will create an app for obtaining device location information.
What You Will Learn
In this codelab, you will learn how to:
- Configure a development environment.
- Call the location service of Location Kit.
2. What You Will Need
Hardware Requirements
- A computer (desktop or laptop), which is used to install Android Studio
- A Huawei phone or tablet running EMUI 5.0 or later, or a non-Huawei phone running Android 5.1 or later, which is used to debug the developed app
Software Requirements
- Android Studio (Version 3.6.1 or later is recommended.)
- JDK(Version 1.7 or later is recommended.)
- Android API level 22 or higher
- Gradle 5.4.1 or later
3. Integration Preparations
To integrate Location Kit, you must complete the following preparations:
- Create a project and app in AppGallery Connect.
- Create an Android Studio project.
- Generate a signing certificate.
- Generate a signing certificate fingerprint.
- Add the signing certificate fingerprint to the app in AppGallery Connect.
- Enable required kit APIs in AppGallery Connect.
- Add necessary configurations.
- Configure the app signature.
- Synchronize the project.
4. Configuring the Development Environment
Configuring the Maven Repository Address for the SDK
The procedure for configuring the Maven repository address in Android Studio is different for Gradle plugin earlier than 7.0, Gradle plugin 7.0, and Gradle plugin 7.1 or later. Click a relevant link below to find the configuration procedure for the specific Gradle plugin version.
Gradle plugin earlier than 7.0 | Gradle plugin 7.0 | Gradle plugin 7.1 or later |
Gradle plugin earlier than 7.0
- Open the build.gradle file in the root directory of your Android Studio project.
- Add the AppGallery Connect plugin and the Maven repository.
- Go to buildscript > repositories and configure the Maven repository address for the HMS Core SDK.
- Go to allprojects > repositories and configure the Maven repository address for the HMS Core SDK.
- If the agconnect-services.json file has been added to the app, go to buildscript > dependencies and add the AppGallery Connect plugin configuration.
buildscript {
repositories {
google()
jcenter()
// Configure the Maven repository address for the HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
...
// Add the AppGallery Connect plugin configuration. Please refer to AppGallery Connect Plugin Dependency to select a proper plugin version.
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
allprojects {
repositories {
google()
jcenter()
// Configure the Maven repository address for the HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
}
}
Gradle plugin 7.0
- Open the build.gradle file in the root directory of your Android Studio project.
- Add the AppGallery Connect plugin and the Maven repository
- Go to buildscript > repositories and configure the Maven repository address for the HMS Core SDK.
- If the agconnect-services.json file has been added to the app, go to buildscript > dependencies and add the AppGallery Connect plugin configuration and Android Gradle plugin configuration.
buildscript {
repositories {
google()
jcenter()
// Configure the Maven repository address for the HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
}
dependencies {
...
// Add the Android Gradle plugin configuration. You need to replace {version} with the actual Gradle plugin version, for example, 7.0.1.
classpath 'com.android.tools.build:gradle:{version}'
// Add the AppGallery Connect plugin configuration. Please refer to AppGallery Connect Plugin Dependency to select a proper plugin version.
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
dependencyResolutionManagement {
...
repositories {
google()
jcenter()
// Configure the Maven repository address for the HMS Core SDK.
maven {url 'https://developer.huawei.com/repo/'}
}
}
Gradle plugin 7.1 or later
- Open the build.gradle file in the root directory of your Android Studio project.
- If the agconnect-services.json file has been added to the app, go to buildscript > dependencies and add the AppGallery Connect plugin configuration and Android Gradle plugin configuration.
buildscript {
dependencies {
...
// Add the Android Gradle plugin configuration. You need to replace {version} with the actual Gradle plugin version, for example, 7.1.1.
classpath 'com.android.tools.build:gradle:{version}'
// Add the AppGallery Connect plugin configuration. Please refer to AppGallery Connect Plugin Dependency to select a proper plugin version.
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
// Configure the Maven repository address for the HMS Core SDK.
maven { url 'https://developer.huawei.com/repo/' }
}
}
dependencyResolutionManagement {
...
repositories {
google()
mavenCentral()
// Configure the Maven repository address for the HMS Core SDK.
maven { url 'https://developer.huawei.com/repo/' }
}
}
Adding Build Dependencies
- Open the app-level build.gradle file.
- Add a dependency on the Location SDK.
dependencies {
implementation 'com.huawei.hms:location:6.4.0.300'
}
5. Configuring Obfuscation Scripts
Before building the APK, configure the obfuscation configuration file to prevent the HMS Core SDK from being obfuscated.
- Open the obfuscation configuration file proguard-rules.pro of your Android project.
-
Add the following configuration to exclude the HMS Core SDK from
obfuscation:
-ignorewarnings -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile,LineNumberTable -keep class com.huawei.hianalytics.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;} -keep class * extends com.huawei.hms.core.aidl.IMessageEntity{ *; } -keep public class com.huawei.location.nlp.network.** {*; } -keep class com.huawei.wisesecurity.ucs.**{*;}
-
If you are using AndResGuard, add its trustlist to the obfuscation
configuration file.
"R.string.hms*", "R.string.connect_server_fail_prompt_toast", "R.string.getting_message_fail_prompt_toast", "R.string.no_available_network_prompt_toast", "R.string.third_app_*", "R.string.upsdk_*", "R.layout.hms*", "R.layout.upsdk_*", "R.drawable.upsdk*", "R.color.upsdk*", "R.dimen.upsdk*", "R.style.upsdk*"
-
(Optional) If you integrate the Location SDK 6.0.0.xxx (a
three-digit number), add the following statement in the app-level
build.gradle file to ensure proper running of your app. This is
because SDKs of this series of versions use SO files for hardening
and the SO files cannot be compressed after hardening.
android { buildTypes { release { packagingOptions { // If the CPU architecture is ARMv7 or ARMv8, add the following configuration: doNotStrip "*/arm64-v8a/libucs-credential.so" doNotStrip "*/armeabi-v7a/libucs-credential.so" // If the CPU architecture is x86, add the following configuration: doNotStrip "*/x86/libucs-credential.so" doNotStrip "*/x86_64/libucs-credential.so" } } debug { packagingOptions { // If the CPU architecture is ARMv7 or ARMv8, add the following configuration: doNotStrip "*/arm64-v8a/libucs-credential.so" doNotStrip "*/armeabi-v7a/libucs-credential.so" // If the CPU architecture is x86, add the following configuration: doNotStrip "*/x86/libucs-credential.so" doNotStrip "*/x86_64/libucs-credential.so" } } } }
6. Developing the Location Service
You can click here to download the demo source code and obtain the xxx.java file used during the demo development.
-
Apply for location permissions.
-
Declare the permissions for obtaining the precise and coarse
locations in the AndroidManifest.xml file.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
-
If your app needs to continuously locate the device when it
runs in the background in Android 10, also declare the
ACCESS_BACKGROUND_LOCATION permission in the
AndroidManifest.xml file.
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
-
Dynamically apply for required permissions.
Java sample code:
Kotlin sample code:// 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) { String[] strings = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}; ActivityCompat.requestPermissions(this, strings, 1); } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 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, 3); }else{ if (ActivityCompat.checkSelfPermission(this, "android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) { String[] permission = {"android.permission.ACCESS_BACKGROUND_LOCATION"}; ActivityCompat.requestPermissions(this, permission, 0); } } } 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); } }
// check location permission 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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (checkSelfPermission( this, ACCESS_FINE_LOCATION ) != PERMISSION_GRANTED && checkSelfPermission( this, ACCESS_COARSE_LOCATION ) != PERMISSION_GRANTED ) { val strings = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION) ActivityCompat.requestPermissions(this, strings, 3) } else { if (checkSelfPermission( this, "android.permission.ACCESS_BACKGROUND_LOCATION" ) != PERMISSION_GRANTED ) { val permission = arrayOf("android.permission.ACCESS_BACKGROUND_LOCATION") ActivityCompat.requestPermissions(this, permission, 0) } } } else { if (checkSelfPermission(this@RequestLocationUpdatesWithCallbackActivity, ACCESS_FINE_LOCATION) != PERMISSION_GRANTED && checkSelfPermission( this@RequestLocationUpdatesWithCallbackActivity, ACCESS_COARSE_LOCATION ) != PERMISSION_GRANTED && checkSelfPermission( this@RequestLocationUpdatesWithCallbackActivity, "android.permission.ACCESS_BACKGROUND_LOCATION" ) != PERMISSION_GRANTED ) { val strings = arrayOf( ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, "android.permission.ACCESS_BACKGROUND_LOCATION" ) requestPermissions(this, strings, 2) } }
-
Configure permission application result callback.
Java sample code:
Kotlin sample code:@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 PERMISSION 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"); } } if (requestCode == 3) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED || grantResults[1] == PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.checkSelfPermission(this, "android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) { String[] permission = {"android.permission.ACCESS_BACKGROUND_LOCATION"}; ActivityCompat.requestPermissions(this, permission, 0); } } else { Log.i(TAG, "onRequestPermissionsResult: apply LOCATION PERMISSION failed"); } } }
override fun onRequestPermissionsResult( requestCode: Int, permissions: Array
, 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 PERMISSION failed" ) } } if (requestCode == 2) { if (grantResults.size > 2 && grantResults[2] == PERMISSION_GRANTED && grantResults[0] == PERMISSION_GRANTED && grantResults[1] == PERMISSION_GRANTED ) { Log.i( TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION successful" ) } else { Log.i( TAG, "onRequestPermissionsResult: apply ACCESS_BACKGROUND_LOCATION failed" ) } } if (requestCode == 3) { if (grantResults.isNotEmpty() && grantResults[0] == PERMISSION_GRANTED || grantResults[1] == PERMISSION_GRANTED ) { if (checkSelfPermission( this, "android.permission.ACCESS_BACKGROUND_LOCATION" ) != PERMISSION_GRANTED ) { val permission = arrayOf("android.permission.ACCESS_BACKGROUND_LOCATION") ActivityCompat.requestPermissions(this, permission, 0) } } else { Log.i( TAG, "onRequestPermissionsResult: apply LOCATION PERMISSSION failed" ) } } }
You can refer to the
RequestLocationUpdatesWithCallbackActivity.java or
RequestLocationUpdatesWithCallbackActivity.kt file to complete
subsequent steps.
-
Declare the permissions for obtaining the precise and coarse
locations in the AndroidManifest.xml file.
-
Create a location provider client and device setting client.
Java sample code:
Kotlin sample code:// Define a location provider client. private FusedLocationProviderClient fusedLocationProviderClient; // Define a device setting client. private SettingsClient settingsClient; fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this); settingsClient = LocationServices.getSettingsClient(this);
// Define a location provider client. private lateinit var fusedLocationProviderClient: FusedLocationProviderClient // Define a device setting client. private lateinit var settingsClient: SettingsClient fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this) settingsClient = LocationServices.getSettingsClient(this)
-
Create the location request body.
Java sample code:
Kotlin sample code:LocationRequest mLocationRequest; mLocationRequest = new LocationRequest(); // Set the interval for requesting location updates (unit: ms). mLocationRequest.setInterval(10000); // Set the location type. mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
var mLocationRequest: LocationRequest? = null // Set the interval for requesting location updates (unit: ms). // Set the location type. mLocationRequest = LocationRequest().apply { interval = 1000 needAddress = true priority = LocationRequest.PRIORITY_HIGH_ACCURACY }
-
Create a location result callback.
Java sample code:
Kotlin sample code:LocationCallback mLocationCallback; mLocationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { if (locationResult != null) { List<Location> locations = locationResult.getLocations(); if (!locations.isEmpty()) { for (Location location : locations) { Log.i(TAG,"onLocationResult location[Longitude,Latitude,Accuracy]:" + location.getLongitude() + "," + location.getLatitude() + "," + location.getAccuracy()); } } } } @Override public void onLocationAvailability(LocationAvailability locationAvailability) { if (locationAvailability != null) { boolean flag = locationAvailability.isLocationAvailable(); Log.i(TAG, "onLocationAvailability isLocationAvailable:" + flag); } } };
var mLocationCallback: LocationCallback? = null if (null == mLocationCallback) { 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}" ) } } } } override fun onLocationAvailability(locationAvailability: LocationAvailability?) { locationAvailability?.let { val flag: Boolean = locationAvailability.isLocationAvailable Log.i(TAG, "onLocationAvailability isLocationAvailable:$flag") } } } }
-
Request location updates.
Java sample code:
Kotlin sample code:private void requestLocationUpdatesWithCallback() { try { LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); builder.addLocationRequest(mLocationRequest); LocationSettingsRequest locationSettingsRequest = builder.build(); // Check the device settings before requesting location updates. settingsClient.checkLocationSettings(locationSettingsRequest) .addOnSuccessListener(new OnSuccessListener
() { @Override public void onSuccess(LocationSettingsResponse locationSettingsResponse) { Log.i(TAG, "check location settings success"); // Request location updates. fusedLocationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper()).addOnSuccessListener(new OnSuccessListener () { @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()); } }); } catch (Exception e) { Log.e(TAG, "requestLocationUpdatesWithCallback exception:" + e.getMessage()); } } private fun requestLocationUpdatesWithCallback() { try { val builder = LocationSettingsRequest.Builder() builder.addLocationRequest(mLocationRequest) val locationSettingsRequest = builder.build() // Check the device settings before requesting location updates. val locationSettingsResponseTask: Task
= 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}") } } catch (e: Exception) { Log.e(TAG, "requestLocationUpdatesWithCallback exception:${e.message}") } } -
Stop requesting location updates.
Java sample code:
Kotlin sample code:private void removeLocationUpdatesWithCallback() { try { fusedLocationProviderClient.removeLocationUpdates(mLocationCallback) .addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { Log.i(TAG, "removeLocationUpdatesWithCallback onSuccess"); } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { Log.e(TAG, "removeLocationUpdatesWithCallback onFailure:" + e.getMessage()); } }); } catch (Exception e) { Log.e(TAG, "removeLocationUpdatesWithCallback exception:" + e.getMessage()); } }
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}" ) } }
7. Testing the Demo App
Tap requestLocationUpdates with callback in the demo app. The obtained location information will be displayed on the app screen.
8. Congratulations
Well done. You have successfully completed this codelab and learned how to:
- Integrate Location Kit.
-
Call the location service of Location Kit.
For more information about Location Kit, please visit our official website. If you encounter any problems during the development, please refer to FAQs.