How to Use Geofences for Precise Audience Messaging
Tags: java, programming
Published: 2022-04-24 12:11:48

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.

## Implementation
You can carry out precise messaging to specified target audiences by using the geofence capability of HMS Core Location Kit in conjunction with the message pushing capability of the 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%.

## Demo
1. 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.

## Development Procedure
i. 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.

```
buildscript {
i.	    dependencies {
ii.	        ...
iii.	        // Add the AppGallery Connect plugin configuration. You are advised to use the latest plugin version.
iv.	        classpath 'com.huawei.agconnect:agcp:1.6.0.300'
    }
v.	}
```
b) Open the project-level **settings.gradle** file and configure the Maven repository address for the HMS Core SDK.

```
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/' }
    }
}
```
ii. Add build dependencies in the **dependencies** block.

```
// 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'
}
```
iii. Declare system permissions in the **AndroidManifest.xml** file.
Location Kit 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.

```
<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 Code
Code 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.

i. Configure geofences.

a) Create geofences and geofence groups as needed, and set relevant parameters, such as the geofence radius and triggering time.

```
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.

```
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);
}
```
ii. 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.

```
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.

## References

- 
[Location Kit official website](https://developer.huawei.com/consumer/en/hms/huawei-locationkit?ha_source=hms1)

- 
[Location Kit development documentation](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/introduction-0000001050706106?ha_source=hms1)