HarmonyOS 鸿蒙Next中使用高德地图 SDK 实现路径规划功能

HarmonyOS 鸿蒙Next中使用高德地图 SDK 实现路径规划功能 在开发导航类应用时,需要实现多种出行方式的路径规划:

  1. 支持步行、骑行、驾车、公交四种出行方式
  2. 返回路线距离、预计用时、详细导航步骤
  3. 驾车路线需要显示路况信息(拥堵状态)
  4. 公交路线需要显示换乘方案、途经站点
  5. 返回路线坐标点用于地图上绑制路线
3 回复

1. 配置高德地图 SDK

oh-package.json5 中添加依赖:

{
  "dependencies": {
    "[@amap](/user/amap)/amap_lbs_search": "^1.0.0",
    "[@amap](/user/amap)/amap_lbs_map3d": "^1.0.0"
  }
}

2. 定义路线数据模型

// models/RouteModels.ets
import { LatLng } from '[@amap](/user/amap)/amap_lbs_map3d'
import { TMC } from '[@amap](/user/amap)/amap_lbs_search'

/**
 * 路线类型
 */
export type RouteType = 'walk' | 'ride' | 'drive' | 'bus'

/**
 * 路线步骤
 */
export interface RouteStep {
  instruction: string   // 导航指令
  action: string        // 动作(如"左转"、"直行")
  distance: number      // 距离(米)
  duration: number      // 时长(秒)
}

/**
 * 路线结果
 */
export interface RouteResult {
  type: RouteType
  distance: number      // 总距离(米)
  duration: number      // 总时长(秒)
  steps: RouteStep[]    // 导航步骤
  polyline: LatLng[]    // 路线坐标点(用于绑制)
  
  // 驾车专用
  taxiCost?: number     // 打车费用
  tolls?: number        // 过路费
  tmcs?: TMC[]          // 路况信息
  
  // 公交专用
  busLines?: string[]   // 公交线路名称
  walkDistance?: number // 步行距离
}

3. 创建路线搜索服务

// services/RouteSearchService.ets
import {
  RouteSearchV2,
  WalkRouteQueryV2,
  DriveRouteQueryV2,
  RideRouteQueryV2,
  BusRouteQueryV2,
  WalkRouteResultV2,
  DriveRouteResultV2,
  RideRouteResultV2,
  BusRouteResultV2,
  FromAndTo,
  LatLonPoint,
  DrivingStrategy,
  AMapException,
  OnRouteSearchListenerV2,
  RouteSearch
} from '[@amap](/user/amap)/amap_lbs_search'
import { LatLng } from '[@amap](/user/amap)/amap_lbs_map3d'
import { RouteResult, RouteStep } from '../models/RouteModels'

/**
 * 路线搜索回调
 */
export interface RouteSearchCallback {
  onSuccess: (routes: RouteResult[]) => void
  onError: (message: string) => void
}

/**
 * 路线搜索服务类
 */
export class RouteSearchService {
  private routeSearch?: RouteSearchV2
  private context: Context
  private callback?: RouteSearchCallback

  constructor(context: Context) {
    this.context = context
  }
}

4. 实现步行路线搜索

/**
 * 搜索步行路线
 */
searchWalkRoute(start: LatLonPoint, end: LatLonPoint, callback: RouteSearchCallback): void {
  this.callback = callback
  
  console.info(`[RouteSearch] 🚶 开始搜索步行路线`)
  console.info(`  起点: ${start.getLatitude()}, ${start.getLongitude()}`)
  console.info(`  终点: ${end.getLatitude()}, ${end.getLongitude()}`)
  
  this.routeSearch = new RouteSearchV2(this.context)
  this.routeSearch.setRouteSearchListener(this.createWalkListener())
  
  const fromAndTo = new FromAndTo(start, end)
  const query = new WalkRouteQueryV2(fromAndTo)
  query.setShowFields(0b0011111)  // 返回所有字段
  
  this.routeSearch.calculateWalkRouteAsyn(query)
}

/**
 * 创建步行路线监听器
 */
