记录 uniapp 微信小程序获取定位流程

前言

记录 uniapp 微信小程序获取定位流程。

正文

之前做过一个基于 uniapp 的小程序,当时需要通过定位来获取用户的位置,从而来计算用户所需的运费。

检测 GPS 开关

在手机中,一般都会有一个 GPS 开关,比如我的小米手机是如下这样的:

这个开关决定了所有的应用是否能够使用定位,所以最开始,我们要检测这个开关是否开启了。

在 uniapp 中,有两个可以获取该开关的接口,分别是

第一个 API 里面提示说不推荐使用,所以我们用第二个。

PS:这两个 API 分别对应微信的 wx.getSystemInfowx.getSystemSetting 。在微信的 wx.getSystemInfo 文档中,有下面这段提示:

从基础库 2.20.1 开始,本接口停止维护,请使用 wx.getSystemSetting、wx.getAppAuthorizeSetting、wx.getDeviceInfo、wx.getWindowInfo、wx.getAppBaseInfo 代替

所以在 uniapp 这边我们用 uni.getSystemSetting 就行了,不过我看文档这个接口只有微信和 APP 支持,但是我在支付宝小程序的文档上发现了相似的接口 my.getSystemSetting,也有这个返回字段,就挺奇怪的😫。

相关代码如下:

1
const { locationEnabled } = uni.getSystemSetting()

检测 APP 是否有定位权限

在开启了 GPS 开关之后,我们还要检测微信是否有获取 GPS 的权限,在我的小米中是如下这样的:

这里的话我们要使用 uni.getAppAuthorizeSetting 接口。这个接口返回了 locationAuthorized ,它可以判断微信是否拥有定位权限,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
const { locationAuthorized } = uni.getAppAuthorizeSetting();
if (locationAuthorized === "authorized") {
// 微信已有定位权限
} else if (locationAuthorized === "denied") {
// 没有权限,需要引导用户
} else if (locationAuthorized === "not determined") {
// 未请求过该权限
} else if (locationAuthorized === "config error") {
// 只在 APP 端返回,主要是 APP 开发的时候没有授予相关权限问题。
// Android平台:表示没有授予 android.permission.ACCESS_COARSE_LOCATION 权限
// iOS平台:表示没有在 manifest.json -> App模块配置 中配置 Geolocation(定位) 模块
// 这里我们只针对微信小程序,所以可以不用管这个分支判断。
}

检测小程序是否有定位权限

在每个小程序中,都有可以设置是否开启定位权限,比如这里我们拿 BOSS 直聘的小程序,进入小程序后点击右上角的三个点,然后点击设置,出现如下页面:

这里的位置信息就两个选项,一个是关闭,一个是使用小程序时,所以我们要检测的就是小程序的这个选项是不是为“使用小程序时”,这里要使用 uni.getSetting 接口。这个接口返回了 authSetting 对象,这个对象包含了 scope 的信息,其中 scope.userLocation 就是我们需要的值,代码如下:

1
2
3
4
5
const { authSetting } = await uni.getSetting();

if (authSetting["scope.userLocation"]) {
// 小程序已获取定位权限
}

其他的 scope 值可以在上面的链接查看,每个 scope 都会对应某个接口,比如这里的 scope.userLocation ,它对应了 uni.getLocationuni.chooseLocation 接口,这两个接口就是最后我们获取位置信息的。

获取定位信息

在上面的权限全部都符合之后,我们就可以调用 uni.getLocation 来获取当前位置,如果想要别的位置的信息,可以配合 uni.chooseLocation 来实现。

使用 uni.getLocation 的代码如下:

1
2
3
4
5
6
const { 
latitude, // 维度
longitude // 经度
} = await uni.getLocation({
type: "gcj02",
});

这里我们用的是 gcj02 的坐标,它和 wgs84 的区别为(摘自 GPT ):

WGS-84(World Geodetic System 1984)

定义

  • WGS-84 是一种全球性的地理坐标系,由美国国防部制定,用于 GPS(全球定位系统)。
  • 它是一个国际通用的地理参考坐标系。

