背景
这系列文章主要讲解鸿蒙地图的使用,当前可以免费使用,并提供了丰富的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
属性名称 | 属性类型 | 属性备注 | 是否必填 |
---|---|---|---|
mapOptions | mapCommon.MapOptions | 初始化参数,提供了地图类型、相机位置、地图边界等属性 | 是 |
mapCallback | AsyncCallback<map.MapComponentController> | 地图主要功能类map.MapComponentController的回调函数,提供了地图各种操作的API | 是 |
- 项目初始化框架
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类
- 常用属性
名称 | 类型 | 可选 | 说明 |
---|---|---|---|
mapType | MapType | 是 | 地图类型,默认值为MapType.STANDARD,异常值按默认值处理。 |
position | CameraPosition | 否 | 地图相机位置。 |
bounds | LatLngBounds | 是 | 地图展示边界,异常值根据无边界处理。说明西南角纬度不能大于东北角纬度。 |
minZoom | number | 是 | 地图最小图层,有效范围:[2, 20],默认值为2,异常值按默认值处理。如果设置的最小缩放级别小于2,minZoom会取2。 |
maxZoom | number | 是 | 地图最大图层,有效范围:[2, 20],默认值为20,异常值按默认值处理。如果设置的最大缩放级别大于20,maxZoom会取20。 |
rotateGesturesEnabled | boolean | 是 | 是否支持旋转手势,默认值为true,异常值按默认值处理。true:支持false:不支持 |
scrollGesturesEnabled | boolean | 是 | 是否支持滑动手势,默认值为true,异常值按默认值处理。true:支持false:不支持 |
zoomGesturesEnabled | boolean | 是 | 是否支持缩放手势,默认值为true,异常值按默认值处理。true:支持false:不支持 |
tiltGesturesEnabled | boolean | 是 | 是否支持倾斜手势,默认值为true,异常值按默认值处理。true:支持false:不支持 |
zoomControlsEnabled | boolean | 是 | 是否展示缩放控件,默认值为true,异常值按默认值处理。true:展示false:不展示 |
myLocationControlsEnabled | boolean | 是 | 是否展示定位按钮,默认值为false,异常值按默认值处理。true:展示false:不展示 |
compassControlsEnabled | boolean | 是 | 是否展示指南针控件,默认值为true,异常值按默认值处理。true:展示false:不展示 |
scaleControlsEnabled | boolean | 是 | 是否展示比例尺,默认值为false,异常值按默认值处理。true:展示false:不展示 |
padding | Padding | 是 | 设置地图和边界的距离,默认值为{ left: 0 , top: 0 , right: 0 , bottom: 0 }。 |
styleId | string | 是 | 自定义样式ID。 |
dayNightMode | DayNightMode | 是 | 日间夜间模式,默认值为DayNightMode.DAY(日间模式) |
alwaysShowScaleEnabled | boolean | 是 | 是否一直显示比例尺,只有比例尺启用时该参数才生效。 |
- 在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
}
})
}
}
总结
上面的流程是地图组件的初始化的个人理解流程,看完这篇希望可以在地图开发上给你提供帮助。