微信餐饮外卖配送小程序实现后台持续获取位置信息

最近开发一款微信餐饮外卖配送小程序,通过微信公众号和微信小程序实现菜单展示、线上订餐、预约点餐、外卖配送等功能。在开发过程中遇到一个需求,需要小程序持续定位,然后向后台发送实时位置,实时更新配送行程轨迹。

能力体验之"后台持续定位"接口的使用与踩坑之旅开始了。

一、申请开通相关接口

进入小程序后台管理页面找到开发-开发管理-接口设置,进行申请一般小程序都会申请开通 wx.getLocation 这个接口,然后我们会在第一次进入小程序时弹出让我们授权位置信息获取。但是为了实现微信出在后台时我们还需要额外申请其他几个接口,wx.onLocationChange用来监听实时地理位置变化事件;wx.startLocationUpdate 开启小程序进入前台时接受位置信息(如果开通前后台的话,一般会用的前后台的,建议开通,服务其他页面需求);wx.startLocationUpdateBackground 开启小程序进入前后台时均接受位置信息。

二、代码实现

权限配置:

json 复制代码
"permission" : { //小程序接口权限相关设置
            "scope.userLocation" : { //获取用户位置信息的权限,需要配置
                "desc" : "获取用户位置,用于配送轨迹实时更新"
            }
        },
        "requiredBackgroundModes" : [ "location" ], //申明需要后台运行的能力,类型为数组,目前支持audio后台音乐播放,location 后台定位
        "requiredPrivateInfos" : [ 
            "getLocation",
            "startLocationUpdate",
            "onLocationChange",
            "startLocationUpdateBackground"
        ], //在代码中使用申请的地理位置接口 需要在此配置,未申请接口需先申请开通

交互逻辑:

javascript 复制代码
// 获取微信授权弹框
  getWxLocation() {
   return new Promise((resolve, reject) => {
    console.log("定位中...");
    // 开启定位追踪
    // wx.startLocationUpdateBackground 后台获取位置接口
    wx.startLocationUpdateBackground({
     success: (res) => {
      console.log("开启定位追踪", res);
      // 监听位置变化
      wx.onLocationChange((data) => {
       console.log(data, '位置变化上传');
       //获取当前时间
       var currentTime = new Date().getTime();
       //获取上次执行的时间
       var oldTime = wx.getStorageSync("oldTime");
       //判断并且间隔时间
       // 五分钟执行一次
       if (currentTime - oldTime > 1000 * 60 * 5) {
        //缓存当前执行的时间
        wx.setStorageSync("oldTime", currentTime);
        // wx.showToast({title:'上传位置信息',icon:'none'})
        //将位置信息上传后台的自己的代码
        this.uploadLocation(data);
       }
      });
      resolve();
     },
     fail: (err) => {
      console.log("获取当前位置失败", err);
      reject();
     },
    });
   });
  },

  // 上传位置信息
  uploadLocation(data) {
   console.log("地址", data);
   locationUtils
    .getLocationRegeo(`${data.longitude},${data.latitude}`)
    .then((addressInfo) => {
      const addressComponent = addressInfo.addressComponent;//经纬度转码后信息
      let requestData = {} //参数需要上传后台的参数具体根据自己的业务写
      methodName(requestData).then((res) => {}); //上传接口
    });
  },

  // 停止获取位置信息
  stopUploadLocation() {
   wx.stopLocationUpdate({ success: (res) => { }, fail: (error) => { } });
   wx.offLocationChange();
  },

三、遇到的问题

wx.onLocationChange能否加个精度选项和上报频率选项?

用小程序测试了下wx.onLocationChange,坐那没动,console.log显示每隔一秒钟就会回调一次,相当于一秒钟回调一次。

建议:

可以加个位置变化精度选项,比如移动超过1米,再回调;

可以加个回调频率,比如可以选择1ms、1min、5min等;

如果有以上两个选项感觉是不是可以能更省电?客户也更愿意使用,否则客户会以费电抵触使用,导致该API实际用不起来;

四、思考&解决方案

微信团队在公众号里说"满足线路导航、路线记录等服务场景下,小程序需要长时间持续定位来提供服务",但在实际情况中是,小程序很难实现所谓的"长时间"(有时甚至不到5分钟)。这样就会导致我们记录的数据还没来得及上传就丢失了。当我发现这个问题,第一时间是抱怨为什么小程序销毁前不能给我们返回一个提醒。但思考后才理解:微信APP自身都不能确保"长时间"在后台运行,还怎么样保证小程序的"长时间"运行呢?(如被一些软件清理了)既然无法避免突发性关闭,又不宜频繁上传地点数据。那么,我们就只能用到缓存了!以实现类似断线重连的功能。

