一、需求描述
????????实现一个车辆定位签到功能,获取当前车辆的实时定位,当车辆到达签到点1公里范围内时,可以进行签到,当大于1公里时,禁止签到。同时用户还可以手动刷新定位。
二、wx.getLocation
? ? ? ? 在之前的博客中,我写了一篇使用wx.onLocationChange进行定位签到的方法,见文章链接?uni-app 小程序获取实时定位和车辆签到(wx.onLocationChange方法),后面微信官方在2022年7月14日发布了一篇关于 “地理位置接口新增与相关流程调整” 的公告,见链接?地理位置接口新增与相关流程调整 | 微信开放社区,公告说自 2022 年 7 月 14 日起,开发者在使用下表地理位置相关接口时,需要提前在 app.json 中进行配置:
????????对于普通开发者,2022 年 7 月 14 日后发布的小程序,这8个API都需要在小程序管理后台完成权限申请,申请通过才能够在项目中使用,而我当时使用的wx.onLocationChange申请了多次一直被后台驳回,大概意思就是我这种定位签到应用场景,wx.onLocationChange支持的应用场景只支持下图所示的类目,而我的项目不符合wx.onLocationChange的应用场景,不需要实时监听用户的地理位置变化,所以没办法只能改为使用wx.getLocation方法。
?三、wx.getLocation使用流程
1、接口权限开通
????????在 “小程序管理后台 -「开发」-「开发管理」-「接口设置」” 中完成wx.getLocation API权限申请;
?2、manifest.json(或app.json)配置
? ? ? ? uni-app需要在manifest.json配置"requiredPrivateInfos" : [ "getLocation" ]
3、核心代码
<template>
<view class="container">
<view class="map-box">
<map id="myMap" :scale="14" :latitude="myLat" :longitude="myLon" :markers="markers" :circles="circles"></map>
<view class="local-icon" @click="authorization"></view>
</view>
<view class="btn-box">
<view class="cancel" v-if="info.workStatus == 1" @click="handleCancelTask">取消任务</view>
<view class="submit" @click="handleSubmitSign" v-if="isAuth">确认签到</view>
<view class="submit2" v-else>确认签到</view>
</view>
</view>
</template>
<script>
import { host } from '../../config/config.js'
export default {
name: 'sign',
data() {
return {
centerLon: 0, // 中心经度
centerLat: 0, // 中心纬度
circles: [], // 中心签到圈
radius: 0, // 签到半径
myLon: 0, // 当前定位经度
myLat:0, // 当前定位纬度
markers: [], // 当前定位标记点
distance: 99999,// 车辆到签到中心点距离
isAuth: false // 是否授权定位
}
},
methods: {
// 获取中心点坐标, 获取签到圈
getCoordinate() {
uni.request({
url: host + '/api/v1/mini/driver/getCoordinate',
method: 'GET',
header:{
'Content-Type' : 'application/json',
token : uni.getStorageSync("TOKEN")
},
data: {},
success: res => {
if(res.data.code === "0") {
console.log('中心的坐标', JSON.parse(JSON.stringify(res.data.data)))
this.centerLon = res.data.data.longitude;
this.centerLat = res.data.data.latitude;
this.radius = res.data.data.radius;
this.circles = [{
longitude: this.centerLon,
latitude: this.centerLat,
fillColor: "#FF2B431A",
color: "#FF0000",
radius: this.radius,
strokeWidth: 1
}]
} else {
uni.showToast({
title: res.data.msg,
icon: 'none',
duration: 2000
});
}
},
fail: () => {},
complete: () => {}
});
},
// 获取用户是否授权定位
authorization() {
wx.authorize({
scope: 'scope.userLocation',
success: (res) => {
console.log('获取授权成功');
this.isAuth = true;
uni.showLoading({
title: '定位中...'
});
wx.getLocation({
success: (res) => {
console.log("获取当前初始位置成功", res);
uni.hideLoading();
this.drawLocaltionPoint(res);
},
fail: (err) => {
console.log('获取当前初始位置失败', err);
uni.hideLoading();
}
})
},
fail: (err) => {
console.log('获取授权失败', err);
this.handleOpenSetting();
}
})
},
// 用户授权定位
handleOpenSetting() {
uni.showModal({
title: '温馨提示',
content: '获取权限失败,需要获取您的地理位置才能为您提供更好的服务!是否授权获取地理位置?',
success: (res) => {
if (res.confirm) {
wx.openSetting({
success: (res) => {
if (res.authSetting["scope.userLocation"]) { // 用户同意授权
console.log("用户同意授权");
this.authorization();
}
}
})
}
}
});
},
// 绘制定位点
drawLocaltionPoint(res) {
console.log('绘制定位点:', res.longitude, res.latitude);
this.myLon = res.longitude;
this.myLat = res.latitude;
this.markers = [{
id: 1,
longitude: this.myLon,
latitude: this.myLat,
iconPath: "../../static/img/record/point.png",
width: 25,
height: 25
}]
},
// 确认签到,点击按钮时重新获取用户地理位置
handleSubmitSign() {
uni.showLoading({
title: '定位中...'
});
wx.getLocation({
success: (res) => {
console.log("获取当前位置成功", res);
uni.hideLoading();
this.drawLocaltionPoint(res);
this.handleSign();
},
fail: (err) => {
console.log('获取当前位置失败', err);
uni.hideLoading();
this.handleSign();
}
})
},
// 签到
handleSign() {
this.distance = this.getDistance();
console.log('签到距离:', this.distance, ' 签到半径:', this.radius);
// 签到时进行判断,小于签到半径就签到成功,否则提示签到失败
if(this.distance <= this.radius) {
// todo 签到成功,调用签到接口
} else {
uni.showToast({
title: '签到失败,当前未在签到范围内,请稍后重试',
icon: 'none',
duration: 2500
});
}
},
// 获取当前位置距离签到点的距离
getDistance() {
let red1 = this.myLat * Math.PI / 180.0;
let red2 = this.centerLat * Math.PI / 180.0;
let a = red1 - red2;
let b = this.myLon * Math.PI / 180.0 - this.centerLon * Math.PI / 180.0;
let R = 6378137;
let distance = R * 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(red1) * Math.cos(red2) * Math.pow(Math.sin(b / 2), 2)));
return distance.toFixed(2) * 1;
}
},
onLoad(option) {
this.getCoordinate();
this.authorization();
}
}
</script>
<style lang="less" scoped>
.submit {
color: #FFF;
background: #FF2A41;
}
.submit2 {
color: #FFF;
background: #FF95A0;
}
</style>
四、说明
????????wx.getLocation是有调用频率限制的:
? ? ? ? 1. 在开发版或体验版中,30秒内调用getLocation,仅第一次有效,剩余返回fail。
? ? ? ? 2. 正式版中,为保证小程序正常运行同时不过度消耗用户电量,一定时间内(根据设备情况判断)调用getLocation,仅第一次会返回实时定位信息,剩余返回与第一次定位相同的信息。
? ? ? ? 不管是体验版还是正式版,我都进行了兼容处理,使页面提示更加的友好,符合用户的操作习惯,在体验版中,如果30秒内再次点击确认签到,wx.getLocation会返回fail,执行到上面代码的第142行里面去,然后调用handleSign,签到距离大于半径,进行提示“签到失败,当前未在签到范围内,请稍后重试”;如果是正式版,如果30秒内再次点击确认签到,wx.getLocation会返回上一次的执行结果,执行到上面代码的第136行里面去,然后调用handleSign,签到距离大于半径,进行提示“签到失败,当前未在签到范围内,请稍后重试”。所以,不管是正式版还是体验版,当用户频繁调用wx.getLocation,都会提示“签到失败,当前未在签到范围内,请稍后重试”,让用户以为是自己没有到达签到点的问题,当频繁调用频率一过,就会获得新的地理坐标,从而让用户体验更加的友好。
|