【HarmonyOS Next】地图使用详解(一)
- 2025-03-11 广东
本文字数:7891 字
阅读完需:约 26 分钟
背景
这系列文章主要讲解鸿蒙地图的使用,当前可以免费使用,并提供了丰富的 SDK 给开发者去自定义控件开发。目前可以实现个性化显示地图、位置搜索和路径规划等功能,轻松完成地图构建工作。需要注意的是,现在测试只能使用实体手机去做调试,模拟器和预览器是没有办法做测试和使用的。
地图开发环境搭建
1. AGC 中创建项目
在 AGC 中新建项目,并复制 AGC 项目中的 Client ID 填写到工程中的 entry 模块的 module.json5 文件中,新增 metadata,配置 name 为 client_id,value 为 AGC 项目中的 Client ID。

{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
],
"extensionAbilities": [
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup",
"exported": false,
"metadata": [
{
"name": "ohos.extension.backup",
"resource": "$profile:backup_config"
}
],
}
],
"metadata": [
{
"name": "client_id",
"value": "6917564776665168777"
}
]
}
}
2.AGC 中开通地图服务
在 API 管理界面,打开地图服务

3.AGC 中创建 APP
在证书、APP ID 和 Profile 中,APP ID 中创建之前项目中的 App
4.在项目文件中生成密钥请求文件
这个密钥文件比较重要,务必妥善保存。



这里的 Alias 需要记住,后面需要用到

保存 csr 文件

查看生成的 csr 文件

5.AGC 项目中创建证书和设备
新建调试证书,并把证书下载到本地。


6.AGC 项目中创建 Profile
选择对应的调试证书,完成 Profile 的创建


7.把生成的证书和调试文件添加到项目结构中


8.确保当前 IDE 已经登陆了你的华为账号

地图组件(MapComponent)
示例代码使用 MVVM 架构来配置
1、MapComponent 组件初始化
提供了两个必填参数,mapOptions 和 mapCallback
项目初始化框架
import { MapViewModel } from '../ViewModels/MapViewModel';
import { MapComponent } from '@kit.MapKit';
@Entry
@ComponentV2
struct FirstPage {
@Local MapVM: MapViewModel = new MapViewModel();
aboutToAppear(): void {
this.MapVM.Init();
}
build() {
RelativeContainer() {
MapComponent({
mapOptions: this.MapVM.MapOption,
mapCallback: this.MapVM.MapCallBack
})
.width("100%")
.height("100%")
.id("Map")
}
.height('100%')
.width('100%')
}
}
VM 中的 MapOption 赋值
this.MapOption = {
//相机位置
position: {
target: {
latitude: this.LocationLatitude,
longitude: this.LocationLongitude
},
zoom: 10
},
//地图类型
mapType: mapCommon.MapType.STANDARD,
//地图最小图层,默认值为2
minZoom: 2,
//地图最大图层,默认值为20
maxZoom: 20,
//是否支持旋转手势
rotateGesturesEnabled: true,
//是否支持滑动手势
scrollGesturesEnabled: true,
//是否支持缩放手势
zoomGesturesEnabled: true,
//是否支持倾斜手势
tiltGesturesEnabled: true,
//是否展示缩放控件
zoomControlsEnabled: true,
//是否展示定位按钮
myLocationControlsEnabled: true,
//是否展示指南针控件
compassControlsEnabled: false,
//是否展示比例尺
scaleControlsEnabled: true,
//是否一直显示比例尺,只有比例尺启用时该参数才生效。
alwaysShowScaleEnabled: true
};
VM 中的 MapCallBack 赋值
this.MapCallBack = async (err, mapController) => {
if (!err) {
this.MapController = mapController;
//启用我的位置图层
mapController.setMyLocationEnabled(true);
//设置我的位置跟随设备移动
mapController.setMyLocationStyle({
displayType: mapCommon.MyLocationDisplayType.LOCATE
})
//启用我的位置按钮
mapController.setMyLocationControlsEnabled(true);
//地图监听时间管理器
this.MapEventManager = this.MapController.getEventManager();
}
}
权限申请(在 VM 中封装申请)
/**
* 所需要得权限
*/
MapPermissions: Permissions[] =
[
'ohos.permission.INTERNET',
'ohos.permission.LOCATION',
'ohos.permission.APPROXIMATELY_LOCATION'
]
/**
* 初始化方法
*/
public async Init() {
//识别权限是否赋予
if (!PermissionUtils.CheckPermissions(this.MapPermissions)) {
const perResult: boolean = await PermissionUtils.RequestPermissions(this.MapPermissions);
if (!perResult) {
return;
}
}
}
权限方法封装
import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';
/**
*权限封装类
*/
export class PermissionUtils {
/**
* 检查权限是否授权(完全授权)
* @param permissionsArr 权限集合
* @returns true:已经全部授权;false:没有全部授权
*/
public static CheckPermissions(permissionsArr: Permissions[]): boolean {
const atManager = abilityAccessCtrl.createAtManager();
//获取bundle信息
const bundleInfo =
bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
// 拿到当前应用的tokenID 标识
const tokenID = bundleInfo.appInfo.accessTokenId
//校验应用是否被授予权限
let result: boolean = true;
permissionsArr.forEach((x: Permissions, index: number) => {
if (!(atManager.checkAccessTokenSync(tokenID, x) === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)) {
result = false;
return;
}
})
return result;
}
/**
* 申请授权(首次弹窗申请)
* @param permissionList 权限集合
* @returns true:权限完全加载;false:有权限没有加载
*/
public static async RequestPermissions(permissionList: Permissions[]): Promise<boolean> {
// 程序访问控制管理
const atManager = abilityAccessCtrl.createAtManager();
// 拉起弹框请求用户授权
const grantStatus = await atManager.requestPermissionsFromUser(getContext(), permissionList)
// 获取请求权限的结果
const isAuth = grantStatus.authResults.every(v => v === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)
// 返回 Promise 授权结果
return isAuth ? Promise.resolve(true) : Promise.reject(false)
}
/**
* 打开系统设置的权限管理页面
*/
public static OpenPermissionSettingsPage() {
// 获取上下文
const context = getContext() as common.UIAbilityContext
// 获取包信息
const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
// 打开系统设置页
context.startAbility({
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
// 按照包名打开对应设置页
pushParams: bundleInfo.name
}
})
}
}
项目加载时,先进行 VM 的初始化
aboutToAppear(): void {
this.MapVM.Init();
}
界面初始化展示

