复制代码
import geoLocationManager from '@ohos.geoLocationManager';
import { BusinessError, Callback } from '@ohos.base';
import { LogUtil } from './LogUtil';
import { PermissionUtil } from './PermissionUtil';
import { map, mapCommon } from '@kit.MapKit';
/**
* 定位工具类 (WGS-84坐标系)
* author: CSDN-鸿蒙布道师
* since: 2025/04/22
*/
export class LocationUtil {
/**
* 判断位置服务是否已经使能(定位是否开启)。
* @returns true 表示定位已开启,false 表示未开启。
*/
static isLocationEnabled(): boolean {
return geoLocationManager.isLocationEnabled();
}
/**
* 申请定位权限。
* @returns true 表示授权成功,false 表示用户拒绝授权。
*/
static async requestLocationPermissions(): Promise<boolean> {
const permissions: Array<string> = ['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION'];
let grant: boolean = await PermissionUtil.requestPermissions(permissions);
if (!grant) {
grant = await PermissionUtil.requestPermissionOnSetting(permissions);
}
return grant;
}
/**
* 获取当前位置(简化版)。
* @returns 当前位置信息。如果发生错误,则返回 null。
*/
static async getCurrentLocationEasy(): Promise<geoLocationManager.Location | null> {
return LocationUtil.getCurrentLocation();
}
/**
* 获取当前位置。
* @param request 可选的定位请求参数。
* @returns 当前位置信息。如果发生错误,则返回 null。
*/
static async getCurrentLocation(
request?: geoLocationManager.CurrentLocationRequest | geoLocationManager.SingleLocationRequest
): Promise<geoLocationManager.Location | null> {
try {
return await geoLocationManager.getCurrentLocation(request);
} catch (err) {
LocationUtil.handleError(err, '获取当前位置失败');
return null; // 返回 null 表示发生错误
}
}
/**
* 开启位置变化订阅,并发起定位请求(简化版)。
* @param callBack 回调函数。
* @returns 成功返回 0,失败返回错误码。
*/
static onLocationChangeEasy(callBack: Callback<geoLocationManager.Location>): number {
const defaultRequest: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.FIRST_FIX,
scenario: geoLocationManager.LocationRequestScenario.UNSET,
timeInterval: 10,
distanceInterval: 0,
maxAccuracy: 0,
};
return LocationUtil.onLocationChange(defaultRequest, callBack);
}
/**
* 开启位置变化订阅,并发起定位请求。
* @param request 定位请求参数。
* @param callBack 回调函数。
* @returns 成功返回 0,失败返回错误码。
*/
static onLocationChange(
request: geoLocationManager.LocationRequest | geoLocationManager.ContinuousLocationRequest,
callBack: Callback<geoLocationManager.Location>
): number {
try {
geoLocationManager.on('locationChange', request, callBack);
return 0;
} catch (err) {
return LocationUtil.handleError(err, '开启位置变化订阅失败');
}
}
/**
* 关闭位置变化订阅,并删除对应的定位请求。
* @param callback 不传则取消当前类型的所有订阅。
* @returns 成功返回 0,失败返回错误码。
*/
static offLocationChange(callback?: Callback<geoLocationManager.Location>): number {
try {
if (callback) {
geoLocationManager.off('locationChange', callback);
} else {
geoLocationManager.off('locationChange');
}
return 0;
} catch (err) {
return LocationUtil.handleError(err, '关闭位置变化订阅失败');
}
}
/**
* 判断地理编码与逆地理编码服务是否可用。
* @returns true 表示服务可用,false 表示不可用。
*/
static isGeocoderAvailable(): boolean {
return geoLocationManager.isGeocoderAvailable();
}
/**
* 地理编码:将地理描述转换为具体坐标集合。
* @param locationName 地理位置描述。
* @param maxItems 返回结果的最大数量。
* @returns 编码后的坐标集合。
*/
static async getGeoAddressFromLocationName(
locationName: string,
maxItems: number = 1
): Promise<Array<geoLocationManager.GeoAddress>> {
const geocodeRequest: geoLocationManager.GeoCodeRequest = {
description: locationName,
maxItems,
locale: 'zh',
};
try {
const result = await geoLocationManager.getAddressesFromLocationName(geocodeRequest);
return result || [];
} catch (err) {
LocationUtil.handleError(err, '地理编码失败');
return [];
}
}
/**
* 地理编码:将地理描述转换为具体坐标。
* @param locationName 地理位置描述。
* @returns 编码后的坐标对象。
*/
static async getAddressFromLocationName(locationName: string): Promise<geoLocationManager.GeoAddress> {
const geoAddressList = await LocationUtil.getGeoAddressFromLocationName(locationName, 1);
return geoAddressList.length > 0 ? geoAddressList[0] : {};
}
/**
* 逆地理编码:将坐标转换为地理描述集合。
* @param latitude 纬度。
* @param longitude 经度。
* @param maxItems 返回结果的最大数量。
* @returns 逆编码后的地理描述集合。
*/
static async getGeoAddressFromLocation(
latitude: number,
longitude: number,
maxItems: number = 1
): Promise<Array<geoLocationManager.GeoAddress>> {
const reverseGeocodeRequest: geoLocationManager.ReverseGeoCodeRequest = {
latitude,
longitude,
maxItems,
locale: 'zh',
};
try {
const result = await geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest);
return result || [];
} catch (err) {
LocationUtil.handleError(err, '逆地理编码失败');
return [];
}
}
/**
* 逆地理编码:将坐标转换为地理描述。
* @param latitude 纬度。
* @param longitude 经度。
* @returns 逆编码后的地理描述对象。
*/
static async getAddressFromLocation(latitude: number, longitude: number): Promise<geoLocationManager.GeoAddress> {
const geoAddressList = await LocationUtil.getGeoAddressFromLocation(latitude, longitude, 1);
return geoAddressList.length > 0 ? geoAddressList[0] : {};
}
/**
* 获取当前的国家码。
* @returns 当前国家码。
*/
static async getCountryCode(): Promise<string> {
try {
const result = await geoLocationManager.getCountryCode();
return result?.country || '';
} catch (err) {
LocationUtil.handleError(err, '获取国家码失败');
return '';
}
}
/**
* 根据指定的两个经纬度坐标点,计算两点间的直线距离(单位:米)。
* @param from 起始坐标。
* @param to 目标坐标。
* @returns 两点间的直线距离。
*/
static calculateDistance(from: mapCommon.LatLng, to: mapCommon.LatLng): number {
return map.calculateDistance(from, to);
}
/**
* 根据指定的两个经纬度坐标点,计算两点间的直线距离(单位:米)。
* @param fromLat 起始纬度。
* @param fromLng 起始经度。
* @param toLat 目标纬度。
* @param toLng 目标经度。
* @returns 两点间的直线距离。
*/
static calculateDistanceEasy(fromLat: number, fromLng: number, toLat: number, toLng: number): number {
const fromLatLng: mapCommon.LatLng = { latitude: fromLat, longitude: fromLng };
const toLatLng: mapCommon.LatLng = { latitude: toLat, longitude: toLng };
return map.calculateDistance(fromLatLng, toLatLng);
}
/**
* 错误处理方法。
* @param error 错误对象,必须是 BusinessError 类型。
* @param message 提示信息。
* @returns 返回错误码。如果无法获取错误码,则返回默认值 -1。
*/
private static handleError(error: BusinessError, message: string): number {
let errorCode = -1; // 默认错误码
let errorMessage = '未知错误';
if (error && typeof error.code === 'number') {
errorCode = error.code;
errorMessage = error.message || errorMessage;
}
// 记录错误日志
LogUtil.error(`${message}: code=${errorCode}, message=${errorMessage}`);
return errorCode;
}
/**
* 获取错误消息。
* @param code 错误码。
* @param defaultMsg 默认错误消息。
* @returns 错误消息。
*/
static getErrorMsg(code: number, defaultMsg: string): string {
const errorMessages: Map<number, string> = new Map([
[201, '权限校验失败!'],
[202, '系统API权限校验失败!'],
[401, '参数检查失败!'],
[801, '该设备不支持此API!'],
[3301000, '位置服务不可用!'],
[3301100, '请开启位置功能开关!'],
[3301200, '定位失败,未获取到定位结果!'],
[3301300, '逆地理编码查询失败!'],
[3301400, '地理编码查询失败!'],
[3301500, '区域信息(包含国家码)查询失败!'],
[3301600, '地理围栏操作失败!'],
]);
return errorMessages.get(code) || defaultMsg;
}
}
代码如下:
TypeScript
复制代码
import geoLocationManager from '@ohos.geoLocationManager';
import { BusinessError, Callback } from '@ohos.base';
import { LogUtil } from './LogUtil';
import { PermissionUtil } from './PermissionUtil';
import { map, mapCommon } from '@kit.MapKit';
/**
* 定位工具类 (WGS-84坐标系)
* author: CSDN-鸿蒙布道师
* since: 2025/04/22
*/
export class LocationUtil {
/**
* 判断位置服务是否已经使能(定位是否开启)。
* @returns true 表示定位已开启,false 表示未开启。
*/
static isLocationEnabled(): boolean {
return geoLocationManager.isLocationEnabled();
}
/**
* 申请定位权限。
* @returns true 表示授权成功,false 表示用户拒绝授权。
*/
static async requestLocationPermissions(): Promise<boolean> {
const permissions: Array<string> = ['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION'];
let grant: boolean = await PermissionUtil.requestPermissions(permissions);
if (!grant) {
grant = await PermissionUtil.requestPermissionOnSetting(permissions);
}
return grant;
}
/**
* 获取当前位置(简化版)。
* @returns 当前位置信息。如果发生错误,则返回 null。
*/
static async getCurrentLocationEasy(): Promise<geoLocationManager.Location | null> {
return LocationUtil.getCurrentLocation();
}
/**
* 获取当前位置。
* @param request 可选的定位请求参数。
* @returns 当前位置信息。如果发生错误,则返回 null。
*/
static async getCurrentLocation(
request?: geoLocationManager.CurrentLocationRequest | geoLocationManager.SingleLocationRequest
): Promise<geoLocationManager.Location | null> {
try {
return await geoLocationManager.getCurrentLocation(request);
} catch (err) {
LocationUtil.handleError(err, '获取当前位置失败');
return null; // 返回 null 表示发生错误
}
}
/**
* 开启位置变化订阅,并发起定位请求(简化版)。
* @param callBack 回调函数。
* @returns 成功返回 0,失败返回错误码。
*/
static onLocationChangeEasy(callBack: Callback<geoLocationManager.Location>): number {
const defaultRequest: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.FIRST_FIX,
scenario: geoLocationManager.LocationRequestScenario.UNSET,
timeInterval: 10,
distanceInterval: 0,
maxAccuracy: 0,
};
return LocationUtil.onLocationChange(defaultRequest, callBack);
}
/**
* 开启位置变化订阅,并发起定位请求。
* @param request 定位请求参数。
* @param callBack 回调函数。
* @returns 成功返回 0,失败返回错误码。
*/
static onLocationChange(
request: geoLocationManager.LocationRequest | geoLocationManager.ContinuousLocationRequest,
callBack: Callback<geoLocationManager.Location>
): number {
try {
geoLocationManager.on('locationChange', request, callBack);
return 0;
} catch (err) {
return LocationUtil.handleError(err, '开启位置变化订阅失败');
}
}
/**
* 关闭位置变化订阅,并删除对应的定位请求。
* @param callback 不传则取消当前类型的所有订阅。
* @returns 成功返回 0,失败返回错误码。
*/
static offLocationChange(callback?: Callback<geoLocationManager.Location>): number {
try {
if (callback) {
geoLocationManager.off('locationChange', callback);
} else {
geoLocationManager.off('locationChange');
}
return 0;
} catch (err) {
return LocationUtil.handleError(err, '关闭位置变化订阅失败');
}
}
/**
* 判断地理编码与逆地理编码服务是否可用。
* @returns true 表示服务可用,false 表示不可用。
*/
static isGeocoderAvailable(): boolean {
return geoLocationManager.isGeocoderAvailable();
}
/**
* 地理编码:将地理描述转换为具体坐标集合。
* @param locationName 地理位置描述。
* @param maxItems 返回结果的最大数量。
* @returns 编码后的坐标集合。
*/
static async getGeoAddressFromLocationName(
locationName: string,
maxItems: number = 1
): Promise<Array<geoLocationManager.GeoAddress>> {
const geocodeRequest: geoLocationManager.GeoCodeRequest = {
description: locationName,
maxItems,
locale: 'zh',
};
try {
const result = await geoLocationManager.getAddressesFromLocationName(geocodeRequest);
return result || [];
} catch (err) {
LocationUtil.handleError(err, '地理编码失败');
return [];
}
}
/**
* 地理编码:将地理描述转换为具体坐标。
* @param locationName 地理位置描述。
* @returns 编码后的坐标对象。
*/
static async getAddressFromLocationName(locationName: string): Promise<geoLocationManager.GeoAddress> {
const geoAddressList = await LocationUtil.getGeoAddressFromLocationName(locationName, 1);
return geoAddressList.length > 0 ? geoAddressList[0] : {};
}
/**
* 逆地理编码:将坐标转换为地理描述集合。
* @param latitude 纬度。
* @param longitude 经度。
* @param maxItems 返回结果的最大数量。
* @returns 逆编码后的地理描述集合。
*/
static async getGeoAddressFromLocation(
latitude: number,
longitude: number,
maxItems: number = 1
): Promise<Array<geoLocationManager.GeoAddress>> {
const reverseGeocodeRequest: geoLocationManager.ReverseGeoCodeRequest = {
latitude,
longitude,
maxItems,
locale: 'zh',
};
try {
const result = await geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest);
return result || [];
} catch (err) {
LocationUtil.handleError(err, '逆地理编码失败');
return [];
}
}
/**
* 逆地理编码:将坐标转换为地理描述。
* @param latitude 纬度。
* @param longitude 经度。
* @returns 逆编码后的地理描述对象。
*/
static async getAddressFromLocation(latitude: number, longitude: number): Promise<geoLocationManager.GeoAddress> {
const geoAddressList = await LocationUtil.getGeoAddressFromLocation(latitude, longitude, 1);
return geoAddressList.length > 0 ? geoAddressList[0] : {};
}
/**
* 获取当前的国家码。
* @returns 当前国家码。
*/
static async getCountryCode(): Promise<string> {
try {
const result = await geoLocationManager.getCountryCode();
return result?.country || '';
} catch (err) {
LocationUtil.handleError(err, '获取国家码失败');
return '';
}
}
/**
* 根据指定的两个经纬度坐标点,计算两点间的直线距离(单位:米)。
* @param from 起始坐标。
* @param to 目标坐标。
* @returns 两点间的直线距离。
*/
static calculateDistance(from: mapCommon.LatLng, to: mapCommon.LatLng): number {
return map.calculateDistance(from, to);
}
/**
* 根据指定的两个经纬度坐标点,计算两点间的直线距离(单位:米)。
* @param fromLat 起始纬度。
* @param fromLng 起始经度。
* @param toLat 目标纬度。
* @param toLng 目标经度。
* @returns 两点间的直线距离。
*/
static calculateDistanceEasy(fromLat: number, fromLng: number, toLat: number, toLng: number): number {
const fromLatLng: mapCommon.LatLng = { latitude: fromLat, longitude: fromLng };
const toLatLng: mapCommon.LatLng = { latitude: toLat, longitude: toLng };
return map.calculateDistance(fromLatLng, toLatLng);
}
/**
* 错误处理方法。
* @param error 错误对象,必须是 BusinessError 类型。
* @param message 提示信息。
* @returns 返回错误码。如果无法获取错误码,则返回默认值 -1。
*/
private static handleError(error: BusinessError, message: string): number {
let errorCode = -1; // 默认错误码
let errorMessage = '未知错误';
if (error && typeof error.code === 'number') {
errorCode = error.code;
errorMessage = error.message || errorMessage;
}
// 记录错误日志
LogUtil.error(`${message}: code=${errorCode}, message=${errorMessage}`);
return errorCode;
}
/**
* 获取错误消息。
* @param code 错误码。
* @param defaultMsg 默认错误消息。
* @returns 错误消息。
*/
static getErrorMsg(code: number, defaultMsg: string): string {
const errorMessages: Map<number, string> = new Map([
[201, '权限校验失败!'],
[202, '系统API权限校验失败!'],
[401, '参数检查失败!'],
[801, '该设备不支持此API!'],
[3301000, '位置服务不可用!'],
[3301100, '请开启位置功能开关!'],
[3301200, '定位失败,未获取到定位结果!'],
[3301300, '逆地理编码查询失败!'],
[3301400, '地理编码查询失败!'],
[3301500, '区域信息(包含国家码)查询失败!'],
[3301600, '地理围栏操作失败!'],
]);
return errorMessages.get(code) || defaultMsg;
}
}