欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net

在这里插入图片描述

📋 前言

地图功能已经成为许多应用的核心特性。无论是出行导航、位置分享、还是周边服务搜索,地图都扮演着重要角色。react-native-maps 是 React Native 生态中最流行的地图组件库,提供了丰富的地图渲染和交互功能,让开发者能够快速集成地图能力。

🎯 库简介

基本信息

  • 库名称: react-native-maps
  • 版本信息:
    • 1.10.4 + @react-native-ohos/react-native-maps: 支持 RN 0.72 版本
    • 1.24.4 + @react-native-ohos/react-native-maps: 支持 RN 0.77 版本
  • 官方仓库: https://github.com/react-native-oh-library/react-native-maps
  • 主要功能:
    • 🗺️ 地图显示与交互
    • 📍 标记点(Marker)支持
    • 🔵 圆形、多边形、折线覆盖物
    • 🎯 地图相机控制
    • 📱 支持 HarmonyOS 华为地图服务

为什么选择 react-native-maps?

特性 原生地图开发 react-native-maps
跨平台一致性 ❌ 需分别开发 ✅ 统一 API
开发效率 ⚠️ 较低 ✅ 快速集成
维护成本 ⚠️ 较高 ✅ 社区维护
HarmonyOS 支持 ❌ 需自行适配 ✅ 官方适配版本
TypeScript 支持 ⚠️ 需自行定义 ✅ 完整类型定义

支持的组件

组件 说明 HarmonyOS 支持
MapView 地图容器组件
Marker 标记点
Circle 圆形覆盖物
Polygon 多边形覆盖物
Polyline 折线覆盖物
Callout 信息弹窗
UrlTile 瓦片图层
WMSTile WMS 瓦片图层
Overlay 图片覆盖物
Geojson GeoJSON 支持
Cluster 标记聚合

兼容性验证

在以下环境验证通过:

  • RNOH: 0.72.90; SDK: HarmonyOS 6.0.0 Release SDK; IDE: DevEco Studio 6.0.2; ROM: 6.0.0

⚠️ 重要提示:华为地图服务申请

🔴 注意:使用 react-native-maps 的 HarmonyOS 版本需要先开通华为地图服务(Map Kit)。未开通地图服务将导致地图无法正常显示!

为什么需要开通地图服务?

华为地图服务(Map Kit)是云端服务,需要通过华为服务器进行鉴权:

应用 → 请求地图数据 → 华为服务器 → 验证身份 → 返回地图数据

这与 Google Maps 需要 Google Cloud Console 配置 API Key 是类似的原理。

版本差异说明

根据您的开发环境版本,配置流程有所不同:

环境版本 配置复杂度 是否需要 Client ID 是否需要公钥指纹
HarmonyOS 5.0.2+ 且 DevEco Studio 6.0.0+ ✅ 简单 ❌ 不需要 ❌ 不需要
HarmonyOS 5.0.2 以下 或 DevEco Studio 6.0.0 以下 ⚠️ 复杂 ✅ 需要 ✅ 需要

🚀 方案一:HarmonyOS 5.0.2+ 且 DevEco Studio 6.0.0+(推荐使用,我用的也是这个)

适用条件:HarmonyOS SDK 5.0.2(14) 及以上版本,且 DevEco Studio 6.0.0 Beta5 及以上版本

第一步:注册华为开发者账号

  1. 访问 华为开发者联盟
  2. 点击"注册"按钮,完成账号注册
  3. 完成实名认证(个人或企业)

第二步:通过 DevEco Studio 自动开通地图服务

🎉 优势:DevEco Studio 6.0.0+ 支持一键开通地图服务,无需手动配置 Client ID 和公钥指纹!

1. 配置签名

  1. 打开 DevEco Studio
  2. 选择 File → Project Structure
  3. 进入 Project → Signing Configs 页面
  4. 勾选 Automatically generate signature
  5. 登录华为开发者账号
  6. 点击 OK 完成签名配置

2. 开通地图服务

如果bundle name不能申请,说名称已经存在了,就换一个不存在的。我改完以后,app.json5自动同步了bundle名称。

  1. Signing Configs 页面
  2. 点击 Enable open capabilities 按钮
  3. 在弹出的服务列表中,勾选 Map Kit
  4. 点击 OK 完成配置
    在这里插入图片描述