private createWalkListener(): OnRouteSearchListenerV2 {
  return {
    onWalkRouteSearched: (result: WalkRouteResultV2, errorCode: number) => {
      if (errorCode === AMapException.CODE_AMAP_SUCCESS) {
        const paths = result.getPaths()
        if (paths && paths.length > 0) {
          const routeResults: RouteResult[] = []
          
          for (const path of paths) {
            const steps: RouteStep[] = []
            const pathSteps = path.getSteps()
            
            if (pathSteps) {
              for (const step of pathSteps) {
                steps.push({
                  instruction: step.getInstruction() || '',
                  action: step.getAction() || '',
                  distance: step.getDistance() || 0,
                  duration: step.getDuration() || 0
                })
              }
            }

            // 获取路线坐标点
            const polylinePoints: LatLng[] = []
            const polylineData = path.getPolyline()
            if (polylineData) {
              for (const point of polylineData) {
                polylinePoints.push(new LatLng(point.getLatitude(), point.getLongitude()))
              }
            }

            routeResults.push({
              type: 'walk',
              distance: path.getDistance() || 0,
              duration: path.getDuration() || 0,
              steps: steps,
              polyline: polylinePoints
            })
          }
          
          console.info(`[RouteSearch] ✅ 找到 ${routeResults.length} 条步行路线`)
          this.callback?.onSuccess(routeResults)
        } else {
          this.callback?.onError('未找到步行路线')
        }
      } else {
        this.callback?.onError(`路线搜索失败,错误码: ${errorCode}`)
      }
    },
    // 其他回调留空
    onDriveRouteSearched: () => {},
    onRideRouteSearched: () => {},
    onBusRouteSearched: () => {}
  }
}

5. 实现驾车路线搜索

/**
 * 搜索驾车路线
 * @param strategy 驾车策略(可选)
 */
searchDriveRoute(
  start: LatLonPoint,
  end: LatLonPoint,
  callback: RouteSearchCallback,
  strategy: number = DrivingStrategy.DEFAULT.getValue()
): void {
  this.callback = callback
  
  console.info(`[RouteSearch] 🚗 开始搜索驾车路线(策略: ${strategy})`)
  
  this.routeSearch = new RouteSearchV2(this.context)
  this.routeSearch.setRouteSearchListener(this.createDriveListener())
  
  const fromAndTo = new FromAndTo(start, end)
  const query = new DriveRouteQueryV2(fromAndTo, strategy, undefined, undefined, "")
  query.setShowFields(0b0011111)
  
  this.routeSearch.calculateDriveRouteAsyn(query)
}

/**
 * 创建驾车路线监听器
 */
private createDriveListener(): OnRouteSearchListenerV2 {
  return {
    onDriveRouteSearched: (result: DriveRouteResultV2 | undefined, errorCode: number) => {
      if (errorCode === AMapException.CODE_AMAP_SUCCESS && result) {
        const paths = result.getPaths()
        if (paths && paths.length > 0) {
          const routeResults: RouteResult[] = []
          
          for (const path of paths) {
            const steps: RouteStep[] = []
            const tmcs: TMC[] = []
            const pathSteps = path.getSteps()
            
            if (pathSteps) {
              for (const step of pathSteps) {
                const navi = step.getNavi()
                steps.push({
                  instruction: step.getInstruction() || '',
                  action: navi?.getAction() || '',
                  distance: this.parseDistanceFromInstruction(step.getInstruction() || ''),
                  duration: 0
                })
                
                // 提取路况信息(TMC)
                const tmcList = step.getTMCs()
                if (tmcList) {
                  for (const tmc of tmcList) {
                    tmcs.push(tmc)
                  }
                }
              }
            }

            const polylinePoints: LatLng[] = []
            const polylineData = path.getPolyline()
            if (polylineData) {
              for (const point of polylineData) {
                polylinePoints.push(new LatLng(point.getLatitude(), point.getLongitude()))
              }
            }

            routeResults.push({
              type: 'drive',
              distance: path.getDistance() || 0,
              duration: path.getCost()?.getDuration() || 0,
              steps: steps,
              polyline: polylinePoints,
              taxiCost: Math.floor(result.getTaxiCost() || 0),
              tolls: 0,
              tmcs: tmcs
            })
          }
          
          console.info(`[RouteSearch] ✅ 找到 ${routeResults.length} 条驾车路线`)
          this.callback?.onSuccess(routeResults)
        } else {
          this.callback?.onError('未找到驾车路线')
        }
      } else {
        this.callback?.onError(`路线搜索失败,错误码: ${errorCode}`)
      }
    },
    onWalkRouteSearched: () => {},
    onRideRouteSearched: () => {},
    onBusRouteSearched: () => {}
  }
}

