写点什么

探索 HarmonyOS 位置服务:精准定位的科技奥秘

作者:白晓明
  • 2024-08-17
    宁夏
  • 本文字数:6630 字

    阅读完需:约 22 分钟

探索HarmonyOS位置服务:精准定位的科技奥秘

关于作者

白晓明

宁夏图尔科技有限公司董事长兼 CEO、坚果派联合创始人

华为 HDE、润和软件 HiHope 社区专家、鸿蒙 KOL、仓颉 KOL

华为开发者学堂/51CTO 学堂/CSDN 学堂认证讲师

开放原子开源基金会 2023 开源贡献之星

公众号:开源开发者新视界(openwatcher)


数字化飞速发展的今天,我们所拥有的智能设备中各种各样的应用程序,其中的位置服务功能正悄然改变着我们的生活方式。比如外卖订餐 App 可根据我们所在位置推荐周边商家和外卖小哥,短视频 App 可根据我们所在位置推荐周边用户发布的视频。再比如导航类 App 精准地确定我们的位置,并为我们规划出最佳的出现路线,无论是日常通勤还是陌生城市的探索,都能让我们轻松找到目的地,避免迷路的困扰。当然在紧急情况下,位置服务还可以为救援人员提供准确的位置信息,缩短救援时间。


HarmonyOS 位置服务(Location Kit)使用以下多种定位技术提供服务,为用户提供准确地位置信息。


  • 坐标:HarmonyOS 以 1984 年世界大地坐标系统为参考,使用经度、纬度数据描述地球上的一个位置。

  • GNSS 定位:基于全球导航卫星系统,包括 GPS、GLONASS、北斗、Galileo 等,通过导航卫星、设备芯片提供的定位算法,来确定设备准确的位置。定位过程具体使用哪些定位系统,取决于用户设备的硬件能力。

  • 基站定位:根据设备当前驻网基站和相邻基站的位置,估算设备当前位置。此定位方式的定位结果精度较低,并且需要设备可以访问蜂窝网络。

  • WLAN/蓝牙定位:根据设备可搜索到的周围 WLAN、蓝牙设备位置,估算设备当前位置。此定位方式的定位结果精度依赖于设备周围可见的固定 WLAN、蓝牙设备的分布,密度较高时,精度也相较于基站定位方式更高,同时也需要设备可以访问网络。


HarmonyOS 位置服务(Location Kit)除了提供基础的定位服务之外,还提供了地理围栏、地理编码、逆地理编码、国家码等功能和接口。


应用程序的位置服务,如同一把双刃剑,既为我们的生活带来了前所未有的便利和精彩,也需要我们在享受其好处的同时,注重个人隐私的保护。在 HarmonyOS 中,当应用程序处于业务场景且需要位置服务(Location Kit)时,系统进行了严格的约束与限制。这一举措旨在保护用户的隐私安全,确保位置信息不被滥用。使用设备位置能力时,需要用户进行确认并主动开启位置开关。若位置开关未开启,系统不会向任何应用提供定位服务。由于设备位置属于用户敏感数据,所以即使用户已经开启位置开关,应用在获取设备位置前仍需要向用户申请位置访问权限。在用户确认允许后,系统才会向应用提供定位服务,如下图所示。



module.json5配置文件中声明位置权限

应用程序要想使用位置信息,需要检查是否已经获取用户授权访问设备位置信息,若未获得授权,可以向用户申请需要的位置权限。系统提供的定位权限有:



加入 App 运行在前台,且访问设备当前的精准位置信息,需要在module.json5中申请如下权限,并向用户申请授权,具体可参考https://xie.infoq.cn/article/67f540652c1661c8630ab3678


