news 2026/6/9 9:52:18

鸿蒙技术干货8:地理位置获取全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙技术干货8:地理位置获取全解析

承接上一篇的通知服务,今天咱们进入系列第二篇 —— 地理位置服务(geoLocationManager)。地理位置是位置提醒 APP 的核心依赖,无论是获取用户当前位置,还是判断是否到达目标区域,都离不开它。这篇咱们从权限配置、定位初始化、经纬度获取到定位模式优化,一步步拆解实战代码,让你快速掌握鸿蒙地理位置服务的核心用法!

一、地理位置服务核心认知

1. 核心应用场景

  • 位置提醒(如到达目的地、离开指定区域)
  • 周边服务推荐(如附近的餐厅、加油站)
  • 轨迹记录(如运动轨迹、出行路线)
  • 定位导航(如步行、驾车导航)

2. 核心模块与权限要求

  • 核心模块:@ohos.geolocation(geoLocationManager)
  • 必备权限:
    • 模糊定位:ohos.permission.APPROXIMATELY_LOCATION(基础必备)
    • 精确定位:ohos.permission.LOCATION(可选,需搭配模糊定位)
    • 后台定位:ohos.permission.LOCATION_IN_BACKGROUND(后台持续定位需声明)
  • 定位模式:高精度(GNSS + 网络)、低功耗(仅网络)、设备仅(仅 GNSS)

二、地理位置开发四步走:权限 - 初始化 - 定位 - 解析

1. 权限配置与申请(合规核心)

先在module.json5中声明权限:

{ "module": { "requestPermissions": [ { "name": "ohos.permission.APPROXIMATELY_LOCATION", "reason": "用于获取大致位置,提供位置提醒服务", "usedScene": { "abilities": ["MainAbility"], "when": "inuse" } }, { "name": "ohos.permission.LOCATION", "reason": "用于获取精准位置,提升提醒准确性", "usedScene": { "abilities": ["MainAbility"], "when": "inuse" } } ] } }

动态申请权限代码(复用系列第一篇的权限申请逻辑扩展):

import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; import common from '@ohos.app.ability.common'; // 定位权限组 const LOCATION_PERMISSIONS = [ 'ohos.permission.APPROXIMATELY_LOCATION', 'ohos.permission.LOCATION' ]; /** * 检查并申请定位权限 */ export async function requestLocationPermission(context: common.UIAbilityContext): Promise<boolean> { const atManager = abilityAccessCtrl.createAtManager(); try { // 检查权限状态 const authResults = await atManager.checkAccessToken( abilityAccessCtrl.createTokenID(), LOCATION_PERMISSIONS ); // 筛选未授权权限 const needReqPerms = LOCATION_PERMISSIONS.filter( (perm, index) => authResults[index] !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED ); if (needReqPerms.length === 0) { console.log('定位权限已全部授予'); return true; } // 动态申请权限 const reqResult = await atManager.requestPermissionsFromUser(context, needReqPerms); const allGranted = reqResult.authResults.every(status => status === 0); console.log(`定位权限申请结果:${allGranted ? '成功' : '失败'}`); return allGranted; } catch (err) { console.error(`定位权限处理异常:${JSON.stringify(err)}`); return false; } }

2. 定位初始化与配置

import geoLocationManager from '@ohos.geolocation'; // 全局存储定位订阅ID(用于取消定位) let locationSubscriptionId: number | null = null; /** * 初始化定位配置 * @returns 定位请求配置 */ export function initLocationConfig(): geoLocationManager.LocationRequest { // 配置定位参数 const locationRequest = { priority: geoLocationManager.LocationRequestPriority.HIGH_ACCURACY, // 高精度模式 interval: 5000, // 定位间隔(5秒一次,可根据需求调整) distance: 10, // 位置变化超过10米才触发回调(减少功耗) scenario: geoLocationManager.LocationScenario.NAVIGATION // 导航场景(适合位置跟踪) }; console.log('定位配置初始化完成'); return locationRequest; }

3. 获取实时经纬度(核心功能)

支持两种定位方式:单次定位(获取当前位置)和持续定位(实时跟踪位置):

typescript

运行

