【HarmonyOS Next开发】定位相关知识(Locationkit)
简介
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;
}
}
定位信息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 | 是 | 否 | 附加信息。 | | 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;
}
}
持续获取设备定位信息
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;
}
}
地理编码地址获取
两种方式:通过经纬度坐标获取和通过详细地址描述获取
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;
}
}
- 0回答
- 0粉丝
- 0关注
- 用户信息管理小 Demo 解析与相关知识点介绍
- 探索HarmonyOS位置服务:精准定位的科技奥秘
- 【HarmonyOS Next开发】Navigation使用
- 【HarmonyOS Next开发】:ListItemGroup使用
- 【HarmonyOS Next开发】云开发-用户自动认证
- 【HarmonyOS Next开发】静态服务卡片
- 【HarmonyOS Next开发】Tabs使用封装
- 【HarmonyOS Next开发】用户文件访问
- 【HarmonyOS Next开发】:swiper轮播学习
- 【HarmonyOS Next开发】Calendar Kit日历管理
- 【HarmonyOS Next开发】云开发-云数据库(一)
- 【HarmonyOS Next开发】云开发-云数据库(二)
- 【HarmonyOS Next开发】应用权限原理和封装
- 【HarmonyOS Next开发】日历组件详细日界面组件
- HarmonyOS NEXT应用开发指南:开屏广告的使用