【HarmonyOS实战】 LocationKit定位服务:获取用户位置完整指南
文章目录
- 前言
- 一、getMyLocation 方法
- 二、项目中的两次定位
- 三、getCurrentLocation 的参数
- 3.1 LocationRequestPriority(优先策略)
- 3.2 LocationRequestScenario(使用场景)
- 四、持续定位:on/off locationChange
- 五、定位失败处理
- 六、setMyLocation:设置地图的"我的位置"
- 七、定位在项目中的完整使用链路
- 八、定位最佳实践
- 8.1 只在需要时定位
- 8.2 缓存位置结果
- 8.3 权限问题导致定位失败
- 总结
前言
知道用户在哪,是"附近加油站"最核心的能力。这个能力来自LocationKit,通过geoLocationManager模块实现。
项目里获取位置的代码看起来很简单——就一行await geoLocationManager.getCurrentLocation(),但背后有不少值得深入的地方:定位方式选择、精度控制、异步处理、持续定位。这篇文章全部讲清楚。
项目预览
一、getMyLocation 方法
// MapUtil.etsasyncgetMyLocation():Promise<geoLocationManager.Location>{letlocation:geoLocationManager.Location=awaitgeoLocationManager.getCurrentLocation();returnlocation;}geoLocationManager.getCurrentLocation()是一次性定位:获取当前时刻的位置,返回后结束。
调用返回的Location对象结构:
interfaceLocation{latitude:number;// 纬度(WGS84)longitude:number;// 经度(WGS84)altitude:number;// 海拔(米)accuracy:number;// 水平精度(米,越小越精准)speed:number;// 移动速度(m/s)timeStamp:number;// 时间戳direction:number;// 方向角(0-360,正北为0)altitudeAccuracy:number;// 海拔精度additionSize:number;// 附加信息大小}二、项目中的两次定位
// GasStationPage.ets callback 里mapUtil.moveToMyLocation(mapController);// 第一次:移动地图到当前位置this.currentLatitude=(awaitmapUtil.getMyLocation()).latitude;// 第二次this.currentLongitude=(awaitmapUtil.getMyLocation()).longitude;// 获取坐标存起来定位被调用了两次,实际上效率不高(发了两次定位请求)。更优的写法是:
// 优化:只定位一次letlocation=awaitmapUtil.getMyLocation();this.currentLatitude=location.latitude;this.currentLongitude=location.longitude;this.latitude=this.currentLatitude;this.longitude=this.currentLongitude;awaitmapUtil.moveToMyLocation(mapController);// 内部也调用了一次 getMyLocation实际上moveToMyLocation内部也调用了一次getMyLocation,总共三次定位请求。对于演示项目来说这没问题,实际项目里可以缓存位置结果避免重复请求。
三、getCurrentLocation 的参数
不传参时,系统使用默认定位配置。如果需要自定义精度和超时:
// 指定定位请求参数letrequestParam:geoLocationManager.CurrentLocationRequest={priority:geoLocationManager.LocationRequestPriority.FIRST_FIX,// 优先策略scenario:geoLocationManager.LocationRequestScenario.UNSET,// 使用场景maxAccuracy:100,// 最大可接受精度(米),0表示不限制timeoutMs:10000,// 超时时间(毫秒)};letlocation=awaitgeoLocationManager.getCurrentLocation(requestParam);3.1 LocationRequestPriority(优先策略)
| 策略 | 说明 | 耗电 |
|---|---|---|
FIRST_FIX | 尽快返回位置(精度可能低) | 低 |
ACCURACY | 高精度优先(等待更准确的位置) | 高 |
LOW_POWER | 省电模式(精度最低) | 最低 |
UNSET | 未设置,系统决定 | 中等 |
3.2 LocationRequestScenario(使用场景)
enumLocationRequestScenario{UNSET,// 未设置NAVIGATION,// 导航场景(高频率、高精度)TRAJECTORY_TRACKING,// 轨迹记录CAR_HAILING,// 打车场景DAILY_LIFE_SERVICE,// 日常生活(本项目适合这个)NO_POWER,// 不主动定位,只接收其他应用的定位结果}四、持续定位:on/off locationChange
getCurrentLocation是一次性的,如果需要实时跟踪用户位置,用持续定位:
// 开始持续定位geoLocationManager.on('locationChange',locationRequest,(location)=>{console.log(`位置更新:${location.latitude},${location.longitude}`);// 更新地图上的用户位置this.mapController?.setMyLocation(location);});// 停止持续定位(页面销毁时调用)geoLocationManager.off('locationChange',callback);持续定位的请求参数:
letlocationRequest:geoLocationManager.LocationRequest={priority:geoLocationManager.LocationRequestPriority.ACCURACY,scenario:geoLocationManager.LocationRequestScenario.NAVIGATION,timeInterval:3,// 定位间隔(秒)distanceInterval:5,// 位置变化超过 5 米才触发回调maxAccuracy:50,// 精度要求 50 米内};五、定位失败处理
getCurrentLocation返回 Promise,失败时 reject:
// 完整的错误处理asyncgetMyLocation():Promise<geoLocationManager.Location|null>{try{letlocation=awaitgeoLocationManager.getCurrentLocation();returnlocation;}catch(err){leterror=errasBusinessError;Logger.error('MapUtil',`定位失败: code=${error.code}, msg=${error.message}`);// 根据错误码做不同处理switch(error.code){case201:// 权限不足Logger.error('MapUtil','没有定位权限,请用户授权');break;case3301000:// 定位功能未开启Logger.error('MapUtil','请开启设备定位功能');break;case3301100:// 定位超时Logger.error('MapUtil','定位超时,请稍后重试');break;default:Logger.error('MapUtil','定位服务异常');}returnnull;}}常见错误码:
| 错误码 | 含义 |
|---|---|
| 201 | 权限检查失败 |
| 401 | 参数错误 |
| 3301000 | 位置服务不可用(未开启) |
| 3301100 | 定位超时 |
| 3301200 | 反向地理编码失败 |
六、setMyLocation:设置地图的"我的位置"
// MapUtil.ets - moveToMyLocationmapController?.setMyLocation(location);setMyLocation是 MapKit 的方法(不是 LocationKit),它接收一个位置信息,在地图上显示蓝色定位圆点:
mapController.setMyLocation(location:geoLocationManager.Location):void;注意:setMyLocation接受的是WGS84 坐标(geoLocationManager 返回的原始位置),MapKit 内部会自动处理坐标转换,在地图(GCJ02)上正确显示位置。
七、定位在项目中的完整使用链路
申请权限(MainPage.aboutToAppear) └─> PermissionsUtil.checkPermissions(['LOCATION', 'APPROXIMATELY_LOCATION']) └─> 用户授权后 → geoLocationManager.getCurrentLocation() 激活定位 地图初始化(GasStationPage callback) ├─> mapUtil.moveToMyLocation(controller) │ ├─> geoLocationManager.getCurrentLocation() → location (WGS84) │ ├─> mapController.setMyLocation(location) → 地图显示蓝点 │ ├─> convertToGCJ02(location.lat, location.lon) → gcj02 │ └─> animateCamera(gcj02, zoom=15.9) → 镜头移动 │ └─> mapUtil.getMyLocation() × 2 └─> geoLocationManager.getCurrentLocation() → currentLatitude/Longitude └─> 存储,用于后续计算到各加油站的距离八、定位最佳实践
8.1 只在需要时定位
不要一进入应用就持续定位,只在需要位置信息时调用,用完就停。这个项目只在地图页使用位置,完全没问题。
8.2 缓存位置结果
同一次用户操作里多次需要位置,缓存第一次的结果:
// MapUtil 里添加缓存privatecachedLocation:geoLocationManager.Location|null=null;privatelastLocationTime:number=0;privateCACHE_DURATION=10000;// 10秒内的位置可以复用asyncgetMyLocation():Promise<geoLocationManager.Location>{letnow=Date.now();if(this.cachedLocation&&(now-this.lastLocationTime)<this.CACHE_DURATION){returnthis.cachedLocation;// 返回缓存}letlocation=awaitgeoLocationManager.getCurrentLocation();this.cachedLocation=location;this.lastLocationTime=now;returnlocation;}8.3 权限问题导致定位失败
getCurrentLocation在没有定位权限时会报 201 错误。所以一定要先申请权限,再调用定位——这也是项目在主页就申请权限的原因。
总结
LocationKit 的核心 API 就两个:
- 一次性定位:
geoLocationManager.getCurrentLocation()→ 返回当前位置(WGS84) - 持续定位:
on('locationChange', request, callback)→ 实时位置更新
使用注意事项:
- 先申请
LOCATION+APPROXIMATELY_LOCATION权限 - 返回的坐标是WGS84,显示在地图上要转 GCJ02
- 做好错误处理(超时、权限不足、服务不可用)
- 避免重复定位,缓存位置结果
下一篇讲暗色模式与多语言适配——color.json双套配置和string.json多语言是怎么工作的。
