HarmonyOS:使用geoLocationManager (位置服务)获取位置信息

一、简介

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

使用位置服务时请打开设备"位置"开关。如果"位置"开关关闭并且代码未设置捕获异常,可能导致应用异常。

二、申请位置权限

2.1 场景概述

应用在使用Location Kit系统能力前,需要检查是否已经获取用户授权访问设备位置信息。如未获得授权,可以向用户申请需要的位置权限。
系统提供的定位权限有:

  • ohos.permission.LOCATION:用于获取精准位置,精准度在米级别。
  • ohos.permission.APPROXIMATELY_LOCATION:用于获取模糊位置,精确度为5公里。
  • ohos.permission.LOCATION_IN_BACKGROUND:用于应用切换到后台仍然需要获取定位信息的场景。
2.2 开发步骤
  1. 开发者可以在应用配置文件中声明所需要的权限并向用户申请授权,具体可参考向用户申请授权
  2. 当APP运行在前台,且访问设备位置信息时,申请位置权限的方式如下:
申请位置权限的方式 是否允许申请 申请成功后获取的位置的精确度
申请ohos.permission.APPROXIMATELY_LOCATION 获取到模糊位置,精确度为5公里。
同时申请ohos.permission.APPROXIMATELY_LOCATION和ohos.permission.LOCATION 获取到精准位置,精准度在米级别。

当APP运行在后台时,申请位置权限的方式如下:

如果应用在后台运行时也需要访问设备位置,除了按照步骤2申请权限外,还需要申请LOCATION类型的长时任务

三、导入模块

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

四、示例

效果图

示例代码

c 复制代码
import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { geoLocationManager } from '@kit.LocationKit';
import { intl } from '@kit.LocalizationKit';

async function checkPermissionGrant(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;

  // 获取应用程序的accessTokenID
  let tokenId: number = 0;
  try {
    let bundleInfo: bundleManager.BundleInfo =
      await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
    let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
    tokenId = appInfo.accessTokenId;
  } catch (error) {
    const err: BusinessError = error as BusinessError;
    console.error(`获取应用程序的accessTokenID Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`);
  }

  // 校验应用是否被授予权限
  try {
    grantStatus = await atManager.checkAccessToken(tokenId, permission);
  } catch (error) {
    const err: BusinessError = error as BusinessError;
    console.error(`校验应用是否被授予权限 Failed to check access token. Code is ${err.code}, message is ${err.message}`);
  }

  return grantStatus;
}

async function checkPermissions(context: common.UIAbilityContext): Promise<void> {
  let grantStatus1: boolean = await checkPermissionGrant('ohos.permission.LOCATION') ===
  abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED; // 获取精确定位权限状态
  let grantStatus2: boolean = await checkPermissionGrant('ohos.permission.APPROXIMATELY_LOCATION') ===
  abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED; // 获取模糊定位权限状态
  // 精确定位权限只能跟模糊定位权限一起申请,或者已经有模糊定位权限才能申请精确定位权限
  if (grantStatus2 && !grantStatus1) {
    // 申请精确定位权限
    reqPermissionsFromUser(permissionsOne, context)
  } else if (!grantStatus1 && !grantStatus2) {
    // 申请模糊定位权限与精确定位权限或单独申请模糊定位权限
    reqPermissionsFromUser(permissionsTow, context)
  } else {
    // 已经授权,可以继续访问目标操作
    getCurrentLocation()
  }
}


const permissionsOne: Array<Permissions> = ['ohos.permission.LOCATION'];

const permissionsTow: Array<Permissions> = ['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION'];

// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContext
function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
  let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
  // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
  atManager.requestPermissionsFromUser(context, permissions).then((data) => {
    let grantStatus: Array<number> = data.authResults;
    let length: number = grantStatus.length;
    for (let i = 0; i < length; i++) {
      if (grantStatus[i] === 0) {
        // 用户授权,可以继续访问目标操作
      } else {
        // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
        return;
      }
    }
    // 授权成功
    getCurrentLocation()
  }).catch((err: BusinessError) => {
    console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
  })
}


