简介
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<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;
}
}
持续获取设备定位信息
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 ->用户活动场景枚举
- NAVIGATION:导航场景。需要高定位精度和实时性能。
- SPORT:运动场景。要求高定位精度。
- TRANSPORT:运输场景。需要高定位精度和实时性能。
- TRANSPORT:运输场景。需要高定位精度和实时性能。
- DAILY_LIFE_SERVICE:日常生活场景。定位精度要求低。
*/
- 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;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。