OpenHarmony Location Kit技术详解:定位、地理围栏与编码转换
概述
OpenHarmony位置服务(Location Kit)是一套完整的定位服务解决方案,为开发者提供多种定位能力和位置相关功能。Location Kit支持多种定位技术,包括GNSS(全球导航卫星系统)、基站定位、WLAN定位和蓝牙定位等,能够满足不同应用场景下的定位需求。
位置服务提供的主要功能包括:
- 设备位置获取(单次定位和连续定位)
- 地理围栏管理
- 地理编码与逆地理编码转换
- 位置权限管理
- 云侧地理围栏扩展能力
系统架构
Location Kit采用分层架构设计,主要包括以下层次:
- 应用层:提供ArkTS和C/C++两种开发接口,满足不同开发需求
- 服务层:负责位置服务的核心功能实现,包括定位算法、地理围栏管理等
- 硬件抽象层:适配不同的定位硬件和传感器
- 数据源层:整合多种定位数据源,包括GNSS、基站、WLAN和蓝牙等
核心功能模块
1. 位置获取
Location Kit支持两种位置获取方式:
1.1 单次定位
通过getCurrentLocation接口获取当前位置信息,适用于需要即时获取位置的场景,如签到打卡、拍照记录位置等。
1.2 连续定位
通过on('locationChange')接口订阅位置变化事件,适用于需要持续跟踪位置变化的场景,如导航、轨迹记录等。
2. 地理围栏
地理围栏功能允许开发者定义虚拟地理边界,当设备进入、离开或停留在这些区域时触发相应事件。
2.1 设备侧地理围栏
基于设备自身定位能力实现的地理围栏,支持圆形围栏,主要适用于室外GNSS环境下的应用场景,如广告推送、安全区域监控等。
2.2 云侧地理围栏
通过FenceExtensionAbility实现的云侧地理围栏扩展能力,支持更复杂的围栏逻辑和云端协同处理。
3. 地理编码与逆地理编码
3.1 地理编码
将地理描述(如地址、地标名称)转换为坐标信息,通过getAddressesFromLocationName接口实现。
3.2 逆地理编码
将坐标信息转换为地理描述,通过getAddressesFromLocation接口实现。
4. 位置权限管理
Location Kit提供精细化的位置权限控制:
ohos.permission.LOCATION:获取精准位置,精度在米级别ohos.permission.APPROXIMATELY_LOCATION:获取模糊位置,精确度为5公里ohos.permission.LOCATION_IN_BACKGROUND:应用在后台时仍可获取位置信息
开发接口
ArkTS接口
1. 位置获取
import { geoLocationManager } from '@kit.LocationKit';// 检查位置开关状态
async function checkLocationEnabled(): Promise<boolean> {return await geoLocationManager.isLocationEnabled();
}// 单次定位
async function getCurrentLocation() {try {const requestInfo: geoLocationManager.LocationRequest = {'priority': geoLocationManager.LocationRequestPriority.ACCURACY,'timeInterval': 1,'distanceInterval': 0,'maxAccuracy': 0};const location = await geoLocationManager.getCurrentLocation(requestInfo);console.log(`当前位置: 纬度${location.latitude}, 经度${location.longitude}`);return location;} catch (error) {console.error('获取位置失败:', error);}
}// 订阅位置变化
function subscribeLocationChange() {const requestInfo: geoLocationManager.LocationRequest = {'priority': geoLocationManager.LocationRequestPriority.ACCURACY,'timeInterval': 1,'distanceInterval': 0,'maxAccuracy': 0};geoLocationManager.on('locationChange', requestInfo, (location) => {console.log(`位置更新: 纬度${location.latitude}, 经度${location.longitude}`);});
}// 取消订阅位置变化
function unsubscribeLocationChange() {geoLocationManager.off('locationChange');
}
2. 地理围栏
import { geoLocationManager } from '@kit.LocationKit';// 添加GNSS地理围栏
async function addGeofence() {const geofenceRequest: geoLocationManager.GeofenceRequest = {"priority": geoLocationManager.GeofenceRequestPriority.ACCURACY,"geofence": {"latitude": 39.9,"longitude": 116.4,"radius": 200,"expiration": 10000}};const geofenceId = await geoLocationManager.addGnssGeofence(geofenceRequest);console.log(`地理围栏ID: ${geofenceId}`);return geofenceId;
}// 监听地理围栏状态变化
function listenGeofenceStatusChange() {geoLocationManager.on('gnssFenceStatusChange', (geofence) => {console.log(`围栏状态变化: ID=${geofence.geofenceId}, 事件=${geofence.transitionEvent}`);});
}// 移除地理围栏
async function removeGeofence(geofenceId: number) {await geoLocationManager.removeGnssGeofence(geofenceId);console.log(`已移除地理围栏: ${geofenceId}`);
}
3. 地理编码与逆地理编码
import { geoLocationManager } from '@kit.LocationKit';// 地理编码:地址转坐标
async function geocode() {try {const isAvailable = await geoLocationManager.isGeocoderAvailable();if (!isAvailable) {console.error('地理编码服务不可用');return;}const geocodeRequest: geoLocationManager.GeoAddress = {"description": "北京市海淀区","maxItems": 1};const addresses = await geoLocationManager.getAddressesFromLocationName(geocodeRequest);if (addresses.length > 0) {const address = addresses[0];console.log(`坐标: 纬度${address.latitude}, 经度${address.longitude}`);}} catch (error) {console.error('地理编码失败:', error);}
}// 逆地理编码:坐标转地址
async function reverseGeocode(latitude: number, longitude: number) {try {const isAvailable = await geoLocationManager.isGeocoderAvailable();if (!isAvailable) {console.error('逆地理编码服务不可用');return;}const reverseGeocodeRequest: geoLocationManager.GeoAddress = {"latitude": latitude,"longitude": longitude,"maxItems": 1};const addresses = await geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest);if (addresses.length > 0) {const address = addresses[0];console.log(`地址: ${address.description}`);}} catch (error) {console.error('逆地理编码失败:', error);}
}
4. FenceExtensionAbility实现
import { FenceExtensionAbility, geoLocationManager } from '@kit.LocationKit';
import { notificationManager } from '@kit.NotificationKit';
import { Want, wantAgent } from '@kit.AbilityKit';export class MyFenceExtensionAbility extends FenceExtensionAbility {onFenceStatusChange(transition: geoLocationManager.GeofenceTransition, additions: Record<string, string>): void {// 接受围栏状态变化事件,处理业务逻辑console.info(`围栏状态变化: ID=${transition.geofenceId}, 事件=${transition.transitionEvent}`);// 可以发送围栏业务通知let wantAgentInfo: wantAgent.WantAgentInfo = {wants: [{bundleName: 'com.example.myapplication',abilityName: 'EntryAbility',parameters: {"geofenceId": transition?.geofenceId,"transitionEvent": transition?.transitionEvent,}} as Want],actionType: wantAgent.OperationType.START_ABILITY,requestCode: 100};wantAgent.getWantAgent(wantAgentInfo).then((wantAgentMy) => {let notificationRequest: notificationManager.NotificationRequest = {id: 1,content: {notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,normal: {title: `围栏通知`,text: `围栏状态变化: ID=${transition.geofenceId}, 事件=${transition.transitionEvent}`,}},notificationSlotType: notificationManager.SlotType.SOCIAL_COMMUNICATION,wantAgent: wantAgentMy};notificationManager.publish(notificationRequest);});}onDestroy(): void {console.info('FenceExtensionAbility销毁');}
}
C/C++接口
Location Kit也提供了C/C++接口,适用于需要高性能或底层控制的应用场景。
1. 基本配置
#include "LocationKit/oh_location.h"
#include "LocationKit/oh_location_type.h"
#include "hilog/log.h"
#include <stdlib.h>// 创建位置请求配置
struct Location_RequestConfig *g_requestConfig = NULL;
void *mydata = NULL;
2. 检查位置服务状态
static napi_value OhLocationIsEnabled(napi_env env, napi_callback_info info)
{bool isEnabled = false;int resultCode = OH_Location_IsLocatingEnabled(&isEnabled);napi_value result = NULL;napi_get_boolean(env, isEnabled, &result);return result;
}
3. 位置订阅与取消订阅
// 定义回调函数接收位置信息
void reportLocation(Location_Info* location, void* userData)
{Location_BasicInfo baseInfo = OH_LocationInfo_GetBasicInfo(location);char additionalInfo[1024] = "";Location_ResultCode result = OH_LocationInfo_GetAdditionalInfo(location, additionalInfo, sizeof(additionalInfo));OH_LOG_INFO(LOG_APP, "位置信息: 纬度=%f, 经度=%f", baseInfo.latitude, baseInfo.longitude);if (mydata == userData) {OH_LOG_INFO(LOG_APP, "用户数据匹配");}return;
}// 订阅位置信息
static napi_value OhLocationStartLocating(napi_env env, napi_callback_info info)
{if (g_requestConfig == NULL) {g_requestConfig = OH_Location_CreateRequestConfig();}OH_LocationRequestConfig_SetUseScene(g_requestConfig, LOCATION_USE_SCENE_NAVIGATION);OH_LocationRequestConfig_SetInterval(g_requestConfig, 1);mydata = (void *)malloc(sizeof("mydata")); // 用户自定义任意类型,callback 透传返回OH_LocationRequestConfig_SetCallback(g_requestConfig, reportLocation, mydata);OH_Location_StartLocating(g_requestConfig);int32_t ret = 0;napi_value result = NULL;napi_create_int32(env, ret, &result);return result;
}// 取消订阅位置信息
static napi_value OhLocationStopLocating(napi_env env, napi_callback_info info)
{OH_Location_StopLocating(g_requestConfig);if (g_requestConfig != NULL) {OH_Location_DestroyRequestConfig(g_requestConfig);g_requestConfig = NULL;}free(mydata);mydata = NULL;int32_t ret = 0;napi_value result = NULL;napi_create_int32(env, ret, &result);return result;
}
4. 模块初始化
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{napi_property_descriptor desc[] = {{"ohLocationIsEnabled", NULL, OhLocationIsEnabled, NULL, NULL, NULL, napi_default, NULL},{"ohLocationStartLocating", NULL, OhLocationStartLocating, NULL, NULL, NULL, napi_default, NULL},{"ohLocationStopLocating", NULL, OhLocationStopLocating, NULL, NULL, NULL, napi_default, NULL},};napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);return exports;
}
EXTERN_C_END
权限要求
基本权限
使用Location Kit需要在应用配置文件中声明以下权限:
{"module": {"requestPermissions": [{"name": "ohos.permission.LOCATION","reason": "$string:location_reason","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}},{"name": "ohos.permission.APPROXIMATELY_LOCATION","reason": "$string:location_reason","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}}]}
}
后台定位权限
如果应用需要在后台获取位置信息,除了基本位置权限外,还需要:
- 申请
ohos.permission.LOCATION_IN_BACKGROUND权限 - 申请LOCATION类型的长时任务
权限申请策略
| 申请位置权限的方式 | 是否允许申请 | 申请成功后获取的位置的精确度 |
|---|---|---|
| 申请ohos.permission.APPROXIMATELY_LOCATION | 是 | 获取到模糊位置,精确度为5公里。 |
| 同时申请ohos.permission.APPROXIMATELY_LOCATION和ohos.permission.LOCATION | 是 | 获取到精准位置,精准度在米级别。 |
约束与限制
- 位置开关:使用Location Kit前需要确保设备的位置服务开关已开启
- 权限授权:应用必须获得用户授权才能访问位置信息
- 坐标系:Location Kit使用WGS-84坐标系
- 地理围栏限制:
- 设备侧地理围栏主要适用于室外GNSS环境
- 同一应用最多可创建1000个地理围栏
- 围栏半径范围:1米到100000米
- 后台定位限制:应用在后台使用位置服务需要申请长时任务
总结
OpenHarmony Location Kit提供了全面的位置服务能力,支持多种定位技术和应用场景。开发者可以根据应用需求选择合适的接口和定位策略,实现丰富多样的位置相关功能。在使用Location Kit时,需要特别注意权限管理和资源优化,以提供良好的用户体验并保护用户隐私。
