HarmonyOS鸿蒙Next中如何在应用内直接拉起腾讯/百度/高德地图进行导航

HarmonyOS鸿蒙Next中如何在应用内直接拉起腾讯/百度/高德地图进行导航 如何在应用内直接拉起腾讯/百度/高德地图进行导航

5 回复

导航类应用扩展面板参数说明

startAbilityByType接口中type字段为navigation,支持路线规划、导航、位置搜索三种意图场景,对应的wantParam参数如下:

说明

本文中的经纬度均采用GCJ-02坐标系统。

  • 路线规划场景
参数名 类型 必填 说明
sceneType number 意图场景,表明本次请求对应的操作意图。默认为1,路线规划场景填1或不填。
originName string 起点名称。
originLatitude number 起点纬度。
originLongitude number 起点经度。
originPoiIds Record<number, string> 起点POI ID列表,当前仅支持传入花瓣地图、高德地图、百度地图的POI ID。
destinationName string 终点名称。
destinationLatitude number 终点纬度。
destinationLongitude number 终点经度。
destinationPoiIds Record<number, string> 终点POI ID列表,当前仅支持传入花瓣地图、高德地图、百度地图的POI ID。
vehicleType number 交通出行工具,取值:0-驾车,1-步行,2-骑行,3-公交。
  • 导航场景
参数名 类型 必填 说明
sceneType number 意图场景,表明本次请求对应的操作意图。导航场景填2。
destinationName string 终点名称。
destinationLatitude number 终点纬度。
destinationLongitude number 终点经度。
destinationPoiIds Record<number, string> 终点POI ID列表,当前仅支持传入花瓣地图、高德地图、百度地图的POI ID。
  • 位置搜索场景
参数名 类型 必填 说明
sceneType number 意图场景,表明本次请求对应的操作意图。位置搜索场景填3。
destinationName string 地点名称。

直接上代码:

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
const TAG = 'EntryAbility';
export default class EntryAbility extends UIAbility {
    windowStage: window.WindowStage | null = null;
    uri?: string;
    destinationLatitude?: number;
    destinationLongitude?: number;
    destinationName?: string;
    originName?: string;
    originLatitude?: number;
    originLongitude?: number;
    vehicleType?: number;
    destinationPoiId?: string;
    originPoiId?: string;
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        hilog.info(0x0000, TAG, `onCreate, want=${JSON.stringify(want)}`);
        super.onCreate(want, launchParam);
        this.parseWant(want);
    }
    onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        hilog.info(0x0000, TAG, `onNewWant, want=${JSON.stringify(want)}`);
        super.onNewWant(want, launchParam);
        this.parseWant(want);
        if (!this.windowStage) {
            hilog.error(0x0000, TAG, 'windowStage is null');
            this.context.terminateSelf();
            return;
        }
        this.loadPage(this.windowStage);
    }
    private parseWant(want: Want): void {
        this.uri = want.uri as string | undefined;
        this.destinationLatitude = want.parameters?.destinationLatitude as number | undefined;
        this.destinationLongitude = want.parameters?.destinationLongitude as number | undefined;
        this.destinationName = want.parameters?.destinationName as string | undefined;
        this.originName = want.parameters?.originName as string | undefined;
        this.originLatitude = want.parameters?.originLatitude as number | undefined;
        this.originLongitude = want.parameters?.originLongitude as number | undefined;
        this.vehicleType = want.parameters?.vehicleType as number | undefined;
        this.destinationPoiId = want.parameters?.destinationPoiId as string | undefined;
        this.originPoiId = want.parameters?.originPoiId as string | undefined;
    }
    private loadPage(windowStage: window.WindowStage): void {
        hilog.info(0x0000, TAG, `loadPage, uri=${this.uri}`);
        if (this.uri === 'maps://navigation') {
            // 构建导航场景参数
            const storage: LocalStorage = new LocalStorage({
                "destinationLatitude": this.destinationLatitude,
                "destinationLongitude": this.destinationLongitude,
                "destinationPoiId": this.destinationPoiId
            } as Record<string, Object>);
            // 拉起导航页面
            windowStage.loadContent('pages/NavigationPage', storage)
        } else if (this.uri === 'maps://routePlan') {
            // 构建路径规划场景参数
            const storage: LocalStorage = new LocalStorage({
                "destinationLatitude": this.destinationLatitude,
                "destinationLongitude": this.destinationLongitude,
                "destinationName": this.destinationName,
                "originName": this.originName,
                "originLatitude": this.originLatitude,
                "originLongitude": this.originLongitude,
                "vehicleType": this.vehicleType,
                "destinationPoiId": this.destinationPoiId,
                "originPoiId": this.originPoiId
            } as Record<string, Object>);
            // 拉起路径规划页面
            windowStage.loadContent('pages/RoutePlanPage', storage)
        }  else if (this.uri === 'maps://search') {
            // 构建位置搜索场景参数
            const storage: LocalStorage = new LocalStorage({
                "destinationName": this.destinationName
            } as Record<string, Object>);
            // 拉起位置搜索页面
            windowStage.loadContent('pages/PlaceSearchPage', storage)
        } else {
            // 默认拉起首页
            windowStage.loadContent('pages/Index', (err) => {
                if (err.code) {
                    hilog.error(0x0000, TAG, 'Failed to load the content. Cause: %{public}s',
                        JSON.stringify(err) ?? '');
                    return;
                }
                hilog.info(0x0000, TAG, 'Succeeded in loading the content.');
            });
        }
    }
    onDestroy(): void {
        hilog.info(0x0000, TAG, `onDestroy`);
    }
    onWindowStageCreate(windowStage: window.WindowStage): void {
        hilog.info(0x0000, TAG, `onWindowStageCreate`);
        this.windowStage = windowStage;
        this.loadPage(this.windowStage);
    }
    onWindowStageDestroy(): void {
        hilog.info(0x0000, TAG, '%{public}s', 'Ability onWindowStageDestroy');
    }
    onForeground(): void {
        hilog.info(0x0000, TAG, '%{public}s', 'Ability onForeground');
    }
    onBackground(): void {
        hilog.info(0x0000, TAG, '%{public}s', 'Ability onBackground');
    }
}