6. 实现骑行路线搜索

/**
 * 搜索骑行路线
 */
searchRideRoute(start: LatLonPoint, end: LatLonPoint, callback: RouteSearchCallback): void {
  this.callback = callback
  
  console.info(`[RouteSearch] 🚴 开始搜索骑行路线`)
  
  this.routeSearch = new RouteSearchV2(this.context)
  this.routeSearch.setRouteSearchListener(this.createRideListener())
  
  const fromAndTo = new FromAndTo(start, end)
  const query = new RideRouteQueryV2(fromAndTo)
  query.setShowFields(0b0011111)
  
  this.routeSearch.calculateRideRouteAsyn(query)
}

/**
 * 创建骑行路线监听器
 */
private createRideListener(): OnRouteSearchListenerV2 {
  return {
    onRideRouteSearched: (result: RideRouteResultV2, errorCode: number) => {
      if (errorCode === AMapException.CODE_AMAP_SUCCESS) {
        const paths = result.getPaths()
        if (paths && paths.length > 0) {
          const routeResults: RouteResult[] = paths.map(path => {
            const steps: RouteStep[] = []
            const pathSteps = path.getSteps()
            
            if (pathSteps) {
              for (const step of pathSteps) {
                steps.push({
                  instruction: step.getInstruction() || '',
                  action: step.getAction() || '',
                  distance: step.getDistance() || 0,
                  duration: step.getDuration() || 0
                })
              }
            }

            const polylinePoints: LatLng[] = []
            const polylineData = path.getPolyline()
            if (polylineData) {
              for (const point of polylineData) {
                polylinePoints.push(new LatLng(point.getLatitude(), point.getLongitude()))
              }
            }

            return {
              type: 'ride' as const,
              distance: path.getDistance() || 0,
              duration: path.getDuration() || 0,
              steps: steps,
              polyline: polylinePoints
            }
          })
          
          console.info(`[RouteSearch] ✅ 找到 ${routeResults.length} 条骑行路线`)
          this.callback?.onSuccess(routeResults)
        } else {
          this.callback?.onError('未找到骑行路线')
        }
      } else {
        this.callback?.onError(`路线搜索失败,错误码: ${errorCode}`)
      }
    },
    onWalkRouteSearched: () => {},
    onDriveRouteSearched: () => {},
    onBusRouteSearched: () => {}
  }
}

7. 实现公交路线搜索

/**
 * 搜索公交路线
 * @param cityCode 城市代码(如北京 '010')
 */
searchBusRoute(
  start: LatLonPoint,
  end: LatLonPoint,
  callback: RouteSearchCallback,
  cityCode: string
): void {
  this.callback = callback
  
  console.info(`[RouteSearch] 🚌 开始搜索公交路线(城市: ${cityCode})`)
  
  this.routeSearch = new RouteSearchV2(this.context)
  this.routeSearch.setRouteSearchListener(this.createBusListener())
  
  const fromAndTo = new FromAndTo(start, end)
  const query = new BusRouteQueryV2(fromAndTo, RouteSearch.BusDefault, cityCode, 0)
  query.setCityd(cityCode)  // 目的地城市代码
  query.setShowFields(0b0011111)
  
  this.routeSearch.calculateBusRouteAsyn(query)
}

/**
 * 创建公交路线监听器
 */
