How can geofencing be implemented on HarmonyOS wearable devices without using GNSS?
Requirement Description
Geofencing traditionally relies on GNSS (Global Navigation Satellite System) to determine the precise location of a device and to monitor its position relative to a virtual boundary. Without GNSS, implementing geofencing becomes challenging because the system cannot obtain accurate satellite-based positioning data.
However, wearable devices often operate in conjunction with smartphones and are typically connected via Bluetooth. In such scenarios, the wearable device can utilize the smartphone’s location services, which may rely on Wi-Fi positioning, cell towers, or other methods instead of GNSS. This allows the wearable to indirectly access location data without having a dedicated GNSS module.
Therefore, implementing geofencing on wearable devices without GNSS requires alternative approaches:
- Wi-Fi Positioning: Determining location based on available Wi-Fi networks.
- Cell Tower Triangulation: Using mobile network signals to estimate device position.
- Bluetooth Beacons: Creating smaller geofences in indoor environments.
- Smartphone-Assisted Location: Relaying the phone’s location data to the wearable for geofencing purposes.
In summary, while GNSS is the most reliable and accurate method for geofencing, wearable devices often need to rely on alternative positioning techniques through their connected smartphones. This requirement implies that developers must design geofencing features in a flexible way, supporting multiple sources of location data rather than depending solely on GNSS.
Background Knowledge
Geofencing is a location-based technology that creates a virtual boundary around a specific geographic area. When a device enters or exits this predefined area, the system can trigger certain actions, such as sending notifications, tracking activity, or enabling/disabling features. Geofencing is commonly used in applications like fitness tracking, marketing, security, and smart home automation.
GNSS (Global Navigation Satellite System) is a general term for satellite-based navigation systems that provide geolocation and time information to devices. Examples of GNSS include GPS (United States), GLONASS (Russia), Galileo (European Union), and BeiDou (China). These systems work by receiving signals from multiple satellites to determine the device’s position on Earth with high accuracy.
The Connection Between Geofencing and GNSS
Geofencing relies on precise location data to determine whether a device is inside or outside a virtual boundary. GNSS plays a key role in providing this location data. By continuously tracking the device’s position, GNSS enables geofencing systems to function accurately.
- Without GNSS, geofencing may use alternatives such as Wi-Fi positioning, Bluetooth beacons, or cell tower triangulation, but these methods are generally less accurate compared to GNSS-based geofencing.
- On wearable devices, combining GNSS with sensors (like accelerometers and gyroscopes) can improve both location accuracy and battery efficiency.
On HarmonyOS wearable devices, geofencing can be implemented using MapKit and Location Kit, regardless of whether GNSS is available. These frameworks provide flexible methods to obtain and process location data, allowing developers to create virtual boundaries and trigger actions when a device enters or exits them.
Implementation Steps
Here you can find the implementation steps below. Please note that the most important thing here is calculating distance by using Haversine Formula
-
Initialize Map and Location Services
- Use
MapComponentfrom MapKit to render the map on the wearable device. - Configure map options via
mapCommon.MapOptions. - Enable location display with
mapController.setMyLocationEnabled(true)andsetMyLocationControlsEnabled(true).
- Use
-
Define Geofence Parameters
- Set the geofence center (
geoFenceCenter) with latitude and longitude coordinates. - Define the geofence radius (
geoFenceRadius) in meters. - Optionally, visualize the geofence using a circular overlay with
mapController.addCircle().
- Set the geofence center (
-
Start Location Updates
- Configure a
geoLocationManager.LocationRequestto receive device location periodically or when distance changes. - Subscribe to location changes using
geoLocationManager.on('locationChange', callback).
- Configure a
-
Calculate Distance Using Haversine Formula
- For each location update, calculate the distance between the device location and the geofence center using the Haversine formula:
a=sin2(Δlat/2)+cos(lat1)⋅cos(lat2)⋅sin2(Δlon/2)a = \sin^2(\Delta\text{lat}/2) + \cos(\text{lat}_1) \cdot \cos(\text{lat}_2) \cdot \sin^2(\Delta\text{lon}/2)a=sin2(Δlat/2)+cos(lat1)⋅cos(lat2)⋅sin2(Δlon/2) c=2⋅arctan2(a,1−a)c = 2 \cdot \arctan2(\sqrt{a}, \sqrt{1-a})c=2⋅arctan2(a,1−a) distance=R⋅c\text{distance} = R \cdot cdistance=R⋅c
- This formula accurately computes the shortest distance over the Earth’s surface between two points.
-
Monitor Geofence Status
- Compare the calculated distance with the geofence radius:
- If
distance <= geoFenceRadius, the device is inside the geofence. - If
distance > geoFenceRadius, the device is outside the geofence.
- If
- Track changes in geofence status (
isInsideGeoFence) to trigger appropriate actions only when crossing boundaries.
- Compare the calculated distance with the geofence radius:
-
Trigger Notifications and Alerts
-
Inside geofence:
- Show safe zone notification.
- Stop vibration.
-
Outside geofence:
- Show danger zone notification using
showNotification(). - Trigger vibration using
startVibration(). - Optionally, display alert dialog with
showAlert().
- Show danger zone notification using
-
Inside geofence:
-
Update Map Camera (Optional)
- Center the map on the device location with
centerMapOnLocation(location)for real-time tracking.
- Center the map on the device location with
-
Stop Location Updates on Exit
- Unsubscribe from location updates when the component disappears using
geoLocationManager.off('locationChange', callback).
- Unsubscribe from location updates when the component disappears using
Code Snippet / Configuration
1. Imports
import { MapComponent, mapCommon, map } from '@kit.MapKit';
import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
import { router } from '@kit.ArkUI';
import { geoLocationManager } from '@kit.LocationKit';
import { notificationManager } from '@kit.NotificationKit';
import { promptAction } from '@kit.ArkUI';
import vibrator from '@ohos.vibrator';
Explanation:
- Imports all necessary HarmonyOS kits.
-
MapKit→ for map UI components. -
LocationKit→ for location services. -
NotificationKit→ for push notifications. -
vibrator→ device vibration. -
AsyncCallbackandBusinessError→ for handling asynchronous operations and errors.
2. State & Variables
private mapOptions: mapCommon.MapOptions | null = null;
private callback?: AsyncCallback<map.MapComponentController>;
private mapController?: map.MapComponentController;
private mapEventManager?: map.MapEventManager;
@State currentLocation: geoLocationManager.Location | null = null;
@State vibrationInterval: number | undefined = undefined;
private locationRequest: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.ACCURACY,
timeInterval: 0,
distanceInterval: 0,
maxAccuracy: 0
};
private locationChangeCallback?: (location: geoLocationManager.Location) => void;
private mapCircle?: map.MapCircle;
private isInsideGeoFence: boolean = true;
private geoFenceCenter: mapCommon.LatLng | null = null;
private geoFenceRadius: number = 100;
Explanation:
-
mapOptions,mapController,mapEventManager→ control map state. -
currentLocation→ device current position. -
vibrationInterval→ manage vibration timing. -
locationRequest→ request parameters for location updates. -
geoFenceCenter,geoFenceRadius,isInsideGeoFence→ core geofencing data.
3. aboutToAppear()
aboutToAppear(): void {
const params = router.getParams() as mapCommon.MapOptions;
if(params) this.mapOptions = params;
this.locationChangeCallback = (location: geoLocationManager.Location) => {
this.currentLocation = location;
this.centerMapOnLocation(location);
this.checkGeoFenceStatus(location);
};
this.callback = async (err, mapController) => {
if (!err) {
this.mapController = mapController;
this.mapEventManager = this.mapController.getEventManager();
this.mapController.setMyLocationEnabled(true);
this.mapController.setMyLocationControlsEnabled(true);
let mapCircleOptions: mapCommon.MapCircleOptions = {
center: {
latitude: this.mapOptions!.position.target.latitude,
longitude: this.mapOptions!.position.target.longitude
},
radius: 100,
clickable: true,
fillColor: 0xFFFFC100,
strokeColor: 0xFFFF0000,
strokeWidth: 10,
visible: true,
zIndex: 5
};
this.mapCircle = await this.mapController.addCircle(mapCircleOptions);
this.geoFenceCenter = mapCircleOptions.center;
this.geoFenceRadius = mapCircleOptions.radius;
this.startLocationUpdates();
let callback = () => {
if (this.currentLocation) this.centerMapOnLocation(this.currentLocation);
};
this.mapEventManager.on("mapLoad", callback);
} else {
console.error(`Failed to initialize the map. Code: ${err.code}; message: ${err.message}`);
}
};
}
Explanation:
- Called when the component appears.
- Sets map parameters and location change callback.
- Initializes map controller, geofence circle, and starts location updates.
4. centerMapOnLocation()
private centerMapOnLocation(location: geoLocationManager.Location) {
if (this.mapController) {
const cameraPosition: mapCommon.CameraPosition = {
target: { latitude: location.latitude, longitude: location.longitude },
zoom: 15,
tilt: 0,
bearing: 0
};
let cameraUpdate = map.newCameraPosition(cameraPosition);
this.mapController.animateCamera(cameraUpdate, 1000);
}
}
Explanation:
- Animates map camera to the device location.
- Provides smooth transition when updating position.
5. Vibration Control
private startVibration(): void {
this.stopVibration();
vibrator.startVibration({ type: 'time', duration: 10000 }, { id: 0, usage: 'alarm' });
}
private stopVibration() {
if (this.vibrationInterval !== undefined) {
clearInterval(this.vibrationInterval);
this.vibrationInterval = undefined;
vibrator.stopVibration().catch((err: BusinessError) => {
console.error('Failed to stop vibration:', err);
});
}
}
Explanation:
-
startVibration()→ triggers vibration when leaving geofence. -
stopVibration()→ stops vibration when entering safe zone.
6. checkGeoFenceStatus() – Haversine & Geofence Logic
private checkGeoFenceStatus(location: geoLocationManager.Location): void {
if (!this.geoFenceCenter) return;
const distance = this.calculateDistance(
location.latitude, location.longitude,
this.geoFenceCenter.latitude, this.geoFenceCenter.longitude
);
const nowInside = distance <= this.geoFenceRadius;
if (nowInside !== this.isInsideGeoFence) {
this.isInsideGeoFence = nowInside;
if (nowInside) {
this.showNotification("You are in safe zone!", "You have entered the safe zone again");
this.stopVibration();
} else {
this.showNotification("WARNING!", "DANGER ZONE!");
this.startVibration();
this.showAlert("WARNING!", "DANGER ZONE");
}
}
}
Explanation:
- Calculates distance from geofence center using Haversine formula.
- Determines if user is inside or outside geofence.
- Triggers notifications, vibration, and alerts accordingly.
7. calculateDistance() & deg2rad()
private calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
const R = 6371000;
const dLat = this.deg2rad(lat2 - lat1);
const dLon = this.deg2rad(lon2 - lon1);
const a = Math.sin(dLat / 2) ** 2 +
Math.cos(this.deg2rad(lat1)) * Math.cos(this.deg2rad(lat2)) *
Math.sin(dLon / 2) ** 2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
private deg2rad(deg: number): number {
return deg * (Math.PI / 180);
}
Explanation:
- Haversine formula calculates distance between two lat/lon points.
- Critical for GNSS-independent geofencing.
8. Notifications & Alerts
private async showNotification(title: string, content: string): Promise<void> {
try {
await notificationManager.publish({
content: { notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, normal: { title, text: content } },
id: 1
});
} catch (error) { console.error('Notification error:', error); }
}
private async showAlert(title: string, message: string): Promise<void> {
try {
await promptAction.showDialog({ title, message, buttons: [{ text: 'OK', color: '#007AFF' }] });
this.stopVibration();
} catch (error) { console.error('Alert error:', error); }
}
Explanation:
- Sends notifications and shows pop-up alerts.
- Works together with vibration to inform user of geofence events.
9. startLocationUpdates() & aboutToDisappear()
private startLocationUpdates() {
try {
geoLocationManager.on('locationChange', this.locationRequest, this.locationChangeCallback!);
} catch (error) {
console.error('Location updates error:', error);
}
}
aboutToDisappear(): void {
if (this.locationChangeCallback) {
geoLocationManager.off('locationChange', this.locationChangeCallback);
}
}
Explanation:
-
startLocationUpdates()→ registers callback for location changes. -
aboutToDisappear()→ unregisters callback to avoid memory leaks.
10. build() – Map Component
build() {
Stack() {
MapComponent({ mapOptions: this.mapOptions!, mapCallback: this.callback }).width('100%').height('100%');
}.height('100%')
}
Explanation:
- Builds the map UI component.
- Full-screen map with geofence overlay and location tracking.
Test Results
Here you can find the related screenshots belong to demo below;
Limitations or Considerations
- The technologies and APIs discussed in this article work only on real HarmonyOS wearable devices and may not function correctly on emulators or other platforms.
- Geofencing without GNSS relies on Wi-Fi, Bluetooth, or paired smartphone location, which can lead to reduced accuracy compared to satellite-based positioning.
- Battery consumption may increase due to continuous location updates and vibration notifications.
- The Haversine formula calculates straight-line distances and does not account for physical obstacles or restricted areas, which could affect real-world geofence detection.
- Notifications and alerts depend on the device’s permission settings, so users may need to allow notifications and vibrations for proper functionality.
- Network or connectivity issues may delay location updates, causing temporary inaccuracies in geofence detection.
Related Documents or Links
https://developer.huawei.com/consumer/en/doc/harmonyos-guides/map-kit-guide
https://developer.huawei.com/consumer/en/doc/harmonyos-guides/map-creation
https://developer.huawei.com/consumer/en/doc/harmonyos-guides/location-kit
https://developer.huawei.com/consumer/en/doc/harmonyos-guides/location-guidelines



Top comments (0)