更多关于HarmonyOS鸿蒙Next中如何在应用内直接拉起腾讯/百度/高德地图进行导航的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


找相关APP的SDK,

【实现思路】

  • 判断地图应用是否安装 通过 scheme 检查(如 qqmap://baidumap://amapuri://),在拉起地图前先判断 App 是否存在,避免跳转失败。需要注意,这些 scheme 必须在 module.json5querySchemes 字段中声明,否则 canOpenLink 会返回错误或不准确的结果。
  • 拉起导航(startAbility 与 openLink 两种方式)
  • startAbilityByWant:通过构建 Want 对象携带导航参数,包括起点名称、起点经纬度、终点名称、终点经纬度、导航模式(驾车、步行、公交等)等,精确传递给第三方地图 App。
  • openLink:通过 URL scheme 拼接导航参数,直接拉起地图应用进行导航,同样支持传递起终点坐标、路线偏好等信息。
  • 未安装提示逻辑 如果检测到地图 App 未安装,统一调用提示方法(如 promptAction.showToast)告知用户“腾讯地图/百度地图/高德地图未安装”,同时可扩展为引导用户前往应用市场下载。
  • querySchemes 配置的重要性 只有在 module.json5 中声明了对应的 scheme,鸿蒙系统才能正确识别并允许通过 canOpenLink 或 openLink 拉起第三方 App,否则即便 App 已安装,也会出现“暂无打开方式”的提示。

通过封装,开发者只需调用相应方法并传入 起点、终点名称与经纬度,就能轻松实现多地图导航功能,避免重复实现安装判断、参数拼接和异常处理逻辑。

一、前提:querySchemes 配置

在鸿蒙中,判断应用是否安装通常依赖 bundleManager.canOpenLink(scheme)必须在自己应用的 module.json5 中配置对应的 scheme,否则即使应用安装了,也可能返回 false。

示例配置:

"module": {
 "querySchemes": [
   "qqmap",
   "baidumap",
   "amapuri"
 ]
}
  • 这里的 qqmap, baidumap, amapuri 对应三方地图的 scheme。
  • 仅被拉起的应用需要配置自己的 URI;自己的应用只需配置 querySchemes

配置错误是 canOpenLink 返回 false 的常见原因。

二、工具类设计思路

封装思路:

  1. 定义 包名scheme
export enum MapApp {
 TENCENT = 'com.tencent.mapohos',
 BAIDU = 'com.baidu.hmmap',
 AMAP = 'com.amap.hmapp'
}

export enum MapScheme {
 TENCENT = 'qqmap://',
 BAIDU = 'baidumap://',
 AMAP = 'amapuri://'
}
  1. 提供两类拉起方式:
  • startAbility 方式:可以传递完整参数,并可用于鸿蒙应用或元服务。
  • openLink 方式:类似 URI Scheme 方式,调用简单,直接拉起第三方应用。
  1. 判断安装,未安装统一提示。

三、方法拆解讲解

1. 判断应用是否安装

private isMapInstalled(scheme: string): boolean {
 try {
   return bundleManager.canOpenLink(scheme);
 } catch (err) {
   console.error(`canOpenLink failed for ${scheme}`, JSON.stringify(err));
   return false;
 }
}
  • 原理:通过 scheme 查询应用是否能被打开。
  • 注意:必须在 querySchemes 中声明,否则返回 false。
  • 示例
if (!this.isMapInstalled(MapScheme.TENCENT)) {
 this.showNotInstalledMsg('腾讯地图');
}

2. startAbility 方式拉起导航

async openTencentMapByWant(from: string, fromLat: number, fromLng: number,
                          to: string, toLat: number, toLng: number) {
 if (!this.isMapInstalled(MapScheme.TENCENT)) {
   this.showNotInstalledMsg('腾讯地图');
   return;
 }
 const want: Want = {
   action: 'ohos.want.action.viewData',
   uri: `qqmap://map/routeplan?type=drive` +
        `&from=${from}&fromcoord=${fromLat},${fromLng}` +
        `&to=${to}&tocoord=${toLat},${toLng}` +
        `&policy=0&referer=myApp`
 };
 this.openMethod.startAbilityByWant(want);
}
  • 适用场景:希望完整控制参数、或者拉起鸿蒙应用/元服务。
  • 优点:可捕获异常,便于处理未安装或其他错误。

注意:百度地图在鸿蒙上暂时不支持 canOpenLink 判断,可直接尝试拉起。

3.openLink 方式拉起导航

async openTencentMapByLink(from: string, fromLat: number, fromLng: number,
                          to: string, toLat: number, toLng: number) {
 if (!this.isMapInstalled(MapScheme.TENCENT)) {
   this.showNotInstalledMsg('腾讯地图');
   return;
 }
 const url = `qqmap://map/routeplan?type=drive` +
             `&from=${from}&fromcoord=${fromLat},${fromLng}` +
             `&to=${to}&tocoord=${toLat},${toLng}` +
             `&policy=0&referer=myApp`;
 this.openMethod.openLink(url);
}
  • 适用场景:快速拉起第三方应用。
  • 优点:无需关心包名和 Ability 名称。
  • 注意:需要保证 scheme 配置正确,否则会出现“暂无打开方式”。

4.统一未安装提示

private showNotInstalledMsg(appName: string) {
 promptAction.showToast({ message: `${appName} 未安装` });
}
  • 思路:所有地图统一调用该方法提示。
  • 可进一步引导用户前往应用市场下载。

四、使用示例

       // 拉起腾讯地图导航
       Button('拉起腾讯地图-ByLink').onClick((event: ClickEvent) => {
         this.mapNavigator.openTencentMapByLink('我的位置', 39.908823, 116.397470, '天安门', 39.915156, 116.403694)
       })
       // 拉起百度地图导航
       Button('拉起百度地图-ByLink').onClick((event: ClickEvent) => {
         this.mapNavigator.openBaiduMapByLink('我的位置', 39.908823, 116.397470, '天安门', 39.915156, 116.403694)
       })
       // 拉起高德地图导航
       Button('拉起高德打车-ByLink').onClick((event: ClickEvent) => {
         this.mapNavigator.openAmapByLink('我的位置', 39.908823, 116.397470, '天安门', 39.915156, 116.403694)
       })
       // 拉起腾讯地图导航
       Button('拉起腾讯地图-ByWant').onClick((event: ClickEvent) => {
         this.mapNavigator.openTencentMapByWant('我的位置', 39.908823, 116.397470, '天安门', 39.915156, 116.403694)
       })
       // 拉起百度地图导航
       Button('拉起百度地图-ByWant').onClick((event: ClickEvent) => {
         this.mapNavigator.openBaiduMapByWant('我的位置', 39.908823, 116.397470, '天安门', 39.915156, 116.403694)
       })
       // 拉起高德地图导航
       Button('拉起高德打车-ByWant').onClick((event: ClickEvent) => {
         this.mapNavigator.openAmapByWant('我的位置', 39.908823, 116.397470, '天安门', 39.915156, 116.403694)
       })

五、总结与最佳实践

  1. querySchemes 配置至关重要,否则 canOpenLink 失效。
  2. startAbility 与 openLink 方法各有优势
  • startAbility :可传递参数,可拉起鸿蒙应用/元服务
  • openLink:轻量、简单,适合第三方应用
  1. 统一未安装提示,提升用户体验。
  2. 百度地图在鸿蒙上 安装检测存在限制,直接拉起即可,异常捕获处理即可。

通过这种封装方式,业务逻辑只需关注 起点、终点,不必关心每个地图应用的调用差异,极大提高了开发效率与可维护性,以上示例代码和封装逻辑已在 真机上 测试通过,如有异常或适配问题,欢迎大家在 Issues 中提出,我们将持续优化并补充更多地图应用和导航参数的支持。如果大家喜欢或者对这个系列感兴趣欢迎大家在评论区交流讨论。

望一键三连!

六、代码仓库

README.md · ZhangHuiXin/MapNavigatorDemo - Gitee.com

在HarmonyOS Next中,可通过want参数调用地图应用。使用startAbility方法,指定地图应用的bundleNameabilityName,并在parameters中传入目的地坐标或地址信息。需提前在module.json5中声明所需权限,如ohos.permission.LOCATION。具体参数格式需参考对应地图厂商提供的鸿蒙SDK文档。

在HarmonyOS Next中,应用内拉起第三方地图应用(如腾讯、百度、高德地图)进行导航,主要通过HarmonyOS的Want隐式启动能力实现。核心步骤是构造一个符合目标地图应用约定的意图(Want),并启动对应的Ability。

以下是关键实现方法:

  1. 确认目标地图应用的支持情况:首先需在设备上安装对应的地图应用,并确认其支持通过HarmonyOS Want被拉起。通常主流地图应用会提供相关的协议或文档。

  2. 构造Want对象:这是最关键的一步。你需要根据各地图应用公开的URI格式action来构造Want,以传递目的地参数(如经纬度、地名)。

    • 基本参数:通常包括action(如"ohos.want.action.viewData")和uri(或entitiesparameters)。
    • URI示例格式(具体格式需查阅对应地图厂商的HarmonyOS适配文档或参考其Android协议进行类比):
      • 高德地图"location://com.amap.location?lat=39.904989&lon=116.405285&name=目的地"
      • 百度地图"bdapp://map/navi?destination=纬度,经度|地名"
      • 腾讯地图"qqmap://map/routeplan?type=drive&to=目的地&tocoord=纬度,经度"
    • 在Want的parameters中也可以传递键值对参数。
  3. 使用隐式Want启动:通过startAbility()方法,并设置Wantactionurientities等属性,系统会匹配并让用户选择已安装的、能处理该意图的地图应用。

    import { common, Want } from '@kit.AbilityKit';
    
    let wantInfo: Want = {
        action: 'ohos.want.action.viewData', // 常用查看数据的action
        // 示例:拉起高德地图导航到北京
        uri: 'location://com.amap.location?lat=39.904989&lon=116.405285&name=天安门',
        // 或使用parameters传递参数
        // parameters: {
        //     'lat': 39.904989,
        //     'lon': 116.405285,
        //     'name': '天安门'
        // }
    };
    let context = getContext(this) as common.UIAbilityContext;
    context.startAbility(wantInfo).then(() => {
        // 成功拉起
    }).catch((err) => {
        // 处理错误,如未安装对应应用
    });
    
  4. 处理未安装应用的情况:如果设备未安装目标地图应用,startAbility可能会失败。为了更好的用户体验,建议:

    • 在调用前,可以使用abilityManager.getAbilityList()查询设备上已安装的应用,判断是否存在能处理对应Want的应用。
    • 或者捕获启动失败的错误,引导用户跳转到AppGallery安装所需地图应用。

注意事项

  • 参数格式:各地图应用所需的URI或参数键值对格式可能不同,且可能随版本更新而变化。最准确的方式是查阅该地图应用为HarmonyOS Next提供的官方开发文档或接口说明
  • 权限:通常拉起导航不需要特殊权限,但如果你的应用需要获取用户当前位置作为起点,则需要申请相应的位置权限(ohos.permission.LOCATION)。
  • 多应用选择:当多个地图应用都能响应同一个Want时,系统会弹出选择器让用户选择。你可以通过设置Wantentities字段来更精确地匹配特定应用。

由于HarmonyOS Next处于快速发展阶段,建议在实际开发时,优先查询华为官方文档中关于Want和隐式启动的详细说明,并关注目标地图应用厂商是否发布了针对HarmonyOS Next的导航拉起规范。

回到顶部