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类型的长时任务

三、导入模块

import { geoLocationManager } from '@kit.LocationKit';

四、示例

效果图

在这里插入图片描述

示例代码

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个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值