当前位置: 首页 > news >正文

【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 就两个:

  1. 一次性定位geoLocationManager.getCurrentLocation()→ 返回当前位置(WGS84)
  2. 持续定位on('locationChange', request, callback)→ 实时位置更新

使用注意事项:

  • 先申请LOCATION+APPROXIMATELY_LOCATION权限
  • 返回的坐标是WGS84,显示在地图上要转 GCJ02
  • 做好错误处理(超时、权限不足、服务不可用)
  • 避免重复定位,缓存位置结果

下一篇讲暗色模式与多语言适配——color.json双套配置和string.json多语言是怎么工作的。

http://www.jsqmd.com/news/965748/

相关文章:

  • Matlab鱼雷刚体运动仿真:俯仰/偏航/深度/航速四维动态可视化
  • 无需鼠标!借助键盘实现快速鼠标控制
  • MicroPython固件“魔改”指南:以BLACK_F407ZG为例,自定义你的板载LED、串口和SPI引脚
  • 别再只盯着GPS了!精度因子(DOP)在Wi-Fi/蓝牙定位里同样关键
  • 当“观察力”成为产品核心:从一篇小说看如何设计真正“被看见”的用户体验
  • 从数据到洞察:手把手教你用Python处理卫星测高数据计算SLA/SSHA
  • ai一键生成vivado安装验证脚本,快速搭建fpga开发环境
  • 从F1赛车到无人机避障:聊聊脉冲雷达‘测不准’的那些事儿与工程解法
  • KMS智能激活工具:高效解决Windows和Office激活难题
  • CPU上的LLM推理加速:AMX指令集与稀疏化技术
  • 给奈奎斯特图‘加点料’:一个零点如何让系统频率响应大变样?
  • 高效Windows内存优化指南:3步掌握Mem Reduct智能内存管理技巧
  • 告别环境冲突:用Docker一键部署Matconvnet(支持Matlab 2020b + CUDA 11)
  • 瑞萨e2 studio调试配置全解析:Connection Settings里那个200mA选项到底该不该勾?
  • 【HarmonyOS实战】 暗色模式与国际化:一套代码适配多套皮肤和语言
  • AI虚拟城市主义:生成式模型与城市身份量化分析
  • 告别复制粘贴:手把手教你为任意STM32F4开发板定制MicroPython引脚配置文件
  • 别再手动试错了!用Minitab 21做全因子DOE,5步搞定工艺参数优化
  • 从Linux命令行到MinIO存储桶:一份给运维的mc命令对照手册(含实战脚本)
  • e2 studio调试总失败?别慌,先检查这3个配置项(含Connection Settings详解)
  • 物理信息神经网络与随机增广拉格朗日方法解析
  • 别再死记硬背了!用Proteus 8.9仿真51单片机,手把手教你搭建第一个流水灯电路
  • CANoe自动化配置进阶:如何用CommunicationSetup接口批量管理你的应用模型和数据源
  • 用Arduino Uno和PAJ7620手势传感器做个智能台灯:手势控制开关/调光/流水灯(附完整代码)
  • 2026年5月国内电动两轮高端改装灯具品牌排行:行业电动两轮高端灯具/顶级灯具设计研发/高端两轮灯具/高端灯具研发首家/选择指南 - 优质品牌商家
  • 从零开始搞懂SoC:芯片设计中的‘大脑’与‘高速公路’(AMBA总线篇)
  • 手把手教你将GCNv2特征提取器‘抠’出来做双目匹配测试(附完整C++代码)
  • 3分钟掌握Keyviz:让屏幕操作从此不再神秘
  • 从《半日》到代码人生:一个程序员如何用技术工具高效啃下大学英语精读(附Anki+欧路词典配置)
  • 从金融量化到数据分析:Pandas 0.20.0的诞生故事与核心设计思想