#HarmonyOS NEXT 体验官#HarmonyOS NEXT 地图服务中‘我的位置’功能全解析 原创 精华
关于作者
白晓明
宁夏图尔科技有限公司董事长兼CEO、坚果派联合创始人
华为HDE、润和软件HiHope社区专家、鸿蒙KOL、仓颉KOL
华为开发者学堂/51CTO学堂/CSDN学堂认证讲师
开放原子开源基金会2023开源贡献之星
OpenHarmony三方库贡献者
公众号:开源开发者新视界(openwatcher)
1 前言
“我的位置”功能在表象上或许给人以简单之感,但从专业角度深入剖析,其蕴含着极为可观的信息量与巨大潜力。此功能绝非仅仅局限于作为一个单纯显示用户当前所处地点的标识,而确切地说是连接用户与周边世界、实现个性化服务的关键纽带。无论是在日常出行导航领域,还是社交互动方面;无论是便捷的生活服务范畴,还是丰富的旅游体验场景,“我的位置”在各个领域的应用程序中均发挥着至关重要的专业作用。其背后所涉及的技术原理、丰富的应用场景以及对用户生活产生的深远影响,均值得专业人士进行深入探讨与研究。
2 不同类型应用中的使用场景
2.1 导航类应用
- 精准路线规划:用户输入目的地,应用以 “我的位置” 为依据生成最优路线并实时导航,随用户位置变化更新路线,确保高效准确抵达。例如,以为商务人士在陌生城市出差,通过导航应用的”我的位置“功能,快速找到前往会议地点的最佳路线,避免因不熟悉路况而导致迟到。
- 高效周边搜索:借助 “我的位置” 提供周边兴趣点搜索,如加油站、餐厅、酒店等,用户可根据需求检索并查看评价和距离信息。比如,一位自驾游爱好者在旅途中,通过导航应用搜索附近的加油站和特色餐厅,为行程提供便利。
- 实时交通信息呈现:结合实时交通信息,以 “我的位置” 为基点推荐最佳路线,遇拥堵自动规划避堵路线。例如,在上下班高峰期,上班族可以通过导航应用选择最顺畅的路线,减少通勤时间。
2.2 社交类应用
- 便捷位置分享:用户可通过 “我的位置” 分享位置给好友,也能查看好友位置,方便聚会约会安排。例如,一群朋友计划聚会,通过社交应用的位置分享功能,大家可以快速确定集合地点,提高聚会的效率。
- 附近的人推荐:比如,一位新到一个城市的年轻人,通过社交应用的“附近的人”功能,认识了一些志同道合的朋友,丰富了自己的社交生活。
- 个性化活动推荐:比如,一位音乐爱好者通过社交应用得知附近有一场自己喜欢乐队的演唱会,于是购买了门票,享受了一场精彩的音乐盛宴。
2.3 生活服务类应用
- 外卖精准配送:“我的位置” 确定送餐地址,用户可实时查看外卖小哥位置掌握配送进度。例如,一位忙碌的上班族在办公室点外卖,通过外卖应用的 “我的位置” 功能,确保外卖能够及时送到自己手中,不影响工作进度。
- 打车高效服务:确定上车地点,方便司机找到用户,用户也能查看司机位置了解行驶进度。比如,一位在机场的旅客,通过打车应用的 “我的位置” 功能,快速叫到车,顺利到达目的地。
- 快递智能查询:用于查询快递配送进度和当前位置,用户可随时了解快递是否送达附近以便收件。例如,一位网购爱好者通过快递应用的 “我的位置” 功能,实时跟踪自己的包裹,合理安排收件时间。
2.4 旅游类应用
- 个性化景点推荐:根据 “我的位置” 推荐附近景点和旅游线路,用户依兴趣选择参观丰富旅游体验。例如,一位游客在一个陌生的城市旅游,通过旅游应用的 “我的位置” 功能,发现了一些小众但非常有特色的景点,为旅行增添了不少乐趣。
- 智能导游服务:依据 “我的位置” 提供实时导游讲解和景点介绍,让用户深入了解历史文化背景知识。比如,一位历史爱好者在参观古迹时,通过旅游应用的智能导游功能,了解到了古迹的详细历史和文化内涵,加深了对历史的认识。
- 定制旅游攻略:根据 “我的位置” 为用户提供个性化旅游攻略,用户可依时间和兴趣制定专属计划。例如,一位自由行游客通过旅游应用的 “我的位置” 功能,制定了一份适合自己的旅游攻略,充分享受了旅行的乐趣。
当然,“我的位置” 这项功能的应用绝不仅仅局限于上文所提及的那些场景。实际上,它在更多的领域中同样能够发挥出至关重要的作用。比如在救援行动中,当人们遭遇紧急情况时,准确的 “我的位置” 信息可以迅速传递给救援人员,使得救援行动能够更加高效地展开。无论是在山区的迷路救援、海上的遇险救助,还是城市中的突发事件应对,“我的位置” 都能成为连接受困者与救援力量的关键纽带,为生命的救援争取宝贵的时间。它如同黑暗中的一盏明灯,为处于困境中的人们指引着希望的方向,让救援行动更加精准、及时、有效。
3 前期准备
3.1 配置Client ID
实际应用开发中,当你打算使用地图服务(Map Kit)时,首先需要在AppGallery Connect平台上创建相应的应用。在创建完成后,要准确地获取“项目设置 > 常规 > 应用”的Client ID,这里需要特别注意的是,一定不能获取项目的Client ID,两者有着明确的区分。获取正确的Client ID之后,接下来要在工程entry
模块的module.json5
文件中进行特定的操作。具体而言,就是要在这个文件中新增metadata
,将其配置为name
属性设置为client_id
,value
属性为获取到的Client ID值。
{
"module": {
...
"metadata": [
{
"name": "client_id",
"value": "xxxxxx"
}
]
}
}
3.2 开通地图服务
当完成Client ID的配置工作后,接下来还需要在AppGallery Connect平台该应用的“项目设置 > API管理”板块中打开地图服务开关。
3.3 添加公钥指纹
除了满足以上两个条件,还需要为应用添加公钥指纹,才能够确保地图服务(Map Kit)在应用中正常使用和发挥其强大的功能。
- 在DevEco Studio中使用自动签名,对应用进行签名。
- 在AppGallery Connect平台“项目设置 > 常规 > 应用”下的SHA256证书/公钥指纹中添加公钥指纹,勾选证书名称为
auto_debug_xxxx
的证书。
4 开发步骤
目前有两种方式可用于在地图上显示我的位置。推荐采用安全控件LocationButton
方式,此方式能够临时获取精准定位权限,无需进行权限弹框授权确认。另一种方式则是申请授权方式,该方式需要动态向用申请设备位置信息ohos.permission.LOCATION
和设备模糊位置信息ohos.permission.APPROXIMATELY_LOCATION
两个权限。
4.1 使用安全控件方式
安全控件是一种可融入应用页面,实现用户点击自动授权,而无需弹窗授权。相较于动态申请权限方式,安全控件可基于场景化授权,简化开发者和用户的操作,优点如下:
- 用户可掌握授权时机,授权范围最小化。
- 授权场景可匹配用户真实意图。
- 减少弹窗打扰。
- 开发者不必向应用市场申请权限,简化操作。
位置控件(LocationButton
)是目前系统提供的安全控件之一,该控件对应精准定位特权。应用集成位置控件后,用户点击该控件,无论应用是否申请过或者被授予精准定位权限,都会在本次前台期间获得精准定位的授权,可以调用位置服务获取精准定位。
使用LocationButton
可使用默认创建带有图标、文本、背景的位置按钮,也可以通过创建指定LicationButtonOptions
元素的位置按钮。
// 默认创建带有图标、文本、背景的位置按钮
LocationButton()
// 创建包含指定元素的位置按钮
LocationButton(option: LocationButtonOptions)
/**
* 指定元素的位置按钮
*/
declare interface LocationButtonOptions {
/**
* 设置位置按钮的图标风格。
* 不传入该参数表示没有图标,icon和text至少存在一个。
* LocationIconStyle.FULL_FILLED 填充样式图标
* LocationIconStyle.LINES 线条样式图标
*/
icon?: LocationIconStyle;
/**
* 设置位置按钮的文本描述。
* 不传入该参数表示没有文字描述,icon和text至少存在一个。
* LocationDescription.CURRENT_LOCATION 当前位置
* LocationDescription.ADD_LOCATION 添加位置
* LocationDescription.SELECT_LOCATION 选择位置
* LocationDescription.SHARE_LOCATION 共享位置
* LocationDescription.SEND_LOCATION 发送位置
* LocationDescription.LOCATING 定位
* LocationDescription.LOCATION 位置
* LocationDescription.SEND_CURRENT_LOCATION 发送实时位置
* LocationDescription.RELOCATION 重定位
* LocationDescription.PUNCH_IN 大卡定位
* LocationDescription.CURRENT_POSITION 所在位置
*/
text?: LocationDescription;
/**
* 设置位置按钮的背景样式。
* 不传入该参数,系统默认提供Capsule类型按钮。
* ButtonType.Capsule 胶囊型按钮
* ButtonType.Circle 圆形按钮
* ButtonType.Normal 普通按钮
*/
buttonType?: ButtonType;
}
LocationButton
组件不支持通用属性,仅支持安全控件通用属性,如设置安全控件上图标尺寸iconSize()
;设置安全控件上图标和文字分布的方向layoutDirection()
;设置绝对定位,设置安全控件的左上角相对于父容器左上角的便宜位置position()
;设置安全控件相对于自身布局位置的坐标偏移offset()
等,具体可参见安全控件通用属性。
LocationButton
组件不支持通用事件,仅支持onClick(event: (event: ClickEvent, result: LocationButtonOnClickResult) => void)
事件。
/**
* 位置权限的授权结果
*/
declare enum LocationButtonOnClickResult {
/**
* 位置按钮点击后授权成功。
*/
SUCCESS = 0,
/**
* 位置按钮点击后位置权限授权失败。
*/
TEMPORARY_AUTHORIZATION_FAILED = 1
}
使用安全控件LocationButton
可以在点击安全控件后,开启“我的位置”功能。
LocationButton()
.onClick((event: ClickEvent, result: LocationButtonOnClickResult) => {
console.log(`[LearningMapKit]位置权限的授权结果:${result}`);
this.myLocationBtnStatus = true;
// 启用我的位置图层
this.mapController?.setMyLocationEnabled(true);
// 启用我的位置按钮
this.mapController?.setMyLocationControlsEnabled(true);
})
4.2 使用用户授权方式
使用用户授权方式,需要先申请ohos.permission.LOCATION
和ohos.permission.APPROXIMATELY_LOCATION
权限。
步骤一:声明权限
{
"module": {
...
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" },
{
"name": "ohos.permission.LOCATION", // 允许应用在前台运行时获取位置信息
"reason": "$string:location_permission", // 在/resources/base/element/string.json中定义
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.APPROXIMATELY_LOCATION", // 允许应用获取设备模糊位置信息
"reason": "$string:location_permission",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
}
步骤二:动态申请权限
我在《HarmonyOS 应用程序访问控制探究》一文中对权限控制进行了详尽的阐述。你可以参考该篇文章来实现向用户动态申请权限的操作。授权后,还需要调用MapComponentController
地图操作类的setMyLocationEnabled()
方法启用我的位置图层,以及setMyLocationControlsEnabled()
方法启用我的位置按钮。
// 校验是否被授予定位权限
let flag: boolean = false;
for (const permission of this.locationPermissions) {
flag = false;
const grantStatus: abilityAccessCtrl.GrantStatus = PermissionUtil.checkPermissionGrant(permission);
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
// 启用我的位置图层
this.mapController?.setMyLocationEnabled(true);
// 启用我的位置按钮
this.mapController?.setMyLocationControlsEnabled(true);
flag = true;
}
}
if (!flag) { // 未授权,则弹出授权提示弹窗
const authResults: number[] = await PermissionUtil.reqPermissionFromUser(this.locationPermissions);
for (let i = 0; i < authResults.length; i++) {
if (authResults[i] === 0) {
// 启用我的位置图层
this.mapController?.setMyLocationEnabled(true);
}
}
}