简介
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+ | 是 | 否 | 表示定位结果的来源。 |
单次获取设备定位信息
有两种方式,分别是获取系统缓存的最新位置和获取当前位置。
获取缓存的位置,可以减少系统功耗。如果对时间精度要求较高,直接获取当前位置较好。
以下是完整的代码
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.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 百万级群聊的设计实践
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)