交互逻辑:

javascript 复制代码
var points_map = [ ]  // 实时绘制地图
var points_yun = [ ]  // 云开发需要的格式
var point

Page({

  data: {
    polyline: [{
      points: points_map,
      color: '#FFA500',
      width: 3
    }],
  },

  onLoad: function (options) {
    var that = this
    wx.getStorage({ 
      key: 'TimeStamp',
      success(res) { 
        console.log('有缓存')
        wx.getStorage({
          key: 'points_yun',
          success(res) { points_yun = res.data }
        })
        wx.showModal({
          content: '检测到您有一个未完成的配送记录!',
          cancelText: '不保存',
          cancelColor: '#DC143C',
          confirmText: '继续配送',
          confirmColor: '#228B22',
          success(k) {
            if (k.confirm) {
              console.log('用户点击确定-继续配送')
              that.setData({ TimeStamp: res.data })
              that.GoContinue()
            } else if (k.cancel) {
              console.log('用户点击取消-不保存')
              wx.removeStorage({ key: 'TimeStamp' }) //删缓存
              wx.removeStorage({ key: 'points_yun' })
              points_yun = []
            }
          }
        })
      }, fail(res) {
        console.log('无缓存')
        points_yun = []
      }
    })
  },


  Go: function () { // 开始配送(首次)
    var that = this
    wx.startLocationUpdateBackground({
      success(res) {
        var TimeStamp = (new Date()).valueOf()
        that.GetNowGeo()
        wx.setStorage({  //设置缓存(TimeStamp)
          key: "TimeStamp",
          data: TimeStamp
        })
      },
      fail() {
      // 这里弹窗引导用户授权使用地理位置
      }
    })
  },
  GoContinue: function () {  // 开始配送(再续)
    var that = this
    wx.startLocationUpdateBackground({
      success(res) {
        that.GetNowGeo()
      },
      fail() {
      // 这里弹窗引导用户授权使用地理位置
      }
    })
  },

  End: function () {
    var that = this
    wx.stopLocationUpdate()
    clearInterval(this.data.setInter)
    wx.showModal({
      title: '',
      content: '是否要上传数据?',
      success(res) {
        if (res.confirm) {
          that.updateGeo()
        }
      }
    })
  },

  GetNowGeo: function () {
    var that = this
    wx.onLocationChange(function (res) {
      point = { latitude: res.latitude, longitude: res.longitude }
    })
    this.data.setInter = setInterval(function () {
      if (points_map.length == 0) {  
        points_yun.push([])
      } 
      points_map.push(point); //画地图
      that.setData({
        'polyline[0].points': points_map
      })
      var n = [point.longitude, point.latitude]  // 云开发数据库需要的格式
      var r = points_yun.length - 1
      points_yun[r].push(n) 
      wx.setStorage({  // 设置缓存(路程数据)
        key: "points_yun",
        data: points_yun
      })
    }, 6000);
  },

  updateGeo: function () {
    var that = this
    wx.showLoading({
      title: '数据上传中',
    })
    db.collection('patrol_geo').add({  // 云开发上传
      data: {
        location: {
          type: 'MultiLineString',
          coordinates: points_yun
        }
      },
      success: res => {
        wx.showToast({
          title: '上传成功'
        })
        wx.removeStorage({ key: 'TimeStamp' }) // 清理缓存
        wx.removeStorage({ key: 'points_yun' })
      },
      fail: res => {
        wx.showToast({
          title: '上传失败,请重新操作!'
        })
        console.log(res)
      }
    })
  },

})
相关推荐
余生H4 分钟前
前端Python应用指南(三)Django vs Flask:哪种框架适合构建你的下一个Web应用?
前端·python·django
LUwantAC13 分钟前
CSS(四)display和float
前端·css
cwtlw16 分钟前
CSS学习记录20
前端·css·笔记·学习
界面开发小八哥21 分钟前
「Java EE开发指南」如何用MyEclipse构建一个Web项目?(一)
java·前端·ide·java-ee·myeclipse
米奇妙妙wuu36 分钟前
react使用sse流实现chat大模型问答,补充css样式
前端·css·react.js
傻小胖41 分钟前
React 生命周期完整指南
前端·react.js
梦境之冢1 小时前
axios 常见的content-type、responseType有哪些?
前端·javascript·http
racerun1 小时前
vue VueResource & axios
前端·javascript·vue.js
m0_548514772 小时前
前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现
java·前端·javascript
AndrewPerfect2 小时前
xss csrf怎么预防?
前端·xss·csrf