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;}
}
代码如下:
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;}
}