✅ DevEco Studio 会自动完成以下操作:

  • 在 AppGallery Connect 创建/关联项目和应用
  • 开通地图服务权限
  • 配置签名信息
  • 生成并下载 Profile 文件

第三步:安装依赖

在项目根目录执行以下命令:
在这里插入图片描述

# RN 0.72 版本
npm install @react-native-ohos/react-native-maps@1.10.4-rc.1

# RN 0.77 版本
npm install @react-native-ohos/react-native-maps@1.24.4-rc.1

第四步:配置权限

1. 在 module.json5 中添加权限

打开 harmony/entry/src/main/module.json5,在 requestPermissions 中添加:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.APPROXIMATELY_LOCATION",
        "reason": "$string:location_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.LOCATION",
        "reason": "$string:location_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

2. 添加权限说明字符串

打开 harmony/entry/src/main/resources/base/element/string.json,添加:

{
  "string": [
    {
      "name": "internet_reason",
      "value": "用于加载地图数据"
    },
    {
      "name": "location_reason",
      "value": "用于显示您的位置和导航"
    }
  ]
}

第五步:原生代码配置

1. 添加依赖

打开 harmony/entry/oh-package.json5,添加依赖:

{
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90",
    "@react-native-ohos/react-native-maps": "file:../../node_modules/@react-native-ohos/react-native-maps/harmony/maps.har"
  }
}

2. 同步依赖

点击 DevEco Studio 右上角的 Sync Now 按钮,或执行:

cd harmony/entry
ohpm install

3. 配置 CMakeLists.txt

打开 harmony/entry/src/main/cpp/CMakeLists.txt,添加 Maps 模块:

project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# 添加 Maps 模块
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-maps/src/main/cpp" ./maps)

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# 链接 Maps 库
+ target_link_libraries(rnoh_app PUBLIC rnoh_maps)

4. 修改 PackageProvider.cpp

打开 harmony/entry/src/main/cpp/PackageProvider.cpp,添加:

#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
+ #include "MapsPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        + std::make_shared<MapsPackage>(ctx),
    };
}

5. 在 ArkTS 侧引入组件

打开 harmony/entry/src/main/ets/pages/Index.ets(或 LoadBundle.ets),添加:

import {
  AIRMap,
  AIR_MAP_TYPE,
  AIRMapMarker,
  AIR_MAP_MARKER_TYPE,
  AIRMapPolyline,
  AIR_MAP_POLYLINE_TYPE,
  AIRMapPolygon,
  AIR_MAP_POLYGON_TYPE,
  AIRMapCircle,
  AIR_MAP_CIRCLE_TYPE,
  AIRMapCallout,
  AIR_MAP_CALLOUT_TYPE,
  AIRMapCalloutSubview,
  AIR_MAP_CALLOUT_SUBVIEW_TYPE,
  Geojson,
  AIR_GEOJSON_TYPE,
  AIRMapUrlTile,
  AIR_URLTILE_TYPE,
  AIRMapWMSTile,
  AIR_WMSTILE_TYPE,
  AIRMapOverlay,
  AIR_OVERLAY_TYPE,
  AIRMapCluster,
  AIR_MAP_CLUSTER_TYPE,
} from "@react-native-ohos/react-native-maps"