2、地图初始化类(MapOptions)
属于 mapCommon 类
常用属性
在 VM 类中,需要在类初始化的时候把 MapOption 初始化。
constructor() {
this.MapOption = {
//相机位置
position: {
target: {
latitude: this.LocationLatitude,
longitude: this.LocationLongitude
},
zoom: 10
},
//地图类型
mapType: mapCommon.MapType.STANDARD,
//地图最小图层,默认值为2
minZoom: 2,
//地图最大图层,默认值为20
maxZoom: 20,
//是否支持旋转手势
rotateGesturesEnabled: true,
//是否支持滑动手势
scrollGesturesEnabled: true,
//是否支持缩放手势
zoomGesturesEnabled: true,
//是否支持倾斜手势
tiltGesturesEnabled: true,
//是否展示缩放控件
zoomControlsEnabled: true,
//是否展示定位按钮
myLocationControlsEnabled: true,
//是否展示指南针控件
compassControlsEnabled: false,
//是否展示比例尺
scaleControlsEnabled: true,
//是否一直显示比例尺,只有比例尺启用时该参数才生效。
alwaysShowScaleEnabled: true
};
this.MapCallBack = async (err, mapController) => {
if (!err) {
this.MapController = mapController;
//启用我的位置图层
mapController.setMyLocationEnabled(true);
//设置我的位置跟随设备移动
mapController.setMyLocationStyle({
displayType: mapCommon.MyLocationDisplayType.LOCATE
})
//启用我的位置按钮
mapController.setMyLocationControlsEnabled(true);
//地图监听时间管理器
this.MapEventManager = this.MapController.getEventManager();
}
}
}
3、获取手机用户当前位置
通过 geoLocationManager 的 getCurrentLocation 方法,获取用户的坐标经纬度,然后封装成更新用户定位的方法,在初始化的时候调用,就可以实现手机打开后会直接更新到用户的位置
/**
* 更新用户定位
*/
public async UpdateLocation() {
// 获取用户位置坐标
let location: geoLocationManager.Location = await geoLocationManager.getCurrentLocation();
this.LocationLongitude = location.longitude;
this.LocationLatitude = location.latitude;
}
完整代码
Page
import { MapViewModel } from '../ViewModels/MapViewModel';
import { MapComponent } from '@kit.MapKit';
@Entry
@ComponentV2
struct FirstPage {
@Local MapVM: MapViewModel = new MapViewModel();
aboutToAppear(): void {
this.MapVM.Init();
}
build() {
RelativeContainer() {
MapComponent({
mapOptions: this.MapVM.MapOption,
mapCallback: this.MapVM.MapCallBack
})
.width("100%")
.height("100%")
.id("Map")
}
.height('100%')
.width('100%')
}
}
ViewModel
import { mapCommon, map, sceneMap } from '@kit.MapKit';
import { AsyncCallback } from '@kit.BasicServicesKit';
import { common, Permissions } from '@kit.AbilityKit';
import { PermissionUtils } from '../Utils/PermissionUtils';
import geoLocationManager from '@ohos.geoLocationManager';
import { image } from '@kit.ImageKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { MapMarkImage } from '../Utils/MapMarkImage';
@ObservedV2
export class MapViewModel {
/**
* 地图初始化参数设置
*/
MapOption?: mapCommon.MapOptions
/**
* 地图回调方法
*/
MapCallBack?: AsyncCallback<map.MapComponentController>
/**
* 地图控制器
*/
MapController?: map.MapComponentController
/**
* 地图监听管理器
*/
MapEventManager?: map.MapEventManager
/**
* 地图标记集合
*/
Markers: map.Marker[] = []
/**
* 所需要得权限
*/
MapPermissions: Permissions[] =
[
'ohos.permission.INTERNET',
'ohos.permission.LOCATION',
'ohos.permission.APPROXIMATELY_LOCATION'
]
/**
* 当前位置的维度
*/
public LocationLatitude: number = 39.9;
/**
* 当前位置的经度
*/
public LocationLongitude: number = 116.4;
/**
* 初始化方法
*/
public async Init() {
//识别权限是否赋予
if (!PermissionUtils.CheckPermissions(this.MapPermissions)) {
const perResult: boolean = await PermissionUtils.RequestPermissions(this.MapPermissions);
if (!perResult) {
return;
}
}
//标点初始化
MapMarkImage.Init(getContext(this));
}
constructor() {
this.UpdateLocation();
this.MapOption = {
//相机位置
position: {
target: {
latitude: this.LocationLatitude,
longitude: this.LocationLongitude
},
zoom: 10
},
//地图类型
mapType: mapCommon.MapType.STANDARD,
//地图最小图层,默认值为2
minZoom: 2,
//地图最大图层,默认值为20
maxZoom: 20,
//是否支持旋转手势
rotateGesturesEnabled: true,
//是否支持滑动手势
scrollGesturesEnabled: true,
//是否支持缩放手势
zoomGesturesEnabled: true,
//是否支持倾斜手势
tiltGesturesEnabled: true,
//是否展示缩放控件
zoomControlsEnabled: true,
//是否展示定位按钮
myLocationControlsEnabled: true,
//是否展示指南针控件
compassControlsEnabled: false,
//是否展示比例尺
scaleControlsEnabled: true,
//是否一直显示比例尺,只有比例尺启用时该参数才生效。
alwaysShowScaleEnabled: true
};
this.MapCallBack = async (err, mapController) => {
if (!err) {
this.MapController = mapController;
//启用我的位置图层
mapController.setMyLocationEnabled(true);
//设置我的位置跟随设备移动
mapController.setMyLocationStyle({
displayType: mapCommon.MyLocationDisplayType.LOCATE
})
//启用我的位置按钮
mapController.setMyLocationControlsEnabled(true);
//地图监听时间管理器
this.MapEventManager = this.MapController.getEventManager();
}
}
}
/**
* 更新用户定位
*/
public async UpdateLocation() {
// 获取用户位置坐标
let location: geoLocationManager.Location = await geoLocationManager.getCurrentLocation();
this.LocationLongitude = location.longitude;
this.LocationLatitude = location.latitude;
}
/**
* 移动视图相机
* @param latitude 维度
* @param longitude 经度
*/
public async MoveCamera(latitude: number, longitude: number) {
if (this.MapController) {
//将视图移动到标点位置
let nwPosition = map.newCameraPosition({
target: {
latitude: latitude,
longitude: longitude
},
zoom: 10
})
// 以动画方式移动地图相机
this.MapController.animateCamera(nwPosition, 1000);
}
}
}
PermissionUtils
import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';
/**
*权限封装类
*/
export class PermissionUtils {
/**
* 检查权限是否授权(完全授权)
* @param permissionsArr 权限集合
* @returns true:已经全部授权;false:没有全部授权
*/
public static CheckPermissions(permissionsArr: Permissions[]): boolean {
const atManager = abilityAccessCtrl.createAtManager();
//获取bundle信息
const bundleInfo =
bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
// 拿到当前应用的tokenID 标识
const tokenID = bundleInfo.appInfo.accessTokenId
//校验应用是否被授予权限
let result: boolean = true;
permissionsArr.forEach((x: Permissions, index: number) => {
if (!(atManager.checkAccessTokenSync(tokenID, x) === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)) {
result = false;
return;
}
})
return result;
}
/**
* 申请授权(首次弹窗申请)
* @param permissionList 权限集合
* @returns true:权限完全加载;false:有权限没有加载
*/
public static async RequestPermissions(permissionList: Permissions[]): Promise<boolean> {
// 程序访问控制管理
const atManager = abilityAccessCtrl.createAtManager();
// 拉起弹框请求用户授权
const grantStatus = await atManager.requestPermissionsFromUser(getContext(), permissionList)
// 获取请求权限的结果
const isAuth = grantStatus.authResults.every(v => v === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED)
// 返回 Promise 授权结果
return isAuth ? Promise.resolve(true) : Promise.reject(false)
}
/**
* 打开系统设置的权限管理页面
*/
public static OpenPermissionSettingsPage() {
// 获取上下文
const context = getContext() as common.UIAbilityContext
// 获取包信息
const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION)
// 打开系统设置页
context.startAbility({
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry',
parameters: {
// 按照包名打开对应设置页
pushParams: bundleInfo.name
}
})
}
}
总结
上面的流程是地图组件的初始化的个人理解流程,看完这篇希望可以在地图开发上给你提供帮助。
版权声明: 本文为 InfoQ 作者【oneal】的原创文章。
原文链接:【http://xie.infoq.cn/article/d69729f103f911f51ffff4f68】。未经作者许可,禁止转载。

oneal
鸿蒙砌砖工程师 2024-12-24 加入
还未添加个人简介
评论