前言

本文所涉及的是基于 HarmonyOS 语言的 ArkTS,可应用于鸿蒙系统的出行类应用中的出行导航场景。

鸿蒙定位功能

在开发APP时,定位服务是许多场景的核心,比如地图、逆地理编码、持续定位和后台定位等常见功能。本文章基于HarmonyOS NEXT操作系统,API12以上的版本,深入剖析定位相关的知识点,结合实际代码示例讲解核心 API,梳理使用步骤,并总结实现要点。无论你是新手还是有经验的开发者,都能够帮你快速上手 HarmonyOS NEXT系统的定位功能。

接下来我们主要从HarmonyOS 的 @kit.LocationKit@kit.MapKit@kit.BackgroundTasksKit 等模块去进行剖析,并逐一讲解相关 API,并搭配代码示例。

核心API解析

以下是代码中使用的核心定位 API,我们将结合实际用法展示如何在 HarmonyOS 中实现定位功能。

1. geoLocationManager.getLastLocation()

  • 功能:获取系统缓存的最后已知位置,无需发起新定位请求,速度快。

  • 返回值geoLocationManager.Location 对象,包含 latitudelongitude 等字段。

  • 使用场景:适合快速显示用户大致位置,比如应用启动时的默认位置。

  • 代码示例

    try {
      let location = geoLocationManager.getLastLocation();
      console.log(`缓存位置: 纬度 ${location.latitude}, 经度 ${location.longitude}`);
      // 处理位置数据,例如显示在地图上
    } catch (err) {
      hilog.error(0x0000, 'Location', `获取缓存位置失败: ${err.message}`);
      promptAction.showToast({ message: '无法获取位置,请检查定位服务', duration: 2000 });
    }
    
  • 注意:若定位服务关闭或无缓存数据,会抛出错误,需妥善处理。

2. geoLocationManager.getCurrentLocation(request: SingleLocationRequest)

  • 功能:获取实时位置,可配置定位优先级和超时时间。

  • 参数

    • locatingPriority:如 PRIORITY_LOCATING_SPEED(优先速度)或 PRIORITY_ACCURACY(优先精度)。
    • locatingTimeoutMs:定位超时时间(毫秒)。
  • 返回值Promise<geoLocationManager.Location>

  • 使用场景:需要高精度位置时,比如用户点击“定位当前位置”。

  • 代码示例

    let request: geoLocationManager.SingleLocationRequest = {
      locatingPriority: CommonConstants.PRIORITY_LOCATING_SPEED,
      locatingTimeoutMs: 10000
    };
    geoLocationManager.getCurrentLocation(request)
      .then((location) => {
        console.log(`当前位置: 纬度 ${location.latitude}, 经度 ${location.longitude}`);
        // 更新地图或 UI
      })
      .catch((err: BusinessError) => {
        hilog.error(0x0000, 'Location', `定位失败: ${err.message}`);
        promptAction.showToast({ message: '定位失败,请检查网络或定位设置', duration: 2000 });
      });
    
  • 注意:需确保定位权限已授予,且设备定位功能开启。

3. geoLocationManager.on('locationChange', request: ContinuousLocationRequest, callback)

  • 功能:注册回调以接收持续的位置更新。

  • 参数

    • request:配置更新间隔(interval)和场景(locationScenario,如 NAVIGATION)。
    • callback:每次位置更新时调用,传入 geoLocationManager.Location
  • 使用场景:导航或实时跟踪场景。

  • 代码示例

    let request: geoLocationManager.ContinuousLocationRequest = {
      interval: 1, // 每秒更新
      locationScenario: CommonConstants.NAVIGATION
    };
    const locationChange = (location: geoLocationManager.Location) => {
      console.log(`位置更新: 纬度 ${location.latitude}, 经度 ${location.longitude}`);
      // 更新地图标记或 UI
    };
    try {
      geoLocationManager.on('locationChange', request, locationChange);
      console.log('开始持续定位');
    } catch (err) {
      hilog.error(0x0000, 'Location', `持续定位失败: ${err.message}`);
    }
    
  • 注意:需在适当时候调用 off 方法停止监听,以节省资源。

