< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5


 简介

LocationKit提供了定位服务、地理围栏、地理编码、逆地理编码和国家码等功能。

可以实现点击获取用户位置信息、持续获取位置信息和区域进出监控等多项功能。

需要注意,需要确定用户已经开启定位信息,一下的代码没有做这一步的操作,默认开启了。

权限

申请位置权限的方式

位置的精确度

只申请ohos.permission.APPROXIMATELY_LOCATION

获取到模糊位置,精确度为5公里。

同时申请

ohos.permission.APPROXIMATELY_LOCATION 和ohos.permission.LOCATION

获取到精准位置,精准度在米级别。

如果应用需要在后台运行时访问设备位置,还需要申请ohos.permission.LOCATION_IN_BACKGROUND权限。

这里强烈推荐大家去使用 旺旺崔冰冰 大佬的工具库( ef-tool)以下的权限获取代码来自大佬的工具库权限相关的代码

import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
import { bundleManager, common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

export class AuthUtil {
  /**
   * 判断是否授权
   * @param permissions  待判断的权限
   * @returns 已授权true,未授权false
   */
  static async checkPermissions(permissions: Permissions): Promise<boolean> {
    //判断是否授权
    let grantStatus: abilityAccessCtrl.GrantStatus = await AuthUtil.checkAccessToken(permissions);
    if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
      //已经授权
      return true;
    } else {
      //未授权
      return false;
    }
  }

  /**
   * 发起授权
   * @param permissions  需要授权的权限
   * @param callBack  授权成功后的回调,1为用户同意授权,-1为用户拒绝授权
   * @returns
   */
  static async reqPermissionsFromUser(permissions: Permissions, callBack: (index: number) => void): Promise<void> {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
    let request = await atManager.requestPermissionsFromUser(getContext() as common.UIAbilityContext, [permissions]);
    let grantStatus: Array<number> = request.authResults;
    let length: number = grantStatus.length;
    for (let i = 0; i < length; i++) {
      if (grantStatus[i] === 0) {
        // 用户授权,可以继续访问目标操作
        callBack(1);
      } else {
        callBack(-1);
        // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
        return;
      }
    }
  }

  /**
   * 发起授权 以Promise方式返回
   * @param permissions 需要授权的权限
   * @returns 1表示授权成功继续业务操作,-1表示用户拒绝授权
   */
  static async reqPermissions(permissions: Permissions): Promise<number> {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
    let request = await atManager.requestPermissionsFromUser(getContext() as common.UIAbilityContext, [permissions]);
    let grantStatus: Array<number> = request.authResults;
    let length: number = grantStatus.length;
    for (let i = 0; i < length; i++) {
      if (grantStatus[i] === 0) {
        // 用户授权,可以继续访问目标操作
        return 1;
      } else {
        // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
        return -1;
      }
    }
    return -1;
  }

  /**
   * 检查是否授权
   * @param permission 待检查权限
   * @returns 授权状态
   */
  private static async checkAccessToken(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.log('获取应用绑定包信息失败:原因为:' + err.message)
    }
    // 校验应用是否被授予权限
    try {
      grantStatus = await atManager.checkAccessToken(tokenId, permission);
    } catch (error) {
      const err: BusinessError = error as BusinessError;
      console.log('校验授权信息失败:原因为:' + err.message)
    }

    return grantStatus;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.

定位信息Location参数

名称

类型

可读

可写

说明

latitude

number



表示纬度信息,正值表示北纬,负值表示南纬。取值范围为-90到90。仅支持WGS84坐标系。

longitude

number



表示经度信息,正值表示东经,负值表是西经。取值范围为-180到180。仅支持WGS84坐标系。

altitude

number



表示高度信息,单位米。

accuracy

number



表示精度信息,单位米。

speed

number



表示速度信息,单位米每秒。

timeStamp

number



表示位置时间戳,UTC格式。

direction

number



表示航向信息。单位是“度”,取值范围为0到360。

timeSinceBoot

number



表示位置时间戳,开机时间格式。

additions

Array<string>



附加信息。

additionSize

number



附加信息数量。取值范围为大于等于0。

additionsMap12+

Map<string, string>



附加信息。具体内容和顺序与additions一致。该字段暂未实现。

altitudeAccuracy12+

number



表示高度信息的精度,单位米。

speedAccuracy12+

number



表示速度信息的精度,单位米每秒。

directionAccuracy12+

number



表示航向信息的精度。单位是“度”,取值范围为0到360。

uncertaintyOfTimeSinceBoot12+

number



表示位置时间戳的不确定度。

sourceType12+

 LocationSourceType



表示定位结果的来源。

单次获取设备定位信息

有两种方式,分别是获取系统缓存的最新位置和获取当前位置。

获取缓存的位置,可以减少系统功耗。如果对时间精度要求较高,直接获取当前位置较好。

以下是完整的代码

import { geoLocationManager } from '@kit.LocationKit';
import { BusinessError } from '@kit.BasicServicesKit'
import json from '@ohos.util.json';
import { AuthUtil } from '../Util/AuthUtil';
import { Permissions } from '@kit.AbilityKit';

@Entry
@Component
struct Index {
  locationPermissions: Permissions = 'ohos.permission.LOCATION'
  locationMatelyPermissions: Permissions = 'ohos.permission.APPROXIMATELY_LOCATION'

  async aboutToAppear(): Promise<void> {
    let permissionResult = await this.CheckPermission();
    if (!permissionResult) {
      //这里需要指引用户二次开启
      return;
    }
  }

  /**
   * 查看缓存中的位置
   */
  GetLastLocation() {
    //查看系统缓存的最新位置
    let location = geoLocationManager.getLastLocation();
    console.log(json.stringify(location))
  }

  /**
   * 查看当前最新位置
   *
   *locatingPriority 有两个相关标签
   *  1.geoLocationManager.LocatingPriority.PRIORITY_LOCATING_SPEED ->如果对定位速度要求较高建议使用这个
   *  2.geoLocationManager.LocatingPriority.PRIORITY_ACCURACY ->如果对位置的返回精度要求较高使用这个
   * locatingTimeoutMs 单次定位时间,建议10S
   */
  GetSingleLocation() {
    let request: geoLocationManager.SingleLocationRequest = {
      'locatingPriority': geoLocationManager.LocatingPriority.PRIORITY_LOCATING_SPEED,
      'locatingTimeoutMs': 10000
    }
    try {
      geoLocationManager.getCurrentLocation(request).then(
        (result) => { // 调用getCurrentLocation获取当前设备位置,通过promise接收上报的位置
          console.log('current location: ' + JSON.stringify(result));
        })
        .catch((error: BusinessError) => { // 接收上报的错误码
          console.error('promise, getCurrentLocation: error=' + JSON.stringify(error));
        });
    } catch (err) {
      console.error("errCode:" + JSON.stringify(err));
    }
  }

  
  build() {
    Column() {
      Button("查看系统中缓存的最新位置")
        .width(220)
        .height(50)
        .margin({ bottom: 40 })
        .onClick(() => this.GetLastLocation())
      Button("查看最新位置").width(220).height(50)
        .margin({ bottom: 40 })
        .onClick(() => {
          this.GetSingleLocation()
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }

  /**
   * 检查定位权限是否添加
   * @returns true为已经添加,false为未添加
   */
  private async CheckPermission(): Promise<boolean> {
    let result: boolean = true;
    let locationPermissionCheck = await AuthUtil.checkPermissions(this.locationPermissions)
    if (!locationPermissionCheck) {
      AuthUtil.reqPermissionsFromUser(this.locationPermissions, (index: number) => {
        if (index === -1) {
          result = false;
        }
      })
    }
    if (!result) {
      return result;
    }
    let locationMatelyPermissionCheck = await AuthUtil.checkPermissions(this.locationMatelyPermissions)
    if (!locationMatelyPermissionCheck) {
      AuthUtil.reqPermissionsFromUser(this.locationMatelyPermissions, (index: number) => {
        if (index === -1) {
          result = false;
        }
      })
    }
    return result;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.

持续获取设备定位信息

import { geoLocationManager } from '@kit.LocationKit';
import { BusinessError } from '@kit.BasicServicesKit'
import json from '@ohos.util.json';
import { AuthUtil } from '../Util/AuthUtil';
import { Permissions } from '@kit.AbilityKit';

@Entry
@Component
struct Index {
  locationPermissions: Permissions = 'ohos.permission.LOCATION'
  locationMatelyPermissions: Permissions = 'ohos.permission.APPROXIMATELY_LOCATION'

  async aboutToAppear(): Promise<void> {
    let permissionResult = await this.CheckPermission();
    if (!permissionResult) {
      //这里需要指引用户二次开启
      return;
    }
  }

  /**
   * 持续定位(ContinuousLocationRequest对象)
   *
   * interval-> 上报位置信息的时间间隔,单位是秒
   *
   * locationScenario ->用户活动场景枚举
   * 1. NAVIGATION:导航场景。需要高定位精度和实时性能。
   * 2. SPORT:运动场景。要求高定位精度。
   * 3. TRANSPORT:运输场景。需要高定位精度和实时性能。
   * 4. TRANSPORT:运输场景。需要高定位精度和实时性能。
   * 5. DAILY_LIFE_SERVICE:日常生活场景。定位精度要求低。
   */
  OpenContinuosLocation() {
    let request: geoLocationManager.ContinuousLocationRequest = {
      'interval': 1,
      'locationScenario': geoLocationManager.UserActivityScenario.NAVIGATION
    }
    let locationCallback = (location: geoLocationManager.Location): void => {
      console.log('定位信息: ' + JSON.stringify(location));
    };
    try {
      geoLocationManager.on('locationChange', request, locationCallback);
    } catch (err) {
      console.error("errCode:" + JSON.stringify(err));
    }
  }

  /**
   * 关闭持续定位
   */
  ClosedContinuosLocation() {
    geoLocationManager.off('locationChange', (loca: geoLocationManager.Location) => {
      console.log("持续定位关闭");
      console.log("最后一次定位" + json.stringify(loca));
    })
  }

  build() {
    Column() {
      Button("开启持续定位").width(220).height(50)
        .margin({ bottom: 40 })
        .onClick(() => {
          this.OpenContinuosLocation()
        })
      Button("关闭持续定位").width(220).height(50)
        .margin({ bottom: 40 })
        .onClick(() => {
          this.ClosedContinuosLocation()
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }

  /**
   * 检查定位权限是否添加
   * @returns true为已经添加,false为未添加
   */
  private async CheckPermission(): Promise<boolean> {
    let result: boolean = true;
    let locationPermissionCheck = await AuthUtil.checkPermissions(this.locationPermissions)
    if (!locationPermissionCheck) {
      AuthUtil.reqPermissionsFromUser(this.locationPermissions, (index: number) => {
        if (index === -1) {
          result = false;
        }
      })
    }
    if (!result) {
      return result;
    }
    let locationMatelyPermissionCheck = await AuthUtil.checkPermissions(this.locationMatelyPermissions)
    if (!locationMatelyPermissionCheck) {
      AuthUtil.reqPermissionsFromUser(this.locationMatelyPermissions, (index: number) => {
        if (index === -1) {
          result = false;
        }
      })
    }
    return result;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.

地理编码地址获取

两种方式:通过经纬度坐标获取和通过详细地址描述获取

import { geoLocationManager } from '@kit.LocationKit';
import { Permissions } from '@kit.AbilityKit';
import { AuthUtil } from '../Util/AuthUtil';

@Entry
@Component
struct Loaction_Page2 {
  locationPermissions: Permissions = 'ohos.permission.LOCATION'
  locationMatelyPermissions: Permissions = 'ohos.permission.APPROXIMATELY_LOCATION'

  async aboutToAppear(): Promise<void> {
    let permissionResult = await this.CheckPermission();
    if (!permissionResult) {
      //这里需要指引用户二次开启
      return;
    }
    this.CheckGeoService()
  }

  LocationToAddress() {
    this.CheckGeoService()
    let reverseGeocodeRequest: geoLocationManager.ReverseGeoCodeRequest =
      {
        "locale": "zh",
        "country": "CN",
        "latitude": 40.02099028,
        "longitude": 115.96965089,
        "maxItems": 1
      };
    try {
      geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest, (err, data) => {
        if (err) {
          console.log('getAddressesFromLocation err: ' + JSON.stringify(err));
        } else {
          console.log('getAddressesFromLocation data: ' + JSON.stringify(data));
        }
      });
    } catch (err) {
      console.error("errCode:" + JSON.stringify(err));
    }

  }

  LocationNameToAddress() {
    let geocodeRequest: geoLocationManager.GeoCodeRequest = {
      "description": "广东省广州市海珠区阅江西路222号(广州塔站B出口170米左右)",
      "maxItems": 1
    };
    try {
      geoLocationManager.getAddressesFromLocationName(geocodeRequest, (err, data) => {
        if (err) {
          console.log('getAddressesFromLocationName err: ' + JSON.stringify(err));
        } else {
          console.log('getAddressesFromLocationName data: ' + JSON.stringify(data));
        }
      });
    } catch (err) {
      console.error("errCode:" + JSON.stringify(err));
    }
  }

  build() {
    Column() {
      Button("具体地址得到地理编码").width(220).height(50)
        .margin({ bottom: 40 })
        .onClick(() => {
          this.LocationNameToAddress();
        })
      Button("具体坐标得到地理编码").width(220).height(50)
        .margin({ bottom: 40 })
        .onClick(() => {
          this.LocationToAddress();
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }

  /**
   * 查询地理编码和逆地理编码是否可用
   */
  private CheckGeoService(): boolean {
    try {
      let isAvailable = geoLocationManager.isGeocoderAvailable();
      if (isAvailable) {
        console.log("地理编码和逆地理编码可用")
        return true;
      } else {
        console.log("地理编码和逆地理编码不可用")
        return false;
      }
    } catch (err) {
      console.error("errCode:" + JSON.stringify(err));
      return false;
    }
  }

  /**
   * 检查定位权限是否添加
   * @returns true为已经添加,false为未添加
   */
  private async CheckPermission(): Promise<boolean> {
    let result: boolean = true;
    let locationPermissionCheck = await AuthUtil.checkPermissions(this.locationPermissions)
    if (!locationPermissionCheck) {
      AuthUtil.reqPermissionsFromUser(this.locationPermissions, (index: number) => {
        if (index === -1) {
          result = false;
        }
      })
    }
    if (!result) {
      return result;
    }
    let locationMatelyPermissionCheck = await AuthUtil.checkPermissions(this.locationMatelyPermissions)
    if (!locationMatelyPermissionCheck) {
      AuthUtil.reqPermissionsFromUser(this.locationMatelyPermissions, (index: number) => {
        if (index === -1) {
          result = false;
        }
      })
    }
    return result;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.


posted on   钟子翔  阅读(60)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 百万级群聊的设计实践
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
点击右上角即可分享
微信分享提示