private createBusListener(): OnRouteSearchListenerV2 {
  return {
    onBusRouteSearched: (result: BusRouteResultV2 | undefined, errorCode: number) => {
      if (errorCode === AMapException.CODE_AMAP_SUCCESS && result) {
        const paths = result.getPaths()
        if (paths && paths.length > 0) {
          const routeResults: RouteResult[] = []
          
          for (const path of paths) {
            const steps: RouteStep[] = []
            const polylinePoints: LatLng[] = []
            const busLineNames: string[] = []
            let totalWalkDistance = 0
            
            const busSteps = path.getSteps()
            if (busSteps) {
              for (const busStep of busSteps) {
                // 步行段
                const walk = busStep.getWalk()
                if (walk) {
                  const walkDistance = walk.getDistance() || 0
                  totalWalkDistance += walkDistance
                  
                  const walkSteps = walk.getSteps()
                  if (walkSteps) {
                    for (const walkStep of walkSteps) {
                      steps.push({
                        instruction: `步行 ${walkStep.getInstruction() || ''}`,
                        action: 'walk',
                        distance: walkStep.getDistance() || 0,
                        duration: walkStep.getDuration() || 0
                      })
                    }
                  }
                }
                
                // 公交/地铁段
                const busLines = busStep.getBusLines()
                if (busLines && busLines.length > 0) {
                  for (const busLine of busLines) {
                    const lineName = busLine.getBusLineName() || ''
                    const departure = busLine.getDepartureBusStation()?.getBusStationName() || ''
                    const arrival = busLine.getArrivalBusStation()?.getBusStationName() || ''
                    const passCount = busLine.getPassStationNum() || 0
                    
                    busLineNames.push(lineName)
                    
                    steps.push({
                      instruction: `乘坐 ${lineName},${departure} 上车,${arrival} 下车,途经 ${passCount} 站`,
                      action: 'bus',
                      distance: busLine.getDistance() || 0,
                      duration: busLine.getDuration() || 0
                    })
                    
                    // 获取公交线路坐标
                    const busPolyline = busLine.getPolyline()
                    if (busPolyline) {
                      for (const point of busPolyline) {
                        polylinePoints.push(new LatLng(point.getLatitude(), point.getLongitude()))
                      }
                    }
                  }
                }
              }
            }

            routeResults.push({
              type: 'bus',
              distance: path.getDistance() || 0,
              duration: path.getDuration() || 0,
              steps: steps,
              polyline: polylinePoints,
              busLines: busLineNames,
              walkDistance: totalWalkDistance
            })
          }
          
          console.info(`[RouteSearch] ✅ 找到 ${routeResults.length} 条公交路线`)
          this.callback?.onSuccess(routeResults)
        } else {
          this.callback?.onError('未找到公交路线')
        }
      } else {
        this.callback?.onError(`路线搜索失败,错误码: ${errorCode}`)
      }
    },
    onWalkRouteSearched: () => {},
    onDriveRouteSearched: () => {},
    onRideRouteSearched: () => {}
  }
}

8. 在页面中使用

// pages/RoutePlanPage.ets
import { RouteSearchService, RouteSearchCallback } from '../services/RouteSearchService'
import { RouteResult, RouteType } from '../models/RouteModels'
import { LatLonPoint } from '[@amap](/user/amap)/amap_lbs_search'

[@Entry](/user/Entry)
[@Component](/user/Component)
struct RoutePlanPage {
  [@State](/user/State) selectedType: RouteType = 'walk'
  [@State](/user/State) routeResult: RouteResult | null = null
  [@State](/user/State) isSearching: boolean = false
  
  private routeService?: RouteSearchService
  
  // 起终点
  private start = new LatLonPoint(39.9042, 116.4074)  // 天安门
  private end = new LatLonPoint(39.9163, 116.3972)   // 北海公园
  
  aboutToAppear(): void {
    this.routeService = new RouteSearchService(getContext(this))
  }
  