4. geoLocationManager.off('locationChange', callback)

  • 功能:取消持续定位监听。

  • 参数:要移除的回调函数。

  • 使用场景:当不再需要位置更新时,如页面退出或用户关闭功能。

  • 代码示例

    try {
      geoLocationManager.off('locationChange', locationChange);
      console.log('停止持续定位');
    } catch (err) {
      hilog.error(0x0000, 'Location', `停止定位失败: ${err.message}`);
    }
    
  • 注意:确保传入正确的回调函数引用。

5. geoLocationManager.getAddressesFromLocation(request: ReverseGeoCodeRequest, callback)

  • 功能:将经纬度逆地理编码为地址。

  • 参数

    • request:包含坐标(latitude, longitude)、语言(locale)和最大结果数(maxItems)。
    • callback:返回地址数组或错误。
  • 使用场景:显示位置的文字描述,如“北京市朝阳区”。

  • 代码示例

    let request: geoLocationManager.ReverseGeoCodeRequest = {
      latitude: 22.878538,
      longitude: 113.886642,
      locale: 'zh_CN',
      maxItems: 1
    };
    geoLocationManager.getAddressesFromLocation(request, (err, data) => {
      if (data && data.length > 0) {
        console.log(`地址: ${data[0].placeName}`);
        // 更新 UI 显示地址
      } else {
        hilog.error(0x0000, 'Location', `逆地理编码失败: ${err?.message}`);
        promptAction.showToast({ message: '无法获取地址,请检查网络', duration: 2000 });
      }
    });
    
  • 注意:需要网络连接,且坐标必须有效。

6. map.convertCoordinate(fromType, toType, coordinate)

  • 功能:转换坐标系(如 WGS84 到 GCJ02),以适配地图要求。

  • 返回值Promise<mapCommon.LatLng>

  • 使用场景:在中国地区,地图通常要求 GCJ02 坐标系。

  • 代码示例

    let coord = { latitude: 22.878538, longitude: 113.886642 };
    map.convertCoordinate(mapCommon.CoordinateType.WGS84, mapCommon.CoordinateType.GCJ02, coord)
      .then((mapLocation) => {
        console.log(`转换后坐标: 纬度 ${mapLocation.latitude}, 经度 ${mapLocation.longitude}`);
        // 在地图上使用转换后的坐标
      })
      .catch((err) => {
        hilog.error(0x0000, 'Map', `坐标转换失败: ${err.message}`);
      });
    
  • 注意:确保输入坐标有效。

7. mapController.animateCamera(cameraUpdate, duration)

  • 功能:平滑移动地图视角到指定位置。

  • 参数

    • cameraUpdate:通过 map.newCameraPosition() 创建,包含目标位置和缩放级别。
    • duration:动画时长(毫秒)。
  • 使用场景:定位后将地图中心移到当前位置。

  • 代码示例

    let cameraPosition: mapCommon.CameraPosition = {
      target: { latitude: 22.878538, longitude: 113.886642 },
      zoom: 15
    };
    let cameraUpdate = map.newCameraPosition(cameraPosition);
    this.mapController?.animateCamera(cameraUpdate, 100);
    
  • 注意:需确保 mapController 已初始化。

8. mapController.addMarker(options: MarkerOptions)

  • 功能:在地图上添加位置标记。

  • 参数

    • position:标记点坐标。
    • icon:标记图标。
    • title, snippet:信息窗口内容。
  • 返回值Promise<map.Marker>

  • 使用场景:在用户位置显示标记点。

  • 代码示例

    let markerOptions: mapCommon.MarkerOptions = {
      position: { latitude: 22.878538, longitude: 113.886642 },
      icon: $r('app.media.point'),
      clickable: true,
      title: '当前位置'
    };
    this.mapController?.addMarker(markerOptions)
      .then((marker) => {
        marker.setSnippet('示例地址');
        marker.setInfoWindowVisible(true);
      });
    
  • 注意:需确保地图已加载。

