实现一个车辆定位签到功能,获取当前车辆的实时定位,当车辆到达签到点1公里范围内时,可以进行签到,当大于1公里时,禁止签到。同时用户还可以手动刷新定位。
在之前的博客中,我写了一篇使用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 API权限申请;
uni-app需要在manifest.json配置"requiredPrivateInfos" : [ "getLocation" ]
- <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,都会提示“签到失败,当前未在签到范围内,请稍后重试”,让用户以为是自己没有到达签到点的问题,当频繁调用频率一过,就会获得新的地理坐标,从而让用户体验更加的友好。