import geoLocationManager from '@ohos.geolocation'; /** * 单次定位:获取当前经纬度 */ export async function getSingleLocation(): Promise<{ latitude: number; longitude: number } | null> { try { const location = await geoLocationManager.getCurrentLocation(); const { latitude, longitude } = location; console.log(`单次定位成功:纬度=${latitude},经度=${longitude}`); return { latitude, longitude }; } catch (err) { console.error(`单次定位失败:${JSON.stringify(err)}`); return null; } } /** * 持续定位:实时监听位置变化 * @param callback 位置变化回调函数 */ export function startContinuousLocation( callback: (location: { latitude: number; longitude: number }) => void ) { const locationRequest = initLocationConfig(); // 订阅位置变化 locationSubscriptionId = geoLocationManager.on('locationChange', locationRequest, (location) => { const { latitude, longitude } = location; console.log(`持续定位更新:纬度=${latitude},经度=${longitude}`); callback({ latitude, longitude }); }); console.log('持续定位已启动,订阅ID:', locationSubscriptionId); } /** * 停止持续定位(释放资源) */ export function stopContinuousLocation() { if (locationSubscriptionId !== null) { geoLocationManager.off('locationChange', locationSubscriptionId); locationSubscriptionId = null; console.log('持续定位已停止'); } }

4. 位置数据解析与距离计算

位置提醒需要判断 “是否到达目标区域”,核心是计算当前位置与目标位置的直线距离:

typescript

运行

/** * 计算两点之间的直线距离(单位:米) * @param lat1 起点纬度 * @param lng1 起点经度 * @param lat2 终点纬度 * @param lng2 终点经度 * @returns 直线距离 */ export function calculateDistance( lat1: number, lng1: number, lat2: number, lng2: number ): number { const R = 6371000; // 地球半径(米) const radLat1 = Math.PI * lat1 / 180; const radLat2 = Math.PI * lat2 / 180; const deltaLat = radLat2 - radLat1; const deltaLng = Math.PI * (lng2 - lng1) / 180; const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; // 距离(米) } /** * 判断是否到达目标区域 * @param currentLoc 当前位置 * @param targetLoc 目标位置 * @param radius 提醒半径(米) * @returns 是否到达 */ export function isReachTargetArea( currentLoc: { latitude: number; longitude: number }, targetLoc: { latitude: number; longitude: number }, radius: number = 100 ): boolean { const distance = calculateDistance( currentLoc.latitude, currentLoc.longitude, targetLoc.latitude, targetLoc.longitude ); return distance <= radius; }

三、实战:定位功能整合演示

typescript

运行

@Entry @Component struct LocationDemoPage { private context = getContext(this) as common.UIAbilityContext; @State currentLocation: string = '未获取位置'; @State targetLocation: { latitude: number; longitude: number } = { latitude: 39.9042, // 北京天安门纬度 longitude: 116.4074 // 北京天安门经度 }; build() { Column({ space: 30 }) .width('100%') .height('100%') .padding(30) .backgroundColor('#f5f5f5') { Text('地理位置服务演示') .fontSize(32) .fontWeight(FontWeight.Bold) Text(`当前位置:${this.currentLocation}`) .fontSize(20) .width('100%') .textAlign(TextAlign.Center) Button('申请定位权限') .type(ButtonType.Capsule) .width(250) .height(60) .backgroundColor('#2f54eb') .onClick(async () => { const granted = await requestLocationPermission(this.context); Toast.show({ message: granted ? '定位权限申请成功' : '定位权限申请失败' }); }) Button('获取当前位置') .type(ButtonType.Capsule) .width(250) .height(60) .backgroundColor('#2f54eb') .onClick(async () => { const location = await getSingleLocation(); if (location) { this.currentLocation = `纬度:${location.latitude.toFixed(6)},经度:${location.longitude.toFixed(6)}`; // 判断是否到达目标区域 const reach = isReachTargetArea(location, this.targetLocation); if (reach) { Toast.show({ message: '已到达目标区域!' }); } } else { this.currentLocation = '位置获取失败'; } }) Button('启动持续定位') .type(ButtonType.Capsule) .width(250) .height(60) .backgroundColor('#2f54eb') .onClick(() => { startContinuousLocation((location) => { this.currentLocation = `纬度:${location.latitude.toFixed(6)},经度:${location.longitude.toFixed(6)}`; // 到达目标区域触发提醒(后续整合通知) if (isReachTargetArea(location, this.targetLocation)) { Toast.show({ message: '已到达目标区域,即将发送通知!' }); stopContinuousLocation(); // 到达后停止定位,减少功耗 } }); }) Button('停止持续定位') .type(ButtonType.Capsule) .width(250) .height(60) .backgroundColor('#ff4d4f') .onClick(() => { stopContinuousLocation(); }) } } }

四、实战踩坑指南

1. 定位失败的常见原因

  • ❶ 权限缺失:必须同时声明模糊定位权限,精确定位不能单独申请;
  • ❷ 定位模式不匹配:室内场景使用 “高精度模式”(GNSS + 网络),纯 GNSS 在室内可能无信号;
  • ❸ 设备定位开关关闭:需引导用户开启系统定位功能(代码可检测定位开关状态);
  • ❹ 后台定位权限未开启:持续定位需申请LOCATION_IN_BACKGROUND并引导用户手动开启。

2. 功耗优化技巧

  • ❶ 合理设置定位间隔:非实时导航场景建议间隔≥3 秒,距离阈值≥10 米;
  • ❷ 到达目标后停止定位:避免不必要的持续定位消耗电量;
  • ❸ 适配电池状态:低电量时切换为 “低功耗模式”(仅网络定位)。

加入班级,学习鸿蒙开发

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 1:58:11

Jsp的四种作用域(超详细)

在 JSP 中&#xff0c;作用域&#xff08;Scope&#xff09; 是指 JSP 内置对象&#xff08;如request、session、application、pageContext&#xff09;中存储的数据的有效范围&#xff0c;它决定了数据能在哪些组件、哪些请求或哪些用户之间共享。JSP 共有四种核心作用域&…

作者头像 李华
网站建设 2026/6/8 13:47:17

vue自定义组件this.$emit(“refresh“);

在Vue中&#xff0c;组件间的通信通常通过事件系统来实现。当你想要在自定义组件中触发一个事件&#xff0c;以便父组件能够监听到这个事件并作出响应&#xff0c;你可以使用$emit方法。下面是如何在自定义组件中触发一个名为refresh的事件的步骤&#xff1a; 在子组件中触发事…

作者头像 李华
网站建设 2026/6/4 19:22:39

如何快速启用WPS宏功能:VBA 7.1免费安装终极指南

如何快速启用WPS宏功能&#xff1a;VBA 7.1免费安装终极指南 【免费下载链接】VBA7.1安装包及安装方法 本仓库提供了一个重要的资源文件&#xff1a;**VBA 7.1 各国语言安装包**。该安装包是随 Office 一起发布的独立安装包&#xff0c;非常珍贵。它特别适用于那些使用 WPS 但没…

作者头像 李华
网站建设 2026/6/9 21:01:26

电缆护层保护器的差异化!

电缆护层保护器是保障电力电缆系统安全稳定运行的核心防护设备&#xff0c;其多样化设计可精准匹配不同应用场景的差异化防护需求。应用场景覆盖极为广泛&#xff0c;囊括中低压配网电缆、高压输电电缆、海底特种电缆、轨道交通专用电缆及化工/矿山等特殊恶劣环境的电缆线路&am…

作者头像 李华
网站建设 2026/6/7 13:05:18

计组:一些记忆点和题

程序的局部性原理 程序的局部性原理是计算机体系结构的核心原理之一&#xff0c;是 Cache、虚拟内存等技术的设计基础&#xff0c;指程序在执行过程中&#xff0c;倾向于访问局部范围内的指令和数据&#xff0c;具体分为时间局部性和空间局部性两类。 类型核心概念典型场景时…

作者头像 李华
网站建设 2026/6/9 19:48:31

35、开源项目非营利组织运营指南

开源项目非营利组织运营指南 在开源项目的发展中,成立非营利基金会是许多项目推动自身发展的重要途径。许多启动了非营利基金会的开源项目会在网上公开其成立文件,例如可以在 http://apache.org/foundation/bylaws.html 查看 Apache 基金会的章程。 免税资格申请 慈善非营…

作者头像 李华