function getCurrentLocation() {
  // 实例化位置信息请求对象,确认当前定位策略。以实例化SingleLocationRequest对象为例,将其定位方式优先级设置为快速获取位置优先,定位超时时间设置为10秒
  let request: geoLocationManager.SingleLocationRequest = {
    locatingPriority: geoLocationManager.LocatingPriority.PRIORITY_LOCATING_SPEED,
    locatingTimeoutMs: 10000
  };

  // 根据定位策略,调用getCurrentLocation()接口获取当前位置信息
  geoLocationManager.getCurrentLocation(request).then((location: geoLocationManager.Location) => {
    // Receive the reported location through the promise.
    const latitude = location.latitude;// 纬度
    const longitude = location.longitude;// 经度
    const speed = location.speed;
    const accuracy = location.accuracy;// 精度
    const sourceType = location.sourceType;// 定位来源
    const direction = location.direction;// 表示航向信息。单位是"度",取值范围为0到360。
    const timeStamp = location.timeStamp;
    let dateFormat8 = new intl.DateTimeFormat('zh-CN', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit'
    })
    let formattedTimeDate = dateFormat8.format(new Date(timeStamp))
    formattedTimeDate = formattedTimeDate.replaceAll('/', ".");// 2025.04.03 18:16:08

    console.log(`formattedTimeDate = ${formattedTimeDate} 获取当前位置信息 latitude = ${latitude} , longitude = ${longitude}, speed = ${speed}, accuracy = ${accuracy} , sourceType = ${sourceType} , direction = ${direction}`);
 
  }).catch((err: BusinessError) => {
    console.log(`获取当前位置信息 getCurrentLocationPosition failed, code: ${err.code}, message: ${err.message}`)
  });

  // 调用getAddressesFromLocation()接口进行逆地理编码转化,将位置坐标信息转换为对应的地理位置描述。
  // geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest, async (err, data) => {
  //   if (data) {
  //     this.address = data[0]?.placeName || '';
  //     // ...
  //   } else {
  //     console.log(`将位置坐标信息转换为对应的地理位置描述 getAddressesFromLocation failed, code: ${err.code}, message: ${err.message}`)
  //   }
  // });
}

@Entry
@Component
struct TestLocation {
  @State message: string = '当前位置信息';
  private context = getContext(this) as common.UIAbilityContext;

  build() {
    Column({ space: 10 }) {
      Text(this.message)
        .id('TestLocationMapHelloWorld')
        .fontSize(20)
        .fontWeight(FontWeight.Medium)

      Button("获取位置信息")
        .fontColor(Color.Black)
        .fontSize(20).onClick(() => {
        checkPermissions(this.context)
      })
    }
    .height('100%')
    .width('100%')
    .margin({ top: 50 })
  }
}
相关推荐
别说我什么都不会10 小时前
【仓颉三方库】 网络组件——httpclient4cj
harmonyos
SuperHeroWu710 小时前
【HarmonyOS 5】鸿蒙实现手写板
华为·harmonyos·鸿蒙·画布·手写板·pan
ChinaDragonDreamer11 小时前
HarmonyOS:使用Refresh组件实现页面下拉刷新上拉加载更多
harmonyos·鸿蒙
谢道韫66613 小时前
鸿蒙公共通用组件封装实战指南:从基础到进阶
华为·harmonyos
别说我什么都不会14 小时前
【仓颉三方库】 网络组件——hyperion
harmonyos
Georgewu14 小时前
【HarmonyOS 5】如何开启DevEco Studio热更新调试应用模式
harmonyos
lucky_hamster14 小时前
[Openharmony] openharmony设备上 进入ubuntu-rootfs根文件系统并运行python程序
harmonyos
程序猿阿伟14 小时前
《鸿蒙软总线:基于UDP的数据传输奥秘与优势》
单片机·udp·harmonyos
江拥羡橙15 小时前
2025年,HarmonyOS认证学习及考试
学习·华为·harmonyos·鸿蒙·华为证书·harmonyos认证·华为证书考试
Georgewu18 小时前
【HarmonyOS 5】AttributeModifier和AttributeUpdater详解
harmonyos