Precise messaging is an important way for mobile apps to retain users and is usually achieved by segmenting users into different groups according to their preferences and then adopting different messaging policies for each user segment. However, if you want to push messages to users based on their precise locations, in-depth customization is usually required since most available third-party messaging services cannot narrow the target audience down to a specific business area or a small area. With geofences, this issue can be effectively resolved. A geofence is a set of virtual boundaries that define a given area on a map. When a user's device enters or leaves the geofence, or stays in the geofence for a specific amount of time, messages and notifications can be automatically sent to an app on the user's device. Geofence and messaging capabilities can work together to precisely send messages to target audiences in a specified area.
For example, suppose that a travel app wants to promote its ticket booking service in Paris. To do so, the app can create geofences for popular scenic spots in Paris. When a target user arrives at a scenic spot during a specified time range, the app will send a promotion message such as "You have received a coupon for the XXX. Tap here to claim the coupon." to the user, increasing their willingness to buy a ticket.
ImplementationYou can carry out precise messaging to specified target audiences by using the geofence capability HMS Core Location Kit in conjunction with the message pushing capability of HMS Core Push Kit. By creating a geofence for a specified area, the app can detect the user's status, for example, when they enter, leave, or stay in this area. Once the messaging condition is met, the app on the user's device will receive a push message in real time. The push message can be sent to and displayed on the user's device even when the app is not running in the background, achieving a delivery rate as high as 99%.
Demo1. Install the demo app on the test device.
2. Start the demo app, tap Add Geofence on the GeoFence screen, and set relevant parameters to create a geofence.
3. Wait for the geofence to be triggered.
4. Check the received message.
{
"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"
}
Development Procedure1. Configure the Maven repository address for the SDK.
(The procedure for configuring the Maven repository address in Android Studio is different for Gradle plugin versions earlier than 7.0, Gradle plugin 7.0, and Gradle plugin 7.1 or later versions. Here, the procedure for Gradle plugin 7.1 is used as an example.)
a) Go to buildscript > dependencies and add AppGallery Connect plugin configurations.
Code:
buildscript {
dependencies {
...
// Add the AppGallery Connect plugin configuration. You are advised to use the latest plugin version.
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
}
}
b) Open the project-level settings.gradle file and configure the Maven repository address for the SDK.
Code:
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
// Configure the Maven repository address for the SDK.
maven { url 'https://developer.huawei.com/repo/' }
}
}
dependencyResolutionManagement {
...
repositories {
google()
mavenCentral()
// Configure the Maven repository address for the SDK.
maven { url 'https://developer.huawei.com/repo/' }
}
}
2. Add build dependencies in the dependencies block.
Code:
// Configure the app-level build.gradle file.
dependencies {
implementation 'com.huawei.hms:location: 6.4.0.300'
implementation 'com.huawei.hms:push: 6.3.0.304'
}
3. Declare system permissions in the AndroidManifest.xml file.
The Location SDK incorporates the GNSS, Wi-Fi, and base station location functions into an app to build up precise global positioning capabilities. Therefore, it requires the network, precise location, and coarse location permissions to function correctly. If the app needs to continuously obtain user locations when running in the background, the ACCESS_BACKGROUND_LOCATION permission also needs to be declared in the AndroidManifest.xml file.
Code:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARES_LOCATION" />
Note: The ACCESS_FINE_LOCATION, WRITE_EXTERNAL_STORAGE, and READ_EXTERNAL_STORAGE permissions are dangerous system permissions, so they must be dynamically applied for. If the app does not have the permissions, Location Kit will be unable to provide services for the app.
Key CodeCode file: com.huawei.hmssample2.geofence\GeoFenceActivity.java
If you want to integrate the geofence service and implement message pushing in your app, you only need to add relevant code in GeoFenceActivity.java to your app project.
1. Configure geofences.
a) Create geofences and geofence groups as needed, and set relevant parameters, such as the geofence radius and triggering time.
Code:
if (checkStyle(geofences, data.uniqueId) == false) {
LocationLog.d("GeoFenceActivity", "not unique ID!");
LocationLog.i("GeoFenceActivity", "addGeofence failed!");
return;
}
geoBuild.setRoundArea(data.latitude, data.longitude, data.radius);
geoBuild.setUniqueId(data.uniqueId);
geoBuild.setConversions(data.conversions);
geoBuild.setValidContinueTime(data.validContinueTime);
geoBuild.setDwellDelayTime(data.dwellDelayTime);
geoBuild.setNotificationInterval(data.notificationInterval);
geofences.add(geoBuild.build());
LocationLog.i("GeoFenceActivity", "addGeofence success!");
b) Register a broadcast using the intent.
Code:
GeofenceRequest.Builder geofenceRequest = new GeofenceRequest.Builder();
geofenceRequest.createGeofenceList(GeoFenceData.returnList());
if (trigger.getText() != null) {
int trigGer = Integer.parseInt(trigger.getText().toString());
geofenceRequest.setInitConversions(trigGer);
LocationLog.d(TAG, "trigger is " + trigGer);
} else {
geofenceRequest.setInitConversions(5);
LocationLog.d(TAG, "default trigger is 5");
}
final PendingIntent pendingIntent = getPendingIntent();
try {
geofenceService.createGeofenceList(geofenceRequest.build(), pendingIntent)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(Task<Void> task) {
if (task.isSuccessful()) {
LocationLog.i(TAG, "add geofence success! ");
setList(pendingIntent, GeoFenceData.getRequestCode(), GeoFenceData.returnList());
GeoFenceData.createNewList();
} else {
// Get the status code for the error and log it using a user-friendly message.
LocationLog.w(TAG, "add geofence failed : " + task.getException().getMessage());
}
}
});
} catch (Exception e) {
LocationLog.i(TAG, "add geofence error:" + e.getMessage());
}
private PendingIntent getPendingIntent() {
Intent intent = new Intent(this, GeoFenceBroadcastReceiver.class);
intent.setAction(GeoFenceBroadcastReceiver.ACTION_PROCESS_LOCATION);
Log.d(TAG, "new request");
GeoFenceData.newRequest();
return PendingIntent.getBroadcast(this, GeoFenceData.getRequestCode(), intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
2. Trigger message pushing. Send a push message when onReceive of GeoFenceBroadcastReceiver detects that the geofence is triggered successfully. The message will be displayed in the notification panel on the device.
Code:
GeofenceData geofenceData = GeofenceData.getDataFromIntent(intent);
if (geofenceData != null) {
int errorCode = geofenceData.getErrorCode();
int conversion = geofenceData.getConversion();
ArrayList<Geofence> list = (ArrayList<Geofence>) geofenceData.getConvertingGeofenceList();
Location myLocation = geofenceData.getConvertingLocation();
boolean status = geofenceData.isSuccess();
sb.append("errorcode: " + errorCode + next);
sb.append("conversion: " + conversion + next);
if (list != null) {
for (int i = 0; i < list.size(); i++) {
sb.append("geoFence id :" + list.get(i).getUniqueId() + next);
}
}
if (myLocation != null) {
sb.append("location is :" + myLocation.getLongitude() + " " + myLocation.getLatitude() + next);
}
sb.append("is successful :" + status);
LocationLog.i(TAG, sb.toString());
Toast.makeText(context, "" + sb.toString(), Toast.LENGTH_LONG).show();
//
new PushSendUtils().netSendMsg(sb.toString());
}
Note: The geofence created using the sample code will trigger two callbacks for conversion types 1 and 4. One is triggered when a user enters the geofence and the other when a user stays in the geofence. If Trigger is set to 7 in the code, callbacks will be configured for all scenarios, including entering, staying, and leaving the geofence.
Once you have performed the preceding steps, you will have enabled geofence-based message pushing for your app and can send messages to target audiences in specific areas, achieving precise marketing.
ReferencesLocation Kit official website
Location Kit development documentation
Related
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
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
Besides the usual offerings of flowers and handbags, what other ways are there to profess your love for your girlfriend?
John, a programmer at Huawei, provides us with a novel answer. John is currently on a business trip in France and wanted to do something different to show his appreciation for his girlfriend, who is far away in China, on March 8th – International Women's Day.
Looking out of his hotel window at the Eiffel Tower, an idea struck John's mind: What if I make an exercise tracking app to express my feelings for her? He shared the fruits of his quick labor with his girlfriend, who saw the following image when she opened the app:
{
"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"
}
On March 8th, we present you with this special tutorial on how to use HUAWEI Location Kit to win the heart of that special person in your life as well as imbue your apps with powerful location services.
OverviewHUAWEI Location Kit can combine the GNSS, Wi-Fi, and base station positioning capabilities into your app, allowing you to provide flexible location-based services for users around the world. We also provide HUAWEI Map Kit, which is an SDK for map development that includes map data for more than 200 countries and regions across the globe, and supports over 100 languages. With this SDK, you can display your user's exercise routes on a map in real time through the use of various map display tools.
Besides being a creative way of expressing your feeling for someone, exercise tracking can be applied to a wide range of scenarios. For example, it provides health and fitness apps with location-based services, such as recording exercise routes, displaying past exercise routes, and calculating distance traveled, so that users can track how much exercise they've done and calculate how many calories they've burned.
Development Preparations1. Create an app in AppGallery Connect and configure the signing certificate fingerprint.
2. Configure the Maven repository address and add the following build dependencies to the build.gradle file in the app directory.
Code:
dependencies {
implementation 'com.huawei.hms:location: 5.1.0.301'
implementation 'com.huawei.hms:maps: 5.1.0.300'
}
3. Configure obfuscation scripts.
For details about the preceding steps, please refer to the Location Kit Development Guide on the HUAWEI Developers website.
4. Declare system permissions in the AndroidManifest.xml file.
Location Kit incorporates GNSS, Wi-Fi, and base station positioning capabilities into your app so that you can provide precise global positioning services for your users. In order to do this, it requires the network permission, precise location permission, and coarse location permission. If you want the app to continuously obtain user locations when running in the background, you also need to declare the ACCESS_BACKGROUND_LOCATION permission in the AndroidManifest.xml file.
XML:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
Development Procedure1. Displaying the MapCurrently, the HMS Core Map SDK supports two map containers: SupportMapFragment and MapView. This article uses SupportMapFragment as an example.
(1) Add a Fragment object in the layout file (for example, activity_main.xml), and set map attributes in the file.
XML:
<fragment
android:id="@+id/mapfragment_routeplanningdemo"
android:name="com.huawei.hms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
(2) To use a map in your app, implement the OnMapReadyCallback API.
RoutePlanningActivity extends AppCompatActivity implements OnMapReadyCallback
(3) In the code file (for example, MainActivity.java), load SupportMapFragment in the onCreate() method and call getMapAsync() to register the callback.
Code:
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.mapfragment_routeplanningdemo);
if (fragment instanceof SupportMapFragment) {
SupportMapFragment mSupportMapFragment = (SupportMapFragment) fragment;
mSupportMapFragment.getMapAsync(this);
}(4) Call the onMapReady callback to obtain the HuaweiMap object.
@Override
public void onMapReady(HuaweiMap huaweiMap) {
hMap = huaweiMap;
hMap.setMyLocationEnabled(true);
hMap.getUiSettings().setMyLocationButtonEnabled(true);
}
2. Implementing the Location Function(1) Check the location permission.
Code:
XXPermissions.with(this)
// Apply for multiple permissions.
.permission(Permission.Group.LOCATION)
.request(new OnPermission() {
@Override
public void hasPermission(List<String> granted, boolean all) {
if (all) {
getMyLoction();
} else{
Toast.makeText(getApplicationContext(),"The function may be unavailable if the permissions are not assigned.",Toast.LENGTH_SHORT).show();
}
}
@Override
public void noPermission(List<String> denied, boolean never) {
if (never) {
XXPermissions.startPermissionActivity(RoutePlanningActivity.this, denied);
} else {
XXPermissions.startPermissionActivity(RoutePlanningActivity.this, denied);
}
}
});
(2) Pinpoint the current location and display it on the map. You need to check whether the location permission is enabled. If not, the location data cannot be obtained.
Code:
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// Check the device location settings.
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(locationSettingsResponse -> {
// Initiate location requests when the location settings meet the requirements.
fusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(aVoid -> {
// Processing when the API call is successful.
Log.d(TAG, "onSuccess: " + aVoid);
});
})
.addOnFailureListener(e -> {
// Device location settings do not meet the requirements.
int statusCode = ((ApiException) e).getStatusCode();
if (statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED) {
try {
ResolvableApiException rae = (ResolvableApiException) e;
// Call startResolutionForResult to display a popup message requesting the user to enable relevant permissions.
rae.startResolutionForResult(RoutePlanningActivity.this, 0);
} catch (IntentSender.SendIntentException sie) {
sie.printStackTrace();
}
}
});
3. Drawing Routes on the Map Based on the Real-time Location
Code:
private void addPath(LatLng latLng1, LatLng latLng2) {
PolylineOptions options = new PolylineOptions().color(Color.BLUE).width(5);
List<LatLng> path = new ArrayList<>();
path.add(latLng1);
path.add(latLng2);
for (LatLng latLng : path) {
options.add(latLng);
}
Polyline polyline = hMap.addPolyline(options);
mPolylines.add(polyline);
}Upload the location results to the cloud in real time by using the route planning function of Map Kit. The routes will then be returned and displayed on the map.String mWalkingRoutePlanningURL = "https://mapapi.cloud.huawei.com/mapApi/v1/routeService/walking";
String url = mWalkingRoutePlanningURL + "?key=" + key;
Response response = null;
JSONObject origin = new JSONObject();
JSONObject destination = new JSONObject();
JSONObject json = new JSONObject();
try {
origin.put("lat", latLng1.latitude);
origin.put("lng", latLng1.longitude);
destination.put("lat", latLng2.latitude);
destination.put("lng", latLng2.longitude);
json.put("origin", origin);
json.put("destination", destination);
RequestBody requestBody = RequestBody.create(JSON, String.valueOf(json));
Request request = new Request.Builder().url(url).post(requestBody).build();
response = getNetClient().initOkHttpClient().newCall(request).execute();
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return response;
ResultsOnce the code is compiled, an APK will be generated. Install it on your device and launch the app. Exercise tracks can now be drawn on the map based on your real-time location information.
More Information
To join in on developer discussion forums, go to Reddit.
To download the demo app and sample code, go to GitHub.
For solutions to integration-related issues, go to Stack Overflow.
Checkout in 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"
}
Introduction
In this article, we can learn how to integrate the Huawei Push Kit in Book Reading app to send the push message notification to users phone from the AppGallery Connect. Push notifications offers a great way to increase your application’s user engagement and boost your retention rates by sending meaningful messages or by informing users about your application. These messages can be sent at any time and even if your app is not running at that time. So, I will provide the series of articles on this Book Reading App, in upcoming articles I will integrate other Huawei Kits.
Push Kit
Huawei Push Kit is a messaging service developed by Huawei for developers to send messages to apps on users’ device in real time. Push Kit supports two types of messages: notification messages and data messages. You can send notifications and data messages to your users from your server using the Push Kit APIs or directly from the AppGallery Push Kit Console.
AppGallery Connect
Find the Push Kit message service in AppGallery connect dashboard.
Choose My Projects > Grow > Push Kit, and click Enable now.
Follow the steps to send the notification message to device from AppGallery Connect, Sending a Notification Message.
Requirements
1. Any operating system (MacOS, Linux and Windows).
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 and above installed.
4. Minimum API Level 24 is required.
5. Required EMUI 9.0.0 and later version devices.
How to integrate HMS Dependencies
1. First register as Huawei developer and complete identity verification in Huawei developers website, refer to register a Huawei ID.
2. Create a project in android studio, refer Creating an Android Studio Project.
3. Generate a SHA-256 certificate fingerprint.
4. To generate SHA-256 certificate fingerprint. On right-upper corner of android project click Gradle, choose Project Name > Tasks > android, and then click signingReport, as follows.
Note: Project Name depends on the user created name.
5. Create an App in AppGallery Connect.
6. Download the agconnect-services.json file from App information, copy and paste in android Project under app directory, as follows.
7. Enter SHA-256 certificate fingerprint and click Save button, as follows.
Note: Above steps from Step 1 to 7 is common for all Huawei Kits.
8. Click Manage APIs tab and enable Push Kit.
9. Add the below maven URL in build.gradle(Project) file under the repositories of buildscript, dependencies and allprojects, refer Add Configuration.
Code:
maven { url 'http://developer.huawei.com/repo/' }
classpath 'com.huawei.agconnect:agcp:1.6.0.300'
10. Add the below plugin and dependencies in build.gradle(Module) file.
Java:
apply plugin: id 'com.huawei.agconnect'
// Huawei AGC
implementation 'com.huawei.agconnect:agconnect-core:1.6.0.300'
// Huawei Push Kit
implementation 'com.huawei.hms:push:6.3.0.302'
// PDF Viewer
implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'
11. Now Sync the gradle.
12. Add the required permission to the AndroidManifest.xml file.
XML:
// Push Kit
<uses-permission android:name="android.permission.INTERNET" />
<service
android:name=".PushService"
android:exported="false">
<intent-filter>
<action android:name="com.huawei.push.action.MESSAGING_EVENT" />
</intent-filter>
</service>
Let us move to development
I have created a project on Android studio with empty activity let us start coding.
In the WebViewActivity.kt to find the web view of pdf document.
Java:
class WebViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_web_view)
webView.webViewClient = WebViewClient()
webView.settings.setSupportZoom(true)
webView.settings.javaScriptEnabled = true
val url = getPdfUrl() webView.loadUrl("https://docs.google.com/gview?embedded=true&url=$url")
}
companion object{
fun getPdfUrl(): String {
return "https://mindorks.s3.ap-south-1.amazonaws.com/courses/MindOrks_Android_Online_Professional_Course-Syllabus.pdf"
}
}
}
Create PushService.kt class to send the push notification to device.
Code:
class PushService : HmsMessageService() {
// When an app calls the getToken method to apply for a token from the server,
// if the server does not return the token during current method calling, the server can return the token through this method later.
// This method callback must be completed in 10 seconds. Otherwise, you need to start a new Job for callback processing.
// @param token token
override fun onNewToken(token: String?) {
Log.i(TAG, "received refresh token:$token")
// send the token to your app server.
if (!token.isNullOrEmpty()) {
// This method callback must be completed in 10 seconds. Otherwise, you need to start a new Job for callback processing.
refreshedTokenToServer(token)
}
val intent = Intent()
intent.action = CODELABS_ACTION
intent.putExtra("method", "onNewToken")
intent.putExtra("msg", "onNewToken called, token: $token")
sendBroadcast(intent)
}
private fun refreshedTokenToServer(token: String) {
Log.i(TAG, "sending token to server. token:$token")
}
// This method is used to receive downstream data messages.
// This method callback must be completed in 10 seconds. Otherwise, you need to start a new Job for callback processing.
// @param message RemoteMessage
override fun onMessageReceived(message: RemoteMessage?) {
Log.i(TAG, "onMessageReceived is called")
if (message == null) {
Log.e(TAG, "Received message entity is null!")
return
}
// getCollapseKey() Obtains the classification identifier (collapse key) of a message.
// getData() Obtains valid content data of a message.
// getMessageId() Obtains the ID of a message.
// getMessageType() Obtains the type of a message.
// getNotification() Obtains the notification data instance from a message.
// getOriginalUrgency() Obtains the original priority of a message.
// getSentTime() Obtains the time when a message is sent from the server.
// getTo() Obtains the recipient of a message.
Log.i(TAG, """getCollapseKey: ${message.collapseKey}
getData: ${message.data}
getFrom: ${message.from}
getTo: ${message.to}
getMessageId: ${message.messageId}
getMessageType: ${message.messageType}
getSendTime: ${message.sentTime}
getTtl: ${message.ttl}
getSendMode: ${message.sendMode}
getReceiptMode: ${message.receiptMode}
getOriginalUrgency: ${message.originalUrgency}
getUrgency: ${message.urgency}
getToken: ${message.token}""".trimIndent())
// getBody() Obtains the displayed content of a message
// getTitle() Obtains the title of a message
// getTitleLocalizationKey() Obtains the key of the displayed title of a notification message
// getTitleLocalizationArgs() Obtains variable parameters of the displayed title of a message
// getBodyLocalizationKey() Obtains the key of the displayed content of a message
// getBodyLocalizationArgs() Obtains variable parameters of the displayed content of a message
// getIcon() Obtains icons from a message
// getSound() Obtains the sound from a message
// getTag() Obtains the tag from a message for message overwriting
// getColor() Obtains the colors of icons in a message
// getClickAction() Obtains actions triggered by message tapping
// getChannelId() Obtains IDs of channels that support the display of messages
// getImageUrl() Obtains the image URL from a message
// getLink() Obtains the URL to be accessed from a message
// getNotifyId() Obtains the unique ID of a message
val notification = message.notification
if (notification != null) {
Log.i(TAG, """
getTitle: ${notification.title}
getTitleLocalizationKey: ${notification.titleLocalizationKey}
getTitleLocalizationArgs: ${Arrays.toString(notification.titleLocalizationArgs)}
getBody: ${notification.body}
getBodyLocalizationKey: ${notification.bodyLocalizationKey}
getBodyLocalizationArgs: ${Arrays.toString(notification.bodyLocalizationArgs)}
getIcon: ${notification.icon}
getImageUrl: ${notification.imageUrl}
getSound: ${notification.sound}
getTag: ${notification.tag}
getColor: ${notification.color}
getClickAction: ${notification.clickAction}
getIntentUri: ${notification.intentUri}
getChannelId: ${notification.channelId}
getLink: ${notification.link}
getNotifyId: ${notification.notifyId}
isDefaultLight: ${notification.isDefaultLight}
isDefaultSound: ${notification.isDefaultSound}
isDefaultVibrate: ${notification.isDefaultVibrate}
getWhen: ${notification.`when`}
getLightSettings: ${Arrays.toString(notification.lightSettings)}
isLocalOnly: ${notification.isLocalOnly}
getBadgeNumber: ${notification.badgeNumber}
isAutoCancel: ${notification.isAutoCancel}
getImportance: ${notification.importance}
getTicker: ${notification.ticker}
getVibrateConfig: ${notification.vibrateConfig}
getVisibility: ${notification.visibility}""".trimIndent())
showNotification(notification.title,notification.body)
}
val intent = Intent()
intent.action = CODELABS_ACTION
intent.putExtra("method", "onMessageReceived")
intent.putExtra("msg", "onMessageReceived called, message id:" + message.messageId + ", payload data:" + message.data)
sendBroadcast(intent)
val judgeWhetherIn10s = false
// If the messages are not processed in 10 seconds, the app needs to use WorkManager for processing.
if (judgeWhetherIn10s) {
startWorkManagerJob(message)
} else {
// Process message within 10s
processWithin10s(message)
}
}
private fun showNotification(title: String?, body: String?) {
val intent = Intent(this, WebViewActivity::class.java)
intent.putExtra("URL", "Provide link here")
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.sym_def_app_icon)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setSound(soundUri)
.setContentIntent(pendingIntent)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(0, notificationBuilder.build())
}
private fun startWorkManagerJob(message: RemoteMessage?) {
Log.d(TAG, "Start new Job processing.")
}
private fun processWithin10s(message: RemoteMessage?) {
Log.d(TAG, "Processing now.")
}
override fun onMessageSent(msgId: String?) {
Log.i(TAG, "onMessageSent called, Message id:$msgId")
val intent = Intent()
intent.action = CODELABS_ACTION
intent.putExtra("method", "onMessageSent")
intent.putExtra("msg", "onMessageSent called, Message id:$msgId")
sendBroadcast(intent)
}
override fun onSendError(msgId: String?, exception: Exception?) {
Log.i(TAG, "onSendError called, message id:$msgId, ErrCode:${(exception as SendException).errorCode}, " +
"description:${exception.message}")
val intent = Intent()
intent.action = CODELABS_ACTION
intent.putExtra("method", "onSendError")
intent.putExtra("msg", "onSendError called, message id:$msgId, ErrCode:${exception.errorCode}, " +
"description:${exception.message}")
sendBroadcast(intent)
}
override fun onTokenError(e: Exception) {
super.onTokenError(e)
}
private fun getToken() {
showLog("getToken:begin")
object : Thread() {
override fun run() {
try {
// read from agconnect-services.json
val appId = "Your app id"
val token = HmsInstanceId.getInstance([email protected]).getToken(appId, "HCM")
Log.i(TAG, "get token:$token")
if (!TextUtils.isEmpty(token)) {
sendRegTokenToServer(token)
}
showLog("get token:$token")
} catch (e: ApiException) {
Log.e(TAG, "get token failed, $e")
showLog("get token failed, $e")
}
}
}.start()
}
fun showLog(log: String?) {
runOnUiThread {
val tvView = findViewById<View?>(R.id.tv_log)
val svView = findViewById<View?>(R.id.sv_log)
if (tvView is TextView) {
tvView.text = log
}
if (svView is ScrollView) {
svView.fullScroll(View.FOCUS_DOWN)
}
}
}
private fun sendRegTokenToServer(token: String?) {
Log.i(TAG, "sending token to server. token:$token")
}
companion object {
private const val TAG: String = "PushDemoLog"
private const val CODELABS_ACTION: String = "com.huawei.codelabpush.action"
}
}
In the activity_web_view.xml we can create the UI screen.
XML:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".WebViewActivity">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
In the log_layout.xml we can create the UI screen.
Code:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView android:id="@+id/sv_log"
android:overScrollMode="never"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/tv_log"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
Demo
Tips and Tricks
1. Make sure you are already registered as Huawei developer.
2. Set minSDK version to 24 or later, otherwise you will get AndriodManifest merge issue.
3. Make sure you have added the agconnect-services.json file to app folder.
4. Make sure you have added SHA-256 fingerprint without fail.
5. Make sure all the dependencies are added properly.
Conclusion
In this article, we have learned how to integrate the Huawei Push Kit in Book Reading app to send the push message notification to users’ phone from the AppGallery Connect. Push notifications offers a great way to increase your application’s user engagement and boost your retention rates by sending meaningful messages or by informing users about your application. These messages can be sent at any time and even if your app is not running at that time.
I hope you have read this article. If you found it is helpful, please provide likes and comments.
Reference
Push Kit – Document
Push 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.