{  "module": {    ...    "requestPermissions": [      {        "name": "ohos.permission.LOCATION",  // 权限名称,为系统已定义的权限        "reason": "$string:location_reason",  // 申请权限的原因,当申请权限为user_grant权限时该字段为必填        "usedScene": {  // 用于描述权限使用场景,当申请权限为user_grant权限时该字段为必填          "abilities": [            "EntryAbility"          ],          "when": "inuse"  // 调用时机(inuse:使用时;always:始终)        }      },      {        "name": "ohos.permission.APPROXIMATELY_LOCATION",        "reason": "$string:location_reason",        "usedScene": {          "abilities": [            "EntryAbility"          ],          "when": "inuse"        }      }    ]  }}
复制代码

导入geoLocationManager模块

geoLocationManager模块提供 GNSS 定位、网络定位(蜂窝基站、WLAN、蓝牙定位技术)、地理编码、逆地理编码、国家码和地理围栏等基本功能 API。


import { geoLocationManager } from '@kit.LocationKit'
复制代码

获取当前设备位置

单次获取当前设备位置

多用于查看当前位置、签到打卡、服务推荐等场景。需要实例化SingleLocationRequest对象,用于告知系统该向应用提供何种类型的位置服务,以及单次定位超时时间。


/** * 单次定位的请求参数 */export interface SingleLocationRequest {    /**     * 优先级信息     */    locatingPriority: LocatingPriority;    /**     * 超时时间,单位是毫秒     */    locatingTimeoutMs: number;}
复制代码


如果对位置的返回精度要求较高,建议LocatingPriority参数优先选择PRIORITY_ACCURACY,会将一段时间内精度较好的结果返回给应用。


如果对定位速度要求较高,建议LocatingPriority参数优先选择PRIORITY_LOCATING_SPEED,会将最先拿到的定位结果返回给应用。


/** * 单次位置请求中的优先级类型 */export enum LocatingPriority {    /**     * 精度优先。     * 定位精度优先策略会同时使用GNSS定位和网络定位技术,并将一段时间内精度较好的结果返回给应用。     * 这个时间段长度为SignleLocationRequest.locationTimeoutMs与“30秒”中的较小者。     * 对设备的硬件资源消耗较大,功耗较大。     */    PRIORITY_ACCURACY = 0x501,    /**     * 快速获取位置优先。     * 快速定位优先策略会同时使用GNSS定位和网络定位技术,以便在室内和户外场景下均可以快速获取到位置结果。     * 对设备的硬件资源消耗较大,功耗也较大。     */    PRIORITY_LOCATING_SPEED = 0x502}
复制代码


以快速定位策略(PRIORITY_LOCATING_SPEED)为例,调用方式如下:


/** * 单次获取当前位置信息 * @param priority * @param timeout * @returns */static async getSingleLocationRequest(priority: geoLocationManager.LocatingPriority,  timeout: number = 10000): Promise<geoLocationManager.Location | undefined> {  const request: geoLocationManager.SingleLocationRequest = {    locatingPriority: priority,    locatingTimeoutMs: timeout  };  let location: geoLocationManager.Location | undefined = undefined;  try {    location = await geoLocationManager.getCurrentLocation(request);    console.info(`[AppLogger]单次获取当前位置信息:${JSON.stringify(location)}`);  } catch (error) {    const err = error as BusinessError;    console.error(`[AppLogger]单次获取当前位置信息异常:${JSON.stringify(err)}`);  }  return location;}

Button('单次获取当前位置信息') .onClick(async () => { this.location = await LocationUtil.getSingleLocationRequest(geoLocationManager.LocatingPriority.PRIORITY_LOCATING_SPEED); })
复制代码



以上是通过实例化SingleLocationRequest对象来获取当前位置信息,还可以实例化当前位置信息请求参数CurrentLocationRequest来获取当前位置信息,可以根据业务选择使用合适的实例化对象。


/** * 当前位置信息请求参数 */export interface CurrentLocationRequest {    /**     * 位置请求中位置信息优先级类型。     * 当scenario取值为UNSET时,priority参数生效,否则priority参数不生效。     * 当scenario和priority均取值为UNSET时,无法发起定位请求。     */    priority?: LocationRequestPriority;    /**     * 位置请求中定位场景类型。     * 当scenario取值为UNSET时,priority参数生效,否则priority参数不生效。     * 当scenario和priority均取值为UNSET时,无法发起定位请求。     */    scenario?: LocationRequestScenario;    /**     * 精度信息,单位为米。     * 仅在精确位置功能场景(同时授予了ohos.permission.APPROXIMATELY_LOCATION和ohos.permission.LOCATION 权限)下有效,模糊位置功能生效场景(仅授予了ohos.permission.APPROXIMATELY_LOCATION 权限)下该字段无意义。     * 当scenario为NAVIGATION/TRAJECTORY_TRACKING/CAR_HAILING或者priority为ACCURACY时建议设置maxAccuracy为大于10的值。     * 当scenario为DAILY_LIFE_SERVICE/NO_POWER或者priority为LOW_POWER/FIRST_FIX时建议设置maxAccuracy为大于100的值。     * 默认值为0,取值范围为大于等于0。     */    maxAccuracy?: number;    /**     * 超时时间,单位为毫秒。     */    timeoutMs?: number;}

/** * 位置请求中位置信息优先级类型 */export enum LocationRequestPriority { /** * 默认优先级,表示未设置优先级,LocationRequestPriority无效。 */ UNSET = 0x200, /** * 精度优先。 * 定位精度优先策略主要以GNSS定位技术为主,会在GNSS提供稳定位置结果之前使用网络定位技术提供服务。 * 在持续定位过程中,如果超过30秒无法获取GNSS定位结果则使用网络定位技术。 */ ACCURACY, /** * 低功耗优先。 * 低功耗定位优先策略仅使用网络定位技术,在室内和户外场景均可提供定位服务。 * 由于其依赖周边基站、可见WLAN、蓝牙设备的分布情况,定位结果精度波动范围较大,推荐在定位结果精度要求不高的场景下使用。 */ LOW_POWER, /** * 快速获取位置优先。 * 快速定位优先策略会同时使用GNSS定位和网络技术定位,以便在室内和户外场景下均可以快速获取到位置结果。 */ FIRST_FIX}

/** * 位置请求中定位场景类型 */export enum LocationRequestScenario { /** * 默认场景信息,表示未设置场景信息。 * LocationRequestScenario字段无效。 */ UNSET = 0x300, /** * 导航场景。 * 适用于在户外获取设备实时位置的场景,如车载、步行导航。 * 主要是用GNSS定位技术提供定位服务。 */ NAVIGATION, /** * 表示运动轨迹记录场景。 * 适用于记录用户位置轨迹的场景,如运动类应用记录轨迹功能。 * 主要使用GNSS定位技术提供定位服务。 */ TRAJECTORY_TRACKING, /** * 打车场景。 * 适用于用户出行打车时定位当前位置的场景,如网约车类应用。 * 主要使用GNSS定位技术提供定位服务。 */ CAR_HAILING, /** * 日常服务使用场景。 * 适用于不需要定位用户精确位置的使用场景,如新闻资讯、网购、点餐类应用。 * 该场景仅使用网络定位技术提供定位服务。 */ DAILY_LIFE_SERVICE, /** * 无功耗场景。 * 该场景不会主动触发定位,会在其他应用定位时,才给当前应用返回位置。 */ NO_POWER}
复制代码


以快速获取位置(FIRST_FIX)策略为例,调用代码如下:


/** * 使用 {CurrentLocationRequest} 实例获取位置信息 * @param priority * @param scenario * @param maxAccuracy * @param timeout * @returns  */static async getCurrentLocationRequest(priority: geoLocationManager.LocationRequestPriority,  scenario: geoLocationManager.LocationRequestScenario,   maxAccuracy: number = 0, timeout: number = 10000): Promise<geoLocationManager.Location | undefined> {  const request: geoLocationManager.CurrentLocationRequest = {    priority: priority,    scenario: scenario,    maxAccuracy: maxAccuracy,    timeoutMs: timeout  };  let location: geoLocationManager.Location | undefined = undefined;  try {    location = await geoLocationManager.getCurrentLocation(request);    console.info(`[AppLogger]单次获取当前位置信息:${JSON.stringify(location)}`);  } catch (error) {    const err = error as BusinessError;    console.error(`[AppLogger]单次获取当前位置信息异常:${JSON.stringify(err)}`);  }  return location;}

Button('使用CurrentLocationRequest实例获取当前位置信息') .onClick(async () => { this.location = await LocationUtil.getCurrentLocationRequest(geoLocationManager.LocationRequestPriority.FIRST_FIX , geoLocationManager.LocationRequestScenario.UNSET); })
复制代码



持续定位

多用于导航、运动轨迹、出行等场景。需要实例化ContinuousLocationRequest对象,用于告知系统该向应用提供何种类型的位置服务,以及位置结果上报的频率。


/** * 持续定位的请求参数 */export interface ContinuousLocationRequest {    /**     * 上报位置信息的时间间隔,单位为秒。     * 默认为1,取值范围为大于等于0。     * 等于0时对位置上报时间间隔无限制。     */    interval: number;    /**     * 定位的场景信息。     */    locationScenario: UserActivityScenario | PowerConsumptionScenario;}
/** * 位置请求中的用户活动场景类型 */export enum UserActivityScenario { /** * 导航场景。 * 适用于在户外获取设备实时位置的场景,如车载、步行导航。 * 主要使用GNSS定位技术提供定位服务。 */ NAVIGATION = 0x401, /** * 运动场景。 * 适用于记录用户位置轨迹的场景,如运动类应用记录轨迹功能。 * 主要使用GNSS定位技术提供定位服务。 */ SPORT = 0x402, /** * 出行场景。 * 适用于用户出行场景,如打车、乘坐公共交通等场景。 * 主要使用GNSS定位技术提供定位服务。 */ TRANSPORT = 0x403, /** * 日常服务使用场景。 * 适用于不需要定位用户精确位置的使用场景,如新闻资讯、网购、点餐类应用。 * 该场景仅使用网络定位技术提供定位服务。 */ DAILY_LIFE_SERVICE = 0x404}
/** * 位置请求中的功耗场景类型 */export enum PowerConsumptionScenario { /** * 高功耗。 * 以GNSS定位技术为主。 */ HIGH_POWER_CONSUMPTION = 0x601, /** * 低功耗。 * 适用于对用户位置精度要求不高的使用场景,如新闻资讯、网购、点餐类应用。 */ LOW_POWER_CONSUMPTION = 0x602, /** * 无功耗。 * 该场景下不会主动触发定位,会在其他应用定位时,才给当前应用返回位置。 */ NO_POWER_CONSUMPTION = 0x603}
复制代码


以地图导航场景为例,调用方式如下:


/** * 持续定位 * @param interval * @param scenario * @returns */static async getContinuousLocationRequest(interval: number = 0,  scenario: geoLocationManager.UserActivityScenario): Promise<geoLocationManager.Location | undefined> {  const request: geoLocationManager.ContinuousLocationRequest = {    interval,    locationScenario: scenario  };  let locationPromise: Promise<geoLocationManager.Location | undefined> = new Promise(resolve => {    let listener: (data: geoLocationManager.Location) => void;    listener = (data: geoLocationManager.Location) => {      console.info(`[AppLogger]持续定位数据:${JSON.stringify(data)}`);      resolve(data);    }    try {      // 开启位置变化订阅      geoLocationManager.on('locationChange', request, listener);    } catch (error) {      const err = error as BusinessError;      console.error(`[AppLogger]持续定位异常:${JSON.stringify(err)}`);    }  });  return locationPromise;}

Button('持续定位') .onClick(async () => { this.location = await LocationUtil.getContinuousLocationRequest(1, geoLocationManager.UserActivityScenario.NAVIGATION); })
复制代码




当然,最后还需要主动结束定位,不然会导致设备功耗高,耗电快,发热等问题。


geoLocationManager.off('locationChange');
复制代码

总结

位置服务(Location Kit)是应用程序常见的能力之一,如天气预报 App 中可以使用位置服务查看所在城市的天气、健康运动类 App 中可以使用位置服务记录运动轨迹等。当开发者在一个你哟功能程序中使用位置服务时,需要按照约束与限制,确保用户敏感数据的安全。

发布于: 4 小时前阅读数: 9
用户头像

白晓明

关注

还未添加个人签名 2021-03-10 加入

还未添加个人简介

评论

发布
暂无评论
探索HarmonyOS位置服务:精准定位的科技奥秘_HarmonyOS NEXT_白晓明_InfoQ写作社区