鸿蒙NEXT开发定位工具类 (WGS-84坐标系)(ArkTs)

复制代码
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;
  }
}
相关推荐
fei_sun4 小时前
【HarmonyOS】ArKUI框架
华为·harmonyos
264玫瑰资源库5 小时前
嘻游电玩三端客户端部署实战:PC + Android + iOS 环境全覆盖教程
android·ios
鸿蒙布道师5 小时前
鸿蒙NEXT开发权限工具类(申请授权相关)(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
万叶学编程6 小时前
鸿蒙移动应用开发--渲染控制实验
前端·华为·harmonyos
alexhilton7 小时前
深入理解Jetpack Compose中的函数的执行顺序
android·kotlin·android jetpack
李新_7 小时前
Android 画中画避坑指北
android
一一Null8 小时前
Android studio—socketIO库return与emit的使用
android·java·网络·ide·websocket·网络协议·android studio
ansondroider9 小时前
Android RK356X TVSettings USB调试开关
android·adb·usb·otg·rk356x
全栈极简9 小时前
Android串口通信
android