9. backgroundTaskManager.startBackgroundRunning(context, mode, wantAgent)

  • 功能:启用后台定位。

  • 参数

    • context:Ability 的上下文。
    • mode:如 BackgroundMode.LOCATION
    • wantAgent:用于 Ability 重启。
  • 使用场景:应用退到后台时继续定位。

  • 代码示例

    let wantAgentInfo: wantAgent.WantAgentInfo = {
      wants: [{ bundleName: context.abilityInfo.bundleName, abilityName: context.abilityInfo.name }],
      operationType: wantAgent.OperationType.START_ABILITY,
      requestCode: 1,
      wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
    };
    wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => {
      backgroundTaskManager.startBackgroundRunning(context, backgroundTaskManager.BackgroundMode.LOCATION, wantAgentObj)
        .then(() => console.log('后台定位启动成功'));
    });
    
  • 注意:需申请后台运行权限。

10. backgroundTaskManager.stopBackgroundRunning(context)

  • 功能:停止后台定位。

  • 使用场景:用户关闭后台定位或应用退出。

  • 代码示例

    backgroundTaskManager.stopBackgroundRunning(context)
      .then(() => console.log('后台定位停止成功'))
      .catch((err) => hilog.error(0x0000, 'Background', `停止失败: ${err.message}`));
    
  • 注意:确保在适当时候清理资源。

11. connection.getDefaultNetSync()connection.getNetCapabilitiesSync(netHandle)

  • 功能:检查网络连接状态。

  • 使用场景:确保逆地理编码或地图加载的网络可用。

  • 代码示例

    try {
      let netHandle = connection.getDefaultNetSync();
      if (!netHandle || netHandle.netId === 0) return false;
      let netCapability = connection.getNetCapabilitiesSync(netHandle);
      return netCapability.networkCap?.includes(connection.NetCap.NET_CAPABILITY_VALIDATED) ?? false;
    } catch (err) {
      hilog.error(0x0000, 'Network', `网络检查失败: ${err.message}`);
      return false;
    }
    
  • 注意:网络不可用时需提示用户。

使用步骤

基于这些 API,开发一个 HarmonyOS 定位服务的流程如下:

  1. 初始化地图

    • 配置 MapComponent,设置初始位置和缩放级别。
    • 获取 MapComponentController 用于后续操作。
  2. 检查网络

    • 使用 connection.getDefaultNetSync() 确认网络可用。
  3. 获取缓存位置

    • 调用 geoLocationManager.getLastLocation() 显示初始位置。
  4. 获取实时位置

    • 配置 SingleLocationRequest,调用 getCurrentLocation()
  5. 启用持续定位

    • 使用 geoLocationManager.on('locationChange') 监听位置更新。
    • 在不需要时调用 off 停止。
  6. 逆地理编码

    • 使用 getAddressesFromLocation() 将坐标转为地址。
  7. 更新地图

    • 转换坐标(若需要),使用 animateCameraaddMarker 更新地图显示。
  8. 支持后台定位

    • 配置 WantAgent,调用 startBackgroundRunning 启用后台定位。
    • 使用 stopBackgroundRunning 停止。
  9. 处理错误

    • 通过 promptAction.showToast() 提示定位或网络错误。
    • 更新 UI 反映失败状态。
  10. 管理生命周期

    • aboutToAppear 初始化定位。
    • aboutToDisappear 清理资源。

完整示例

import { promptAction } from '@kit.ArkUI';
import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
import { MapComponent, mapCommon, map } from '@kit.MapKit';
import { geoLocationManager } from '@kit.LocationKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { common, wantAgent } from '@kit.AbilityKit';
import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import { connection } from '@kit.NetworkKit';
import { CommonConstants } from '../common/CommonConstants';
import { LocationInter } from '../model/LocationInter';

const TAG = '[Index]';