@Builder
export function buildCustomRNComponent(ctx: ComponentBuilderContext) {
  if (ctx.componentName === AIR_MAP_TYPE) {
    AIRMap({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_MARKER_TYPE) {
    AIRMapMarker({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_POLYLINE_TYPE) {
    AIRMapPolyline({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_POLYGON_TYPE) {
    AIRMapPolygon({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_CIRCLE_TYPE) {
    AIRMapCircle({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_CALLOUT_TYPE) {
    AIRMapCallout({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_CALLOUT_SUBVIEW_TYPE) {
    AIRMapCalloutSubview({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_GEOJSON_TYPE) {
    Geojson({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_URLTILE_TYPE) {
    AIRMapUrlTile({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_WMSTILE_TYPE) {
    AIRMapWMSTile({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_OVERLAY_TYPE) {
    AIRMapOverlay({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_CLUSTER_TYPE) {
    AIRMapCluster({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  }
}

const arkTsComponentNames: Array<string> = [
  AIR_MAP_TYPE,
  AIR_MAP_MARKER_TYPE,
  AIR_MAP_POLYLINE_TYPE,
  AIR_MAP_POLYGON_TYPE,
  AIR_MAP_CIRCLE_TYPE,
  AIR_MAP_CALLOUT_TYPE,
  AIR_MAP_CALLOUT_SUBVIEW_TYPE,
  AIR_GEOJSON_TYPE,
  AIR_URLTILE_TYPE,
  AIR_WMSTILE_TYPE,
  AIR_OVERLAY_TYPE,
  AIR_MAP_CLUSTER_TYPE,
]

6. 引入 MapsPackage

打开 harmony/entry/src/main/ets/RNPackagesFactory.ts,添加:

import type { RNPackageContext, RNPackage } from 'rnoh/ts';
import { MapsPackage } from '@react-native-ohos/react-native-maps/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new MapsPackage(ctx),
  ];
}

第六步:运行项目

  1. 连接 HarmonyOS 设备或启动模拟器
  2. 点击 DevEco Studio 的运行按钮
  3. 地图应该正常显示

⚠️ 方案二:HarmonyOS 5.0.2 以下 或 DevEco Studio 6.0.0 以下(不推荐,要适配RN0.7x,还是用最新版)

适用条件:HarmonyOS SDK 5.0.2(14) 以下版本,或 DevEco Studio 6.0.0 Beta5 以下版本

⚠️ 注意:此方案需要手动配置 Client ID 和公钥指纹,流程较为复杂。建议升级到新版本以简化配置。

第一步:注册华为开发者账号

  1. 访问 华为开发者联盟
  2. 点击"注册"按钮,完成账号注册
  3. 完成实名认证(个人或企业)

第二步:在 AppGallery Connect 创建项目和应用

1. 登录 AppGallery Connect

访问 AppGallery Connect 并登录

2. 创建项目

  1. 点击"我的项目"
  2. 点击"创建项目"
  3. 填写项目名称,选择项目类型
  4. 点击"确定"完成创建

3. 创建应用

  1. 在项目详情页,点击"添加应用"
  2. 选择应用平台:HarmonyOS
  3. 填写应用信息:
    • 应用名称:您的应用名称
    • 应用包名:必须与项目 app.json5 中的 bundleName 一致
    • 应用类型:选择"APP"
  4. 点击"确定"完成创建

⚠️ 重要:应用包名必须与 HarmonyOS 项目中的 bundleName 完全一致!

第三步:开通地图服务

  1. 登录 AppGallery Connect
  2. 进入项目详情页
  3. 选择 开发与服务 → API 管理
  4. 找到 地图服务 开关,打开开关
  5. 确认已开启"地图服务"

第四步:配置签名证书

🔴 关键步骤:开通地图服务后,必须重新申请 Profile 文件!

1. 生成签名证书

在 DevEco Studio 中:

  1. 选择 Build → Generate Key and CSR
  2. 填写证书信息:
    • Key Alias: 密钥别名(如:key0)
    • Password: 密钥密码
    • Validity: 有效期(建议 25 年)
    • First and Last Name: 姓名
    • Organization: 组织名称
  3. 选择保存路径,生成 .p12 文件和 .csr 文件

2. 申请调试证书

  1. 登录 AppGallery Connect
  2. 进入 用户与访问 → 证书管理
  3. 点击"新增证书"
  4. 选择证书类型:调试证书
  5. 上传 .csr 文件
  6. 点击"提交",下载 .cer 证书文件

3. 申请 Profile 文件

  1. 进入 应用信息 → HAP Provision Profile 管理
  2. 点击"添加"
  3. 选择类型:调试 Profile
  4. 选择已申请的调试证书
  5. 点击"提交",下载 .p7b Profile 文件

⚠️ 重要:开通地图服务后,必须重新申请 Profile 文件,否则地图无法正常显示!

第五步:获取并配置 Client ID

1. 获取 Client ID

  1. 在 AppGallery Connect 项目详情页
  2. 进入 项目设置 → 常规
  3. 找到应用的 Client ID(客户端 ID)
  4. 复制此 ID

2. 配置 Client ID

打开 harmony/entry/src/main/module.json5,在 metadata 中添加 Client ID:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "metadata": [
      {
        "name": "client_id",
        "value": "110168601"  // 替换为您在 AGC 获取的 Client ID
      }
    ]
  }
}

第六步:配置应用包名

打开 harmony/AppScope/app.json5,确保 bundleName 与 AppGallery Connect 中创建的应用包名一致:

{
  "app": {
    "bundleName": "com.example.yourapp",  // 必须与 AGC 中的应用包名一致
    "vendor": "example",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:app_icon",
    "label": "$string:app_name"
  }
}

第七步:配置签名

打开 harmony/build-profile.json5,配置签名信息:

{
  "app": {
    "signingConfigs": [
      {
        "name": "default",
        "type": "HarmonyOS",
        "material": {
          "certpath": "E:/certs/yourapp.cer",           // 调试证书路径
          "storePassword": "0000001F46D5FEE28...",      // 密钥库密码
          "keyAlias": "key0",                           // 密钥别名
          "keyPassword": "0000001F2B30EA30...",         // 密钥密码
          "profile": "E:/certs/yourappDebug.p7b",       // Profile 文件路径
          "signAlg": "SHA256withECDSA",
          "storeFile": "E:/certs/yourapp.p12"           // 密钥库文件路径
        }
      }
    ]
  }
}

第八步:安装依赖

在项目根目录执行以下命令:

# RN 0.72 版本
npm install @react-native-ohos/react-native-maps@1.10.4-rc.1

# RN 0.77 版本
npm install @react-native-ohos/react-native-maps@1.24.4-rc.1

第九步:配置权限

1. 在 module.json5 中添加权限

打开 harmony/entry/src/main/module.json5,在 requestPermissions 中添加:

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.APPROXIMATELY_LOCATION",
        "reason": "$string:location_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.LOCATION",
        "reason": "$string:location_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

2. 添加权限说明字符串

打开 harmony/entry/src/main/resources/base/element/string.json,添加:

{
  "string": [
    {
      "name": "internet_reason",
      "value": "用于加载地图数据"
    },
    {
      "name": "location_reason",
      "value": "用于显示您的位置和导航"
    }
  ]
}

第十步:原生代码配置

1. 添加依赖

打开 harmony/entry/oh-package.json5,添加依赖:

{
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90",
    "@react-native-ohos/react-native-maps": "file:../../node_modules/@react-native-ohos/react-native-maps/harmony/maps.har"
  }
}

2. 同步依赖

点击 DevEco Studio 右上角的 Sync Now 按钮,或执行:

cd harmony/entry
ohpm install

3. 配置 CMakeLists.txt

打开 harmony/entry/src/main/cpp/CMakeLists.txt,添加 Maps 模块:

project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# 添加 Maps 模块
add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-maps/src/main/cpp" ./maps)

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# 链接 Maps 库
target_link_libraries(rnoh_app PUBLIC rnoh_maps)

4. 修改 PackageProvider.cpp

打开 harmony/entry/src/main/cpp/PackageProvider.cpp,添加:

#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
#include "MapsPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        std::make_shared<MapsPackage>(ctx),
    };
}

5. 在 ArkTS 侧引入组件

打开 harmony/entry/src/main/ets/pages/Index.ets(或 LoadBundle.ets),添加:

import {
  AIRMap,
  AIR_MAP_TYPE,
  AIRMapMarker,
  AIR_MAP_MARKER_TYPE,
  AIRMapPolyline,
  AIR_MAP_POLYLINE_TYPE,
  AIRMapPolygon,
  AIR_MAP_POLYGON_TYPE,
  AIRMapCircle,
  AIR_MAP_CIRCLE_TYPE,
  AIRMapCallout,
  AIR_MAP_CALLOUT_TYPE,
  AIRMapCalloutSubview,
  AIR_MAP_CALLOUT_SUBVIEW_TYPE,
  Geojson,
  AIR_GEOJSON_TYPE,
  AIRMapUrlTile,
  AIR_URLTILE_TYPE,
  AIRMapWMSTile,
  AIR_WMSTILE_TYPE,
  AIRMapOverlay,
  AIR_OVERLAY_TYPE,
  AIRMapCluster,
  AIR_MAP_CLUSTER_TYPE,
} from "@react-native-ohos/react-native-maps"

@Builder
export function buildCustomRNComponent(ctx: ComponentBuilderContext) {
  if (ctx.componentName === AIR_MAP_TYPE) {
    AIRMap({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_MARKER_TYPE) {
    AIRMapMarker({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_POLYLINE_TYPE) {
    AIRMapPolyline({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_POLYGON_TYPE) {
    AIRMapPolygon({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_CIRCLE_TYPE) {
    AIRMapCircle({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_CALLOUT_TYPE) {
    AIRMapCallout({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_CALLOUT_SUBVIEW_TYPE) {
    AIRMapCalloutSubview({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_GEOJSON_TYPE) {
    Geojson({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_URLTILE_TYPE) {
    AIRMapUrlTile({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_WMSTILE_TYPE) {
    AIRMapWMSTile({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_OVERLAY_TYPE) {
    AIRMapOverlay({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  } else if (ctx.componentName === AIR_MAP_CLUSTER_TYPE) {
    AIRMapCluster({
      ctx: ctx.rnComponentContext,
      tag: ctx.tag,
    })
  }
}

const arkTsComponentNames: Array<string> = [
  AIR_MAP_TYPE,
  AIR_MAP_MARKER_TYPE,
  AIR_MAP_POLYLINE_TYPE,
  AIR_MAP_POLYGON_TYPE,
  AIR_MAP_CIRCLE_TYPE,
  AIR_MAP_CALLOUT_TYPE,
  AIR_MAP_CALLOUT_SUBVIEW_TYPE,
  AIR_GEOJSON_TYPE,
  AIR_URLTILE_TYPE,
  AIR_WMSTILE_TYPE,
  AIR_OVERLAY_TYPE,
  AIR_MAP_CLUSTER_TYPE,
]

6. 引入 MapsPackage

打开 harmony/entry/src/main/ets/RNPackagesFactory.ts,添加:

import type { RNPackageContext, RNPackage } from 'rnoh/ts';
import { MapsPackage } from '@react-native-ohos/react-native-maps/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new MapsPackage(ctx),
  ];
}

第十一步:运行项目

  1. 连接 HarmonyOS 设备或启动模拟器
  2. 点击 DevEco Studio 的运行按钮
  3. 地图应该正常显示

📖 API 详解

🔷 MapView - 地图容器

MapView 是地图的核心容器组件,用于显示地图和控制地图状态。

import MapView from 'react-native-maps';

<MapView
  style={{ flex: 1 }}
  initialRegion={{
    latitude: 39.9042,
    longitude: 116.4074,
    latitudeDelta: 0.0922,
    longitudeDelta: 0.0421,
  }}
/>

主要属性

属性 类型 必填 说明 HarmonyOS 支持
initialRegion Region 初始显示区域
region Region 当前显示区域(受控)
camera Camera 相机配置
showsUserLocation boolean 显示用户位置
showsCompass boolean 显示指南针
showsScale boolean 显示比例尺
zoomEnabled boolean 启用缩放
scrollEnabled boolean 启用滚动
rotateEnabled boolean 启用旋转
mapType string 地图类型

Region 类型

interface Region {
  latitude: number;      // 纬度
  longitude: number;     // 经度
  latitudeDelta: number; // 纬度跨度
  longitudeDelta: number; // 经度跨度
}

事件回调

事件 说明 HarmonyOS 支持
onRegionChange 区域变化时触发
onRegionChangeComplete 区域变化完成时触发
onPress 点击地图时触发
onLongPress 长按地图时触发
onMarkerPress 点击标记时触发

🔷 Marker - 标记点

Marker 用于在地图上标注位置。

import MapView, { Marker } from 'react-native-maps';

<MapView style={{ flex: 1 }}>
  <Marker
    coordinate={{
      latitude: 39.9042,
      longitude: 116.4074,
    }}
    title="北京"
    description="中国首都"
  />
</MapView>

主要属性

属性 类型 必填 说明 HarmonyOS 支持
coordinate LatLng 标记坐标
title string 标题
description string 描述
image ImageSource 自定义图标
opacity number 透明度
draggable boolean 可拖拽
anchor Point 锚点

自定义标记图标

<Marker
  coordinate={{ latitude: 39.9042, longitude: 116.4074 }}
  image={require('./assets/marker.png')}
/>

🔷 Circle - 圆形覆盖物

Circle 用于在地图上绘制圆形区域。

import MapView, { Circle } from 'react-native-maps';

<MapView style={{ flex: 1 }}>
  <Circle
    center={{
      latitude: 39.9042,
      longitude: 116.4074,
    }}
    radius={1000}
    fillColor="rgba(255, 0, 0, 0.3)"
    strokeColor="rgba(255, 0, 0, 1)"
    strokeWidth={2}
  />
</MapView>

主要属性

属性 类型 必填 说明 HarmonyOS 支持
center LatLng 圆心坐标
radius number 半径(米)
fillColor string 填充颜色
strokeColor string 边框颜色
strokeWidth number 边框宽度

🔷 Polygon - 多边形覆盖物

Polygon 用于在地图上绘制多边形区域。

import MapView, { Polygon } from 'react-native-maps';

<MapView style={{ flex: 1 }}>
  <Polygon
    coordinates={[
      { latitude: 39.91, longitude: 116.40 },
      { latitude: 39.90, longitude: 116.41 },
      { latitude: 39.89, longitude: 116.40 },
      { latitude: 39.90, longitude: 116.39 },
    ]}
    fillColor="rgba(0, 200, 0, 0.5)"
    strokeColor="rgba(0, 200, 0, 1)"
    strokeWidth={2}
  />
</MapView>

主要属性

属性 类型 必填 说明 HarmonyOS 支持
coordinates LatLng[] 顶点坐标数组
fillColor string 填充颜色
strokeColor string 边框颜色
strokeWidth number 边框宽度
holes LatLng[][] 空洞区域

🔷 Polyline - 折线覆盖物

Polyline 用于在地图上绘制路线或路径。

import MapView, { Polyline } from 'react-native-maps';

<MapView style={{ flex: 1 }}>
  <Polyline
    coordinates={[
      { latitude: 39.91, longitude: 116.40 },
      { latitude: 39.90, longitude: 116.41 },
      { latitude: 39.89, longitude: 116.42 },
    ]}
    strokeColor="#FF0000"
    strokeWidth={3}
    lineDashPattern={[5, 2, 3, 2]}
  />
</MapView>

主要属性

属性 类型 必填 说明 HarmonyOS 支持
coordinates LatLng[] 端点坐标数组
strokeColor string 线条颜色
strokeWidth number 线条宽度
lineDashPattern number[] 虚线模式
geodesic boolean 测地线

📱 完整示例

在这里插入图片描述

import React, { useState, useRef } from 'react';
import {
  View,
  Text,
  StyleSheet,
  TouchableOpacity,
  Alert,
} from 'react-native';
import MapView, {
  Marker,
  PROVIDER_DEFAULT,
} from '@react-native-ohos/react-native-maps';

const LATITUDE_DELTA = 0.01;
const LONGITUDE_DELTA = 0.01;

const DEFAULT_LOCATION = {
  latitude: 39.9042,
  longitude: 116.4074,
};

interface Coordinate {
  latitude: number;
  longitude: number;
}

const MapDemo = () => {
  const mapRef = useRef<MapView>(null);
  const [region, setRegion] = useState<Coordinate>(DEFAULT_LOCATION);
  const [markers, setMarkers] = useState<Coordinate[]>([]);

  const handleMapPress = (e: any) => {
    const coordinate = e.nativeEvent?.coordinate;
    if (coordinate) {
      setMarkers([...markers, coordinate]);
    }
  };

  const handleMarkerPress = (index: number) => {
    const marker = markers[index];
    if (marker) {
      Alert.alert(
        '标记点',
        `位置 ${index + 1}\n纬度: ${marker.latitude.toFixed(4)}\n经度: ${marker.longitude.toFixed(4)}`
      );
    }
  };

  const handleRegionChangeComplete = (newRegion: any) => {
    if (newRegion && typeof newRegion.latitude === 'number' && typeof newRegion.longitude === 'number') {
      setRegion({
        latitude: newRegion.latitude,
        longitude: newRegion.longitude,
      });
    }
  };

  const clearMarkers = () => {
    setMarkers([]);
  };

  return (
    <View style={styles.container}>
      <MapView
        ref={mapRef}
        style={styles.map}
        provider={PROVIDER_DEFAULT}
        initialRegion={{
          ...DEFAULT_LOCATION,
          latitudeDelta: 0.1,
          longitudeDelta: 0.1,
        }}
        onRegionChangeComplete={handleRegionChangeComplete}
        onPress={handleMapPress}
        showsUserLocation
        showsCompass
        showsScale
        showsMyLocationButton
        zoomEnabled
        scrollEnabled
        rotateEnabled
      >
        {markers.map((marker, index) => (
          <Marker
            key={index}
            coordinate={marker}
            title={`标记 ${index + 1}`}
            description="点击查看详情"
            onPress={() => handleMarkerPress(index)}
          />
        ))}
      </MapView>

      <View style={styles.topPanel}>
        <View style={styles.infoBox}>
          <Text style={styles.infoText}>点击地图添加标记点</Text>
          <Text style={styles.infoText}>当前标记数: {markers.length}</Text>
        </View>
        <TouchableOpacity style={styles.clearButton} onPress={clearMarkers}>
          <Text style={styles.clearButtonText}>清除标记</Text>
        </TouchableOpacity>
      </View>

      <View style={styles.coordinateBox}>
        <Text style={styles.coordinateText}>
          纬度: {region?.latitude?.toFixed(4) ?? 'N/A'}
        </Text>
        <Text style={styles.coordinateText}>
          经度: {region?.longitude?.toFixed(4) ?? 'N/A'}
        </Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  map: {
    flex: 1,
  },
  topPanel: {
    position: 'absolute',
    top: 20,
    left: 20,
    right: 20,
    backgroundColor: 'rgba(255, 255, 255, 0.95)',
    borderRadius: 12,
    padding: 12,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.25,
    shadowRadius: 4,
    elevation: 5,
  },
  infoBox: {
    marginBottom: 8,
  },
  infoText: {
    fontSize: 14,
    color: '#333',
    marginBottom: 2,
  },
  clearButton: {
    backgroundColor: '#2196F3',
    paddingVertical: 10,
    borderRadius: 8,
    alignItems: 'center',
  },
  clearButtonText: {
    color: '#fff',
    fontSize: 14,
    fontWeight: '600',
  },
  coordinateBox: {
    position: 'absolute',
    bottom: 120,
    left: 20,
    backgroundColor: 'rgba(0, 0, 0, 0.7)',
    borderRadius: 8,
    padding: 12,
  },
  coordinateText: {
    color: '#fff',
    fontSize: 12,
    fontFamily: 'monospace',
  },
});

export default MapDemo;

❓ 常见问题

1. 地图无法显示(白屏)

问题:运行应用后地图显示为空白。

解决方案

  1. ✅ 确认已在 AppGallery Connect 开通地图服务
  2. ✅ 确认 Client ID 配置正确(仅旧版本需要)
  3. ✅ 确认应用包名与 AGC 中一致
  4. ✅ 确认签名配置正确(使用开通地图服务后重新申请的 Profile)
  5. ✅ 确认网络连接正常

2. 地图显示"鉴权失败"

问题:地图显示鉴权失败错误。

解决方案

  1. 检查 Client ID 是否正确配置在 module.json5 中(仅旧版本需要)
  2. 确认签名证书指纹已在 AGC 中配置(仅旧版本需要)
  3. 确认 Profile 文件是在开通地图服务后重新申请的

3. 定位权限申请失败

问题:申请定位权限时失败。

解决方案

  1. 确认 module.json5 中已声明 LOCATIONAPPROXIMATELY_LOCATION 权限
  2. 确认 string.json 中已添加权限说明
  3. 检查设备是否开启了定位服务

4. 标记点不显示

问题:添加的 Marker 不显示。

解决方案

  1. 检查坐标是否在可视区域内
  2. 检查 Marker 的 coordinate 属性是否正确
  3. 确认 MapView 组件已正确渲染

📚 参考资料


✅ 总结

react-native-maps 是一个功能强大的地图组件库,在 HarmonyOS 平台上需要配合华为地图服务(Map Kit)使用。

版本选择建议

您的环境 推荐方案
HarmonyOS 5.0.2+ 且 DevEco Studio 6.0.0+ ✅ 方案一:自动配置,简单快捷
其他版本 ⚠️ 方案二:手动配置,流程较多

关键步骤总结

方案一(新版本)

  1. DevEco Studio 自动签名
  2. Enable open capabilities → 勾选 Map Kit
  3. 完成!

方案二(旧版本)

  1. AppGallery Connect 创建项目和应用
  2. 开通地图服务
  3. 生成签名证书
  4. 申请调试证书和 Profile
  5. 获取并配置 Client ID
  6. 配置签名信息

关键提醒:使用地图功能前,务必先开通地图服务!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