  build() {
    Column({ space: 16 }) {
      // 出行方式选择
      Row({ space: 8 }) {
        ForEach(['walk', 'ride', 'drive', 'bus'], (type: RouteType) => {
          Button(this.getTypeLabel(type))
            .backgroundColor(this.selectedType === type ? '#A9846A' : '#E0E0E0')
            .fontColor(this.selectedType === type ? '#FFFFFF' : '#333333')
            .onClick(() => {
              this.selectedType = type
              this.searchRoute()
            })
        })
      }
      
      // 搜索状态
      if (this.isSearching) {
        LoadingProgress().width(40).height(40)
      }
      
      // 路线结果
      if (this.routeResult) {
        Column({ space: 8 }) {
          Text(`总距离: ${this.formatDistance(this.routeResult.distance)}`)
          Text(`预计用时: ${this.formatDuration(this.routeResult.duration)}`)
          
          if (this.routeResult.taxiCost) {
            Text(`预计打车费: ¥${this.routeResult.taxiCost}`)
          }
          
          Divider()
          
          // 导航步骤
          List() {
            ForEach(this.routeResult.steps, (step: RouteStep, index: number) => {
              ListItem() {
                Row({ space: 8 }) {
                  Text(`${index + 1}`)
                    .width(24)
                    .textAlign(TextAlign.Center)
                  Text(step.instruction)
                    .

更多关于HarmonyOS 鸿蒙Next中使用高德地图 SDK 实现路径规划功能的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中实现高德地图SDK路径规划,首先需在AppGallery Connect配置应用并获取API Key。通过DevEco Studio集成高Maps SDK,在module.json5中声明ohos.permission.LOCATION等权限。使用@amap/amap-harmonyos包,调用AMapNavi的calculateDriveRoute方法传入起点、终点坐标及策略参数。通过回调处理RouteResult返回的路径信息,可结合Map组件进行可视化绘制。注意SDK需使用HarmonyOS专用版本,并遵循官方坐标转换规范。

在HarmonyOS Next中使用高德地图SDK实现路径规划功能,核心是调用RouteSearch模块。以下是关键步骤和代码要点:

  1. 初始化与权限配置module.json5中声明ohos.permission.LOCATION位置权限,并配置高德地图的access_token

  2. 路线搜索参数设置 根据出行方式创建对应的RouteSearch.FromAndTo(起终点)和搜索参数:

    • 驾车:DrivingRoutePlanParam,需设置drivingStrategy(策略)并启用setOpenTraffic(true)获取路况。
    • 公交:TransitRoutePlanParam,设置transitStrategy(如最经济、最快捷)。
    • 步行/骑行:WalkingRoutePlanParam/RidingRoutePlanParam

    示例(驾车):

    let fromAndTo: routeSearch.FromAndTo = {
        from: { lat: 39.9, lon: 116.3 },
        to: { lat: 40.0, lon: 116.4 }
    };
    let param: routeSearch.DrivingRoutePlanParam = {
        fromAndTo: fromAndTo,
        drivingStrategy: routeSearch.DrivingStrategy.FASTEST_SHORT_DISTANCE
    };
    
  3. 执行搜索并解析结果 调用routeSearch.calculateRoute(),在回调中处理结果:

    • RoutePlanResult获取paths(路线数组),每条path包含distance(距离)、duration(用时)。
    • 驾车路线:从DrivingPathsteps读取traffic(路况状态:0畅通、1缓行、2拥堵)。
    • 公交路线:从TransitPathsegments获取busLines(公交线路)及boarding/alighting站点信息。
    • 坐标点:所有出行方式的steps均提供polyline(坐标串),可用于地图绘制。
  4. 地图绘制polyline坐标串转换为Map模块的Polyline对象,并添加到地图图层。

注意事项

  • 公交/驾车需分别使用专属参数类,确保返回完整数据。
  • 路径规划为网络请求,需在主线程外执行。
  • 坐标点需按高德GCJ-02坐标系处理,与HarmonyOS地图匹配。

通过以上步骤,可完整实现多方式路径规划、数据解析及地图可视化。

回到顶部