/**
 * 位置服务组件,提供地图显示、位置获取、持续定位和后台定位等功能
 */
@Entry
@Component
struct LocationService {
  @State address: string = ''; // 当前地址信息
  @State isBackgroundRunning: boolean = false; // 后台定位是否运行
  @State isOnLocationChange: boolean = false; // 位置变化监听是否开启
  @State isCacheLocation: boolean = false; // 是否显示缓存位置
  @StorageProp('bottomRectHeight') bottomRectHeight: number = 0;
  private mapController?: map.MapComponentController; // 地图控制器
  private callback?: AsyncCallback<map.MapComponentController>; // 地图加载回调
  private marker?: map.Marker; // 地图标记
  private mapOption?: mapCommon.MapOptions; // 地图选项

  /**
   * 组件即将显示时调用,初始化地图和相关配置
   */
  aboutToAppear(): void {
    if (!this.judgeHasNet()) {
      this.showToast("网络已断开,请检查网络设置");
    }

    // 初始化地图相机位置
    let cameraPosition: mapCommon.CameraPosition = {
      target: { longitude: 116.397455, latitude: 39.909187 },
      zoom: 15
    };

    // 配置地图选项
    this.mapOption = {
      position: cameraPosition,
      scaleControlsEnabled: true
    };

    // 地图加载完成回调
    this.callback = async (err, mapController) => {
      if (!err) {
        this.mapController = mapController;
        hilog.info(0x0000, TAG, '地图控制器初始化成功');
      } else {
        hilog.error(0x0000, TAG, `地图控制器初始化失败: ${err.message}`);
      }
    };
  }

  /**
   * 组件即将消失时调用,清理资源和停止定位服务
   */
  aboutToDisappear(): void {
    if (this.isBackgroundRunning) {
      this.stopContinuousTask();
    } else {
      if (this.isOnLocationChange) {
        this.offLocationChange();
      }
    }
  }

  /**
   * 获取缓存的位置信息
   */
  getPreLocationPosition(): void {
    try {
      let location = geoLocationManager.getLastLocation();
      this.getAddress({
        latitude: location.latitude,
        longitude: location.longitude
      });
      hilog.info(0x0000, TAG, '获取缓存位置成功');
    } catch (err) {
      hilog.error(0x0000, TAG, `获取缓存位置失败, 错误码: ${err.code}, 信息: ${err.message}`);
      this.locationFailedAlert(err.code);
    }
  }

  /**
   * 获取当前位置信息
   */
  getLocationPosition(): void {
    let request: geoLocationManager.SingleLocationRequest = {
      locatingPriority: CommonConstants.PRIORITY_LOCATING_SPEED,
      locatingTimeoutMs: CommonConstants.LOCATING_TIMEOUT_MS
    };

    geoLocationManager.getCurrentLocation(request)
      .then((location: geoLocationManager.Location) => {
        this.getAddress({
          latitude: location.latitude,
          longitude: location.longitude
        });
        hilog.info(0x0000, TAG, '获取当前位置成功');
      })
      .catch((err: BusinessError) => {
        hilog.error(0x0000, TAG, `获取当前位置失败, 错误码: ${err.code}, 信息: ${err.message}`);
        this.locationFailedAlert(err.code);
      });
  }

  /**
   * 开始监听位置变化
   */
  onLocationChange(): void {
    let request: geoLocationManager.ContinuousLocationRequest = {
      interval: 1,
      locationScenario: CommonConstants.NAVIGATION
    };

    try {
      geoLocationManager.on('locationChange', request, this.locationChange);
      if (!this.judgeHasNet()) {
        this.showToast("网络已断开,请检查网络设置");
        this.marker?.setInfoWindowVisible(false);
        this.address = '';
      }
      hilog.info(0x0000, TAG, '开始监听位置变化');
    } catch (err) {
      hilog.error(0x0000, TAG, `开启位置监听失败, 错误码: ${err.code}, 信息: ${err.message}`);
      this.locationFailedAlert(err.code);
    }
  }