特点

  • 使用地球的椭球体模型描述位置。
  • 坐标值是全球统一的,没有针对任何国家或地区的调整。
  • 常用于国际场景,例如 GPS 设备、Google Earth 等。

应用场景

  • GPS 系统
  • 国际地图服务
  • 卫星导航与定位

GCJ-02(国测局坐标系)

定义

  • GCJ-02 是一种中国国家地理信息系统使用的地理坐标系,由中国国家测绘局开发。
  • 它在 WGS-84 基础上进行了加密处理。

特点

  • 引入了偏移算法,对 WGS-84 坐标进行一定的随机偏移,以实现加密效果。
  • 偏移算法是非线性的,且只有中国政府拥有其完整实现。
  • 偏移的目的是为了国家地理信息安全。
  • 在中国大陆范围内,WGS-84 坐标会偏离真实位置,偏移量随地理位置变化。

应用场景

  • 高德地图、腾讯地图、百度地图(部分基于 GCJ-02)等国内主要地图服务。
  • 适用于中国大陆范围的地理位置标注。

简单点讲就是国内就用 gcj02 ,国外就用 wgs84 。

如果不想使用当前的位置,而是手动定位一个位置的话,可以再调用 uni.chooseLocation ,代码如下:

1
2
3
4
5
6
7
const location = await uni.getLocation({
type: "gcj02",
});
const { latitude, longitude } = await uni.chooseLocation({
latitude: location.latitude,
longitude: location.longitude,
});

这在微信中会弹出一个微信自带的地图定位选取页面,如下:

缺失权限时的引导

如果用户缺失了某些权限,我们希望能够对用户进行引导,比如提示一段文字,或者如果可以的话,我们可以定位到相应的页面让用户开启某些权限。

缺失全局的 GPS 权限

这种我们只能弹出一个模态框来提示用户开启,模态框可以用 uni.showModal 来创建,相关代码如下:

1
2
3
4
5
6
7
8
9
uni.showModal({
title: "提示",
content: "请先打开 GPS 开关",
// 不显示取消按钮
showCancel: false,
success() {
// 做一些事情
},
});

这里也可以包在 Promise 中,用起来更加简洁:

1
2
3
4
5
6
7
8
9
10
11
await new Promise((resolve) => {
uni.showModal({
title: "提示",
content: "请先打开 GPS 开关",
// 不显示取消按钮
showCancel: false,
success() {
resolve();
},
});
})

微信缺失定位权限

这里我们可以使用 uni.showModal 配合 uni.openAppAuthorizeSetting 来让用户进入微信的设置页,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const confirm = await new Promise<boolean>((resolve, reject) => {
uni.showModal({
title: "提示",
content: "请将定位权限授权给微信",
confirmText: "前往设置",
success(res) {
// res.confirm 为 true 表示用户点了确定按钮
resolve(res.confirm);
},
fail(err) {
reject(err);
},
});
});
if (confirm) {
// 打开微信设置页
await uni.openAppAuthorizeSetting();
} else {
throw new Error("用户取消给与微信定位权限");
}

小程序缺失定位权限

这里我们可以使用 uni.showModal 配合 uni.openSetting 来让用户进入微信的设置页,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const confirm = await new Promise<boolean>((resolve, reject) => {
uni.showModal({
title: "提示",
content: "请将定位权限授权给微信",
confirmText: "前往设置",
success(res) {
// res.confirm 为 true 表示用户点了确定按钮
resolve(res.confirm);
},
fail(err) {
reject(err);
},
});
});
if (confirm) {
// 打开微信小程序设置页
const authSetting = await uni.openSetting();
// 这里可以根据 authSetting 来判断用户是否更新了相关的权限
} else {
throw new Error("用户取消给与小程序定位权限");
}

后记

当然每个项目需要的定位引导的需求都是不一样,比如我做的那个项目,在用户没有小程序权限时,会引导用户进入小程序的设置页,当从设置页退出的时候,会重新检测一次是否开启,如果没开启,会提示用户功能受限。

当然万变不离其宗,都是上面这些函数组合来组合去而已,熟悉这些步骤后只需要组合即可。