前言
在即时通讯应用中,虽然发送位置信息不是核心功能,但在特定场景下,这个功能仍然非常有用。
本文将介绍如何在 uniapp 中实现位置信息的发送和展示,特别是在遇到地图层级问题时的解决方案。
以下内容均基于 uniapp 打包 App 端。
常规解决方案带来的问题
在 uniapp 中,通常使用map
组件来展示位置信息。但在打包为 App 端后,map
组件的层级问题会导致它无法随着聊天页面滚动。就像下图的情况:
在这个方案中,有在文档上看到描述说可以采用cover-view
去解决在滚动组件中map
层级过高的问题,但是经过折腾应该还是对 uniapp 的了解不够,没有解决层级过高的问题,因此换了下面的方案,也算是一个新的路子,希望能够对看到这篇文档的你有所帮助。
采用的方案
静态地图方案
静态地图
方案的核心其实是用一张地图的静态图片,替换了map
组件,图片在scoll-list
中不存在有层级过高的情况。而静态地图的产生则是调用了地图厂商所提供的静态地图 api,在调用生成的静态地图 api 时通过 url 传参的形式,将要展示的坐标经纬度传入,并且根据地图厂商规则去传入其他扩展参数,从而达到预期想要生成的静态地图效果。在本次我的实现中,我采用的是高德地图的 api,其他如百度,腾讯类似。
在高德静态地图 api 中,你可以除可传入经纬度坐标,也支持返回的图片宽高,这里我贴一下具体官方文档地址,供大家详细研究静态地图的使用:
功能实现
在接下来的篇幅里面,我将描述一下,我在实现位置消息发送,消息页面展示位置气泡,以及点击消息气泡展示详细位置的实现过程,以及遇到的问题。
在实现之前我们需要先在 uniApp 官网查看相关获取位置、选择位置、查看位置相关 api 的用法以及注意事项。
第一步:实现发送位置
1)在mainifest.json
文件下的App模块配置
中勾选Geolocation(定位)
在定位中你可以选择系统定位或者是高德、百度等厂商的系统定位,这里为了延时,就直接选择系统定位。
2)点击发送位置
获取系统定位授权
js
getLocation() {
uni.getLocation({
// type: 'wgs84',
type: 'gcj02',
success: (res) => {
this.location = { ...res };
console.log('当前位置:' + JSON.stringify(res));
},
fail: (err) => {
console.error(err);
// 这里可以处理权限被拒绝的情况
if (err.errMsg === 'getLocation:fail auth deny') {
// 引导用户打开权限设置
uni.showModal({
title: '提示',
content: '需要获取您的位置信息,请到设置中打开相关权限',
success: function (res) {
if (res.confirm) {
// 打开设置页面
uni.openSetting({
success: function (res) {
console.log(res.authSetting);
// res.authSetting = { "scope.userLocation": true } 表示已获得权限
},
});
}
},
});
}
},
});
},
3)授权后调用uni.chooseLocation
打开进入地图选择位置。
此 api 在调用拉起时会发现进入的页面并不会给你一个地图页面以及地点联想,这是因为还需要在App权限模块
中勾选Maps
而Maps
下有高德
、百度
、Google
三家,而我这里就选高德地图。
用户名的获取:
appkey_android key 的获取:
你需要在高德开放平台进行操作:
进入
高德控制台
→应用管理
→我的应用
→创建新应用
→添加Key
→选择服务平台
→获取SHA1码
在填写一系列指定信息后,即可成功创建。
如果你不知道SHA1码
的获取,在下文中也会提到对应 Mac 平台获取的方式。
appkey_ios key 的获取:
同安卓步骤只不过 iOS 不需要获取SHA1
码,仅需要填写Bundle ID
完成以上步骤后,重新打包自定义调试基座,确保将地图原生插件依赖进去。
重新调用uni.chooseLocation
后发现正常的展示了当下前位置,以及附近位置,选择完成后即可获取勾选的位置经纬度,位置名称,详细位置。
4) 发送位置消息
通过调用环信 uniApp api 发送位置消息来实现位置消息的发送
js
let option = {
chatType: 'singleChat',
type: 'loc',
to: 'username',
addr: this.location.address || '未知地址',
buildingName: this.location.name || '未知建筑名称',
lat: this.location.latitude,
lng: this.location.longitude,
};
let msg = WebIM.message.create(option);
conn
.send(msg)
.then((res) => {
console.log('Send message success', res);
})
.catch((e) => {
console.log('Send message fail', e);
});
该 api 相关文档:
环信-发送位置消息
第二步:渲染展示位置消息气泡
1) 创建高德地图 Web 平台 Key
静态地图的使用需要创建 Web 平台的 Key,该 Key 会在拼接静态地图 URL 时用到。
sh
https://restapi.amap.com/v3/staticmap?location=116.481485,39.990464&zoom=10&size=750*300&markers=mid,,A:116.481485,39.990464&key=<用户的key>
2) 拿经纬度置换可用的静态地图资源图片
通过解析发送或者接收到的位置消息中的经纬度,调用高德地图静态地图 api,从而获取对应坐标的静态地图。
msgBody 即为环信收发位置消息的消息体。
js
<img
class="map_image_container"
:src="`${AMAP_API_URL}${location}&zoom=10&size=400*200&scale=1&markers=mid,,A:${msgBody.lng},${msgBody.lat}&key=${AMAP_KEY}`"
/>
const AMAP_KEY = 'YOUR KEY';
const AMAP_API_URL = 'https://restapi.amap.com/v3/staticmap?';
const location = () => {
return `location=${this.msgBody.lng},${this.msgBody.lat}`;
},
3)展示位置名以及详细地址
js
<view class="location_msg_container" @click="openMap">
<u--text
:lines="1"
:text="msgBody.buildingName ? msgBody.buildingName : '未知建筑'"
></u--text>
<u--text
:lines="1"
:text="msgBody.addr ? msgBody.addr : '未知建筑'"
></u--text>
<img
class="map_image_container"
:src="`${AMAP_API_URL}${location}&zoom=10&size=400*200&scale=1&markers=mid,,A:${msgBody.lng},${msgBody.lat}&key=${AMAP_KEY}`"
/>
</view>
第三步:点击位置消息气泡跳转详细位置地图
js
openMap() {
uni.openLocation({
latitude: this.msgBody.lat,
longitude: this.msgBody.lng,
success: function () {
console.log('success');
},
});
相关效果展示
选择位置
点击选择位置
位置消息在消息列表的渲染效果
点击消息气泡查看详细位置
遇到的问题
问题一: getLocation
失败,不支持gcj02
坐标系。
js
{
"errMsg": "getLocation:fail not support gcj02",
"errCode": 18,
"code": 18
}
解决方式:进行了重新自定义调试基座。
问题二:地图依赖模块未勾选导致的问题。
解决方式:在mainifest.json
勾选地图依赖模块,并重新打包自定义调试基座。
问题三:获取安卓高德 key SHA1 指纹。
为了获取安卓高德 key SHA1 指纹的获取
以 Mac 举例
1. 下载并安装 Java JDK
如果你还没有安装 Java JDK,可以通过以下步骤安装:
- 打开 Oracle JDK 下载页面。
- 下载并安装适合你操作系统的 JDK。
2. 使用 keytool
工具获取 SHA1
keytool
工具是 Java 开发工具包 (JDK) 中的一个命令行工具,用于管理密钥和证书。
假设你的 APK 文件名为 your_app.apk
并且存放在 ~/Downloads
目录中。
- 打开终端(Terminal)。
- 运行以下命令来提取 APK 包中的证书信息:
sh
keytool -printcert -jarfile ~/Downloads/your_app.apk
该命令会显示 APK 包的证书详细信息,包括 SHA1 指纹。
示例输出
ruby
Signature:
Owner: CN=Your Name, OU=Your Organization, O=Your Company, L=Your City, ST=Your State, C=Your Country
Issuer: CN=Your Name, OU=Your Organization, O=Your Company, L=Your City, ST=Your State, C=Your Country
Serial number: 1234567890abcdef
Valid from: Mon Jul 01 00:00:00 PDT 2021 until: Wed Jun 26 00:00:00 PDT 2041
Certificate fingerprints:
SHA1: AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:00:AA:BB:CC
SHA256: AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:00:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99
Signature algorithm name: SHA256withRSA
Version: 3
从输出中找到 Certificate fingerprints
下的 SHA1
指纹,即为 APK 包的 SHA1 安全码。
注意事项
- 确保你使用的
keytool
是 Java JDK 中的工具,默认情况下,keytool
会安装在/usr/bin
目录中。 - 如果你在使用命令时遇到问题,可以尝试指定
keytool
的完整路径,例如/Library/Java/JavaVirtualMachines/jdk-15.0.1.jdk/Contents/Home/bin/keytool
,具体路径根据你安装的 JDK 版本而定。
通过上述步骤,你可以在 Mac 上获取 UniApp 云打包的 APK 包的 SHA1 安全码。
问题四:uni.chooseLocation
无法定位的问题。
该问题在安卓以及 iOS 均有发现,触发时机是在调用选择地图时高频复现,目前暂不确定是否是uni.chooseLocation
api 的异步调用而产生的 bug,在产生时,选择位置界面无法展示设备所在位置。
解决方案:
经测试该方案使该情况有所好转,但是偶尔还是能复现无法定位的情况,如果你知道原因以及解决方案可以评论区留言。
调用uni.chooseLocation
时将通过uni.getLocation
经纬度坐标一并传入,代码如下:
js
chooseLocationData() {
uni.chooseLocation({
//获取到的经纬度
latitude: this.location.latitude,
longitude: this.location.longitude,
success: (res) => {
console.log('位置名称:' + res.name);
console.log('详细地址:' + res.address);
console.log('纬度:' + res.latitude);
console.log('经度:' + res.longitude);
this.location = Object.assign(this.location, { ...res });
},
fail: (err) => {
console.error(err);
},
});
},
相关文档:
- 注册环信即时通讯IM:https://console.easemob.com/user/register
- 如实战中有任何问题,欢迎到IMGeek社区沟通讨论。