  /**
   * 停止监听位置变化
   */
  offLocationChange(): void {
    try {
      geoLocationManager.off('locationChange', this.locationChange);
      hilog.info(0x0000, TAG, '停止监听位置变化');
    } catch (err) {
      hilog.error(0x0000, TAG, `停止位置监听失败, 错误码: ${err.code}, 信息: ${err.message}`);
    }
  }

  /**
   * 位置变化回调函数
   */
  locationChange = (location: geoLocationManager.Location): void => {
    this.getAddress({
      latitude: location.latitude,
      longitude: location.longitude
    });
    hilog.info(0x0000, TAG, `位置变化: 纬度=${location.latitude}, 经度=${location.longitude}`);
  }

  /**
   * 逆地理编码并在地图上绘制标记
   * @param location 位置信息
   */
  async getAddress(location: LocationInter) {
    try {
      // 坐标转换 (WGS84 -> GCJ02)
      let mapLocation: mapCommon.LatLng =
        await map.convertCoordinate(mapCommon.CoordinateType.WGS84, mapCommon.CoordinateType.GCJ02, {
          latitude: location.latitude,
          longitude: location.longitude
        });

      // 更新地图相机位置
      let cameraPosition: mapCommon.CameraPosition = {
        target: mapLocation,
        zoom: 15,
        tilt: 0,
        bearing: 0
      };

      let cameraUpdate = map.newCameraPosition(cameraPosition);
      this.mapController?.animateCamera(cameraUpdate, 100);

      // 设置或更新地图标记
      let makerOptions: mapCommon.MarkerOptions = {
        position: mapLocation,
        icon: $r('app.media.point'),
        clickable: true,
        title: CommonConstants.MARKER_TITLE
      };

      if (this.marker === undefined) {
        this.marker = await this.mapController?.addMarker(makerOptions);
      } else {
        this.marker.setPosition(mapLocation);
      }

      // 逆地理编码获取地址信息
      let reverseGeocodeRequest: geoLocationManager.ReverseGeoCodeRequest = {
        locale: getContext(this).resourceManager.getStringSync($r('app.string.language')),
        latitude: location.latitude,
        longitude: location.longitude,
        maxItems: 1
      };

      geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest, (err, data) => {
        if (data && data.length > 0) {
          this.address = data[0]?.placeName || '';
          this.marker?.setInfoWindowVisible(true);
          this.marker?.setSnippet(this.address);
          hilog.info(0x0000, TAG, `地址解析成功: ${this.address}`);

          if (this.isBackgroundRunning || this.isOnLocationChange) {
            this.isCacheLocation = false;
          }
        } else {
          hilog.error(0x0000, TAG, `地址解析失败, 错误码: ${err?.code}, 信息: ${err?.message}`);
          if (!this.isOnLocationChange && !this.isBackgroundRunning) {
            this.locationFailedAlert(err?.code || CommonConstants.REVERSE_GEOCODING_FAILED);
          }
        }
      });
    } catch (error) {
      hilog.error(0x0000, TAG, `获取地址信息失败, 错误码: ${error.code}, 信息: ${error.message}`);
    }
  }

  /**
   * 启动后台定位服务
   */
  startContinuousTask(): void {
    let context = getContext(this) as common.UIAbilityContext;
    if (!context) {
      hilog.error(0x0000, TAG, '无法获取UIAbilityContext');
      return;
    }

    // 创建WantAgent信息
    let wantAgentInfo: wantAgent.WantAgentInfo = {
      wants: [
        {
          bundleName: context.abilityInfo.bundleName,
          abilityName: context.abilityInfo.name
        }
      ],
      operationType: wantAgent.OperationType.START_ABILITY,
      requestCode: 1,
      wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
    };

    wantAgent.getWantAgent(wantAgentInfo)
      .then((wantAgentObj) => {
        backgroundTaskManager.startBackgroundRunning(context,
          backgroundTaskManager.BackgroundMode.LOCATION, wantAgentObj)
          .then(() => {
            this.onLocationChange();
            hilog.info(0x0000, TAG, '后台定位服务启动成功');
          })
          .catch((err: BusinessError) => {
            hilog.error(0x0000, TAG, `启动后台定位失败, 原因: ${JSON.stringify(err)}`);
          });
      })
      .catch((err: BusinessError) => {
        hilog.error(0x0000, TAG, `获取WantAgent失败, 原因: ${JSON.stringify(err)}`);
      });
  }

  /**
   * 停止后台定位服务
   */
  stopContinuousTask(): void {
    let context = getContext(this) as common.UIAbilityContext;
    if (!context) {
      hilog.error(0x0000, TAG, '无法获取UIAbilityContext');
      return;
    }

    backgroundTaskManager.stopBackgroundRunning(context)
      .then(() => {
        if (!this.isOnLocationChange) {
          this.offLocationChange();
        }
        hilog.info(0x0000, TAG, '后台定位服务停止成功');
      })
      .catch((err: BusinessError) => {
        hilog.error(0x0000, TAG, `停止后台定位失败, 原因: ${JSON.stringify(err)}`);
      });
  }

  /**
   * 显示位置相关错误提示
   * @param errCode 错误码
   */
  locationFailedAlert(errCode: number) {
    let message: string = '';

    switch (errCode) {
      case CommonConstants.LOCATION_SWITCH_OFF:
        message = "位置功能关闭,请检查位置设置";
        break;
      case CommonConstants.LOCATION_FAILED:
      case CommonConstants.REVERSE_GEOCODING_FAILED:
        message = "网络已断开,请检查网络设置";
        break;
      case CommonConstants.WIFI_BLUETOOTH_OFF:
        message = "WiFi或蓝牙关闭,请检查设置";
        break;
      default:
        message = "获取当前位置失败";
    }

    this.showToast(message);
    this.marker?.setInfoWindowVisible(false);
    this.address = '';
  }

  /**
   * 判断是否有网络连接
   */
  judgeHasNet(): boolean {
    try {
      let netHandle = connection.getDefaultNetSync();
      if (!netHandle || netHandle.netId === 0) {
        return false;
      }

      let netCapability = connection.getNetCapabilitiesSync(netHandle);
      let cap = netCapability.networkCap || [];

      return cap.includes(connection.NetCap.NET_CAPABILITY_VALIDATED);
    } catch (err) {
      hilog.error(0x0000, TAG, `网络连接检查失败, 错误码: ${err.code}, 信息: ${err.message}`);
      return false;
    }
  }

  /**
   * 显示Toast提示
   * @param message 提示信息
   */
  private showToast(message: string) {
    promptAction.showToast({
      message,
      duration: 2000
    });
  }

  build() {
    Column() {
      Row() {
        if (canIUse('SystemCapability.Map.Core')) {
          MapComponent({
            mapOptions: this.mapOption,
            mapCallback: this.callback,
            customInfoWindow: this.customInfoWindow
          })
            .width('100%')
            .height('100%')
        }
      }
      .height('85%')
      .width('100%')

      Column() {
        Row() {
          Text()
            .width(8)
            .height(8)
            .margin({ right: 7 })
            .backgroundColor($r('app.color.green'))
            .borderRadius(4)
            .offset({ y: 6 })
          Text() {
            Span(this.isCacheLocation ? "缓存位置逆地理编码结果:": "当前位置逆地理编码结果:")
              .fontSize(14)
              .lineHeight(19)
              .fontFamily('Medium')
              .fontColor($r('app.color.shallow_green'))
            Span(this.address)
              .fontSize(14)
              .lineHeight(19)
              .fontFamily('Medium')
              .fontColor($r('app.color.black'))
          }
          .margin({ right: 16 })
        }
        .width('100%')
        .padding({
          top: 24,
          bottom: 16,
          left: 16,
          right: 16
        })
        .margin({
          left: 16,
          right: 16
        })
        .constraintSize({ maxWidth: '100%' })
        .alignItems(VerticalAlign.Top)

        Column() {
          Row() {
            Text("持续定位")
              .fontSize(16)
              .fontWeight(FontWeight.Medium)

            Toggle({ type: ToggleType.Switch })
              .onChange((isOn: boolean) => {
                if (isOn) {
                  this.isOnLocationChange = true;
                  this.onLocationChange();
                } else {
                  this.isOnLocationChange = false;
                  if (!this.isBackgroundRunning) {
                    this.offLocationChange();
                  }
                }
              })
          }
          .height(48)
          .width('100%')
          .constraintSize({ maxWidth: '100%' })
          .justifyContent(FlexAlign.SpaceBetween)
          .padding({
            left: 16,
            right: 16
          })

          Row() {
            Text("后台定位")
              .fontSize(16)
              .fontWeight(FontWeight.Medium)

            Toggle({ type: ToggleType.Switch })
              .onChange((isOn: boolean) => {
                if (isOn) {
                  this.isBackgroundRunning = true;
                  this.startContinuousTask();
                } else {
                  this.isBackgroundRunning = false;
                  this.stopContinuousTask();
                }
              })
          }
          .height(48)
          .width('100%')
          .constraintSize({ maxWidth: '100%' })
          .justifyContent(FlexAlign.SpaceBetween)
          .padding({
            left: 16,
            right: 16
          })
          .margin({
            bottom: 24
          })

          Button("获取缓存位置")
            .onClick(() => {
              this.getPreLocationPosition();
              this.isCacheLocation = true;
            })
            .width('100%')
            .height(40)
            .backgroundColor($r('app.color.blue'))
            .fontColor($r('app.color.white'))
            .fontWeight(FontWeight.Medium)
            .margin({
              bottom: 12
            })

          Button("获取当前位置")
            .onClick(() => {
              this.getLocationPosition();
              this.isCacheLocation = false;
            })
            .width('100%')
            .height(40)
            .backgroundColor($r('app.color.blue'))
            .fontColor($r('app.color.white'))
            .fontWeight(FontWeight.Medium)
        }
        .width('100%')
        .constraintSize({ maxWidth: '100%' })
        .margin({
          left: 16,
          right: 16,
          bottom: 16
        })
      }
      .width('100%')
      .borderRadius({
        topLeft: 32,
        topRight: 32
      })
      .backgroundColor($r('sys.color.comp_background_list_card'))
      .position({ bottom: 0 })
    }
    .height('100%')
    .padding({
      bottom: px2vp(this.bottomRectHeight)
    })
  }

  @BuilderParam customInfoWindow: (params: map.MarkerDelegate) => void = this.customInfoWindowBuilder;

  @Builder
  customInfoWindowBuilder(params: map.MarkerDelegate) {
    if (params.marker) {
      Column() {
        Text(params.marker.getTitle())
          .width(180)
          .height(24)
          .backgroundColor($r('app.color.green'))
          .borderRadius({
            topLeft: 12,
            topRight: 12
          })
          .padding({
            top: 4,
            bottom: 4,
            left: 12
          })
          .fontSize(12)
          .fontColor($r('app.color.white_e6'))
          .lineHeight(16)
          .textAlign(TextAlign.Start)
        Text(params.marker.getSnippet())
          .width(180)
          .backgroundColor($r('app.color.white'))
          .borderRadius({
            bottomLeft: 12,
            bottomRight: 12
          })
          .padding({
            top: 4,
            bottom: 6,
            left: 12,
            right: 8
          })
          .fontSize(14)
          .fontColor($r('app.color.black_e6'))
          .lineHeight(19)
          .textAlign(TextAlign.Start)
      }
    }
  }
}

总结

以上Demo通过整合缓存定位、实时定位、持续定位、后台定位和地图交互,展示了一个功能丰富的定位服务。核心 API 如 geoLocationManagermapController 提供了灵活的定位和地图功能,开发者可以参考上述步骤和代码示例,轻松实现导航、位置分享或跟踪等功能。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