写点什么

【HarmonyOS Next】地图使用详解(一)

作者:oneal
  • 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@ComponentV2struct 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@ComponentV2struct 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';
@ObservedV2export 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 } }) }}
复制代码

总结

上面的流程是地图组件的初始化的个人理解流程,看完这篇希望可以在地图开发上给你提供帮助。

发布于: 2025-03-11阅读数: 2
用户头像

oneal

关注

鸿蒙砌砖工程师 2024-12-24 加入

还未添加个人简介

评论

发布
暂无评论
【HarmonyOS Next】地图使用详解(一)_HarmonyOS NEXT_oneal_InfoQ写作社区