【前端探索】移动端H5获取地理位置的探索-程序员宅基地

技术标签: 前端  lbs  javascript  

提出问题

由于现在做的是强依赖于LBS的业务,在业务迭代的两年间,我们遇到了无数关于Web页面上获取用户位置定位的问题:

  1. 为什么我开了app的定位授权,但是H5上却获取不到用户位置信息?
  2. 为什么我关了app的定位授权,但是H5上还是获取到了用户位置信息?
  3. 为什么我进页面的时候会弹H5的位置授权弹窗,这个弹窗上的文字可以改吗?
  4. 我拒绝了H5的位置授权弹窗,要怎么重新弹出来授权弹窗?

多年的踩坑经验,总结成了下面的文章,下面来好好回答这些问题。

web端的定位方式分类

web端定位的方式,大概可以分为下面三类:

  • H5原生:navigator.geolocation
  • IP定位:用IP通过CGI接口获取定位
  • app定位:app获取定位再传给前端

基于这三类,我们可以采用下面方式这些来进行位置定位。

  1. navigator.geolocation

    H5的原生定位即navigator.geolocation。

  2. 腾讯地图前端定位组件

    腾讯地图前端定位组件是基于navigator.geolocation做了一些封装,如果原生定位失败,会降级用ip获取定位,同时也对获取的位置信息做了一些缓存的优化。

  3. 腾讯地图IP定位API

    通过CGI接口请求得到一个精确度比较低的位置信息。

  4. 微信的jssdk

    微信提供了jssdk,H5可以直接调用获取到位置信息。本质上是通过jsbridge传递app获取到位置信息。同理,我们也可以通过url参数等其他方式,来传递app获取到的位置信息。

在这里插入图片描述

下面来详细讲一下各种定位方式的调用,为了方便使用,各种定位方法是对下面这个LocationInterface接口的实现:

// 经纬度,等位置信息
export interface LocationData {
    
  lat: number,
  lng: number,
  type?: string,
}

// 定位flag,标记定位返回结果的类型
export enum LocationFlag {
    
  LocationSuccss = 1, // gps定位,给精确定位
  LocationIpSuccss = 2, // ip定位,给ip定位
  LocationFailed = 3, // 定位失败,给默认定位
}

// 返回的定位结果
export type LocationResult = {
    
  location: LocationData
  flag: LocationFlag
};

// 不同定位场景需要实现的接口
export interface LocationInterface {
    
  getLocation(options?: LocationOptions): Promise<LocationResult>;
}

1. navigator.geolocation

文档

https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/geolocation

使用方式

// H5原生的位置定位
export default class TencentMapApiLocation implements LocationInterface {
    
  getLocation(): Promise<LocationResult> {
    
    return new Promise((resolve, reject) => {
    
      function geoShowPosition(position) {
    
        if (position) {
    
          const location = {
     lat: position.coords.latitude, lng: position.coords.longitude };
          resolve({
     location, flag: LocationFlag.LocationSuccss });
        } else {
    
          reject();
        }
      }

      function geoShowError(error) {
    
        console.log(`getPosError:${
      error.code},${
      navigator.geolocation},${
      error.message}`);
        reject();
      }

      navigator.geolocation.getCurrentPosition(geoShowPosition, geoShowError);
    });
  }
}

优缺点

优点:

  • 不依赖外部接口和组件,位置信息准确。
  • 是否能获取到位置信息,与内嵌H5的app是否开启定位授权强相关,不会出现关闭定位授权,还能获取到定位的情况。

缺点:

  • 用户拒绝H5的授权弹窗后,需要用户重置系统权限才能获取到定位授权(重新开启app的授权设置也是没用的)。
  • H5的定位授权弹窗的是浏览器弹出的,文案不能自定义,没办法在这个弹窗向用户说明获取位置信息是用在什么地方。

适用场景

navigator.geolocation适用于大多数的获取定位的场景,而且其能否获取到定位,完全和用户是否给app开启位置授权有关,不用担心app在合规检查中出现问题。

回答上面的问题

问题1.为什么我开了app的定位授权,但是H5上却获取不到用户位置定位信息?

这是因为H5调用navigator.geolocation获取定位,除了需要app开启授权,还需要“浏览器的授权”。

问题3.为什么我进页面的时候会弹H5的定位授权弹窗,这个弹窗上的文字可以改吗?

不能。

问题4.我拒绝了H5的定位授权弹窗,要怎么再弹出来授权弹窗?

移动端浏览器的授权弹窗被用户拒绝后,需要“重置系统的定位设置”,才能重新弹出这个弹窗。

在iOS,重置定位权限的操作路径是:系统-通用-还原-还原位置和隐私。

2. 腾讯地图前端定位组件

文档

https://lbs.qq.com/webApi/component/componentGuide/componentGeolocation

使用方式

// 用腾讯地图sdk获取位置
export default class TencentMapLocation implements LocationInterface {
    
  public getLocation(options: LocationOptions): Promise<LocationResult> {
    
    return new Promise((resolve, reject) => {
    
      function geoShowPosition(location) {
    
        resolve({
     location, flag: LocationFlag.LocationSuccss });
      }

      function geoShowError() {
    
        reject();
      }


      loader('https://3gimg.qq.com/lightmap/components/geolocation/geolocation.min.js', () => {
    
      // eslint-disable-next-line no-undef
        const geolocation = new (window as any).qq.maps.Geolocation(
          tencentMapConfig.GEO_KEY,
          tencentMapConfig.GEO_REFERER,
        );
        const tencentMapOptions = {
    
          timeout: options.timeout,
        };
        geolocation.getLocation(geoShowPosition, geoShowError, tencentMapOptions);
      });
    });
  }
}

优缺点

优点

  • 腾讯地图前端定位组件是在原生H5定位的基础上做了一下优化,包括对获取的位置信息做了缓存,当原生H5定位失败的时候(用户未授权app权限或者拒绝了授权弹窗),会降级使用IP定位。
  • 和原生相比,获取信息的成功率会有一定的提高。

缺点

  • 用户是否能获取到位置信息,与是否开启app的定位授权不是强相关的。用户关闭了app的定位授权,仍然可以通过缓存和ip定位获取到位置信息。
  • 因为是优先使用H5原生定位,依然会弹出H5的定位授权弹窗。

适用场景

适用于对LBS依赖比较高的业务,在几种定位方式中,是首选的定位方式。

由于位置信息的获取,与用户是否授权app不强相关,在合规检查中可能会有风险。

回答上面的问题

问题2. 为什么我关了app的定位授权,但是H5上还是获取到了用户位置信息?

由于腾讯地图前端定位组件的优化,在用户关闭app定位授权的时候,依旧可以通过ip定位和缓存获取到位置信息。

由于我们的业务是嵌入在多个app中,最近经常需要配合app修改页面以通过合规检查,常用的修改方案是改用navigator.geolocation获取位置信息,或者直接用app获取的位置信息。

3. 微信sdk定位

文档

https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#36

使用方式

// 用微信sdk获取用户位置信息
export default class WechatSdkLocation implements LocationInterface {
    
  public getLocation(): Promise<LocationResult> {
    
    return new Promise((resolve, reject) => {
    
      configWx(['getLocation', 'openLocation'], []).then((wx) => {
    
        const tmp = {
    
          type: 'gcj02',
          success(res) {
    
            const location = {
    
              lat: parseFloat(res.latitude),
              lng: parseFloat(res.longitude),
            };
            resolve({
     location, flag: LocationFlag.LocationSuccss });
          },
          fail(error) {
    
            console.log('WechatSdkLocation', error);
            reject();
          },
        };

        wx.getLocation(tmp);
      })
        .catch((error) => {
    
          console.log('WechatSdkLocation', error);
          reject();
        });
    });
  }
}

优缺点

优点

  • 速度快,精确度高,成功率高
  • 不会有定位授权弹窗。
  • 是否能获取到位置信息,完全和app是否授权相关。

缺点

  • 没有,在微信webview直接用这个就好了。

适用场景

只有微信webview。

使用前需要注入微信js-sdk的配置信息。

在其他app中使用

这种定位方式的本质是直接使用app的定位能力,同理在其他的app中,我们也可以用类似的方式来获取位置信息。需要做的就是app和H5之间的消息传递,通过url参数、jsBridge等等,实现的方式很多。

4. 腾讯地图API的IP定位

文档

https://lbs.qq.com/service/webService/webServiceGuide/webServiceIp

使用方式

// 用腾讯地图api通过IP获取用户位置信息
export default class TencentMapApiLocation implements LocationInterface {
    
  public getLocation(): Promise<LocationResult> {
    
    return new Promise((resolve, reject) => {
    
      axios.get(`https://apis.map.qq.com/ws/location/v1/ip?key=${
      tencentMapConfig.GEO_KEY}`).then((res) => {
    
        const result = (res?.data?.result) || {
    };
        const location = (result?.location) || {
    };

        if (location) {
    
          resolve({
     location, flag: LocationFlag.LocationIpSuccss });
        } else {
    
          reject();
        }
      })
        .catch((error) => {
    
          console.log('TencentMapApiLocation', error);
          reject();
        });
    });
  }
}

优缺点

优点

  • 成功率高
  • 不需要H5授权弹窗,不需要app授权

缺点

  • 精确度低,一般都只有市级的经纬度
  • API接口的请求次数有限额,企业用户可以申请到300w次/日的配额。

适用场景

适用于对精确度要求不高的业务,IP定位一般在服务端使用,可以作为其他定位方法的降级方案,如果前端获取不到用户位置信息,服务端再用ip定位去拉取LBS业务的数据。

由于有限额,服务端可以对单个ip的位置信息做一下缓存优化,减少配额的使用。

封装一下

业务开发的时候,我们当然不希望去考虑上面那么多。我需要位置信息,调用组件接口,拿到位置信息,就可以了。

我们再来把上面提到的这些方案,做一下封装,对外只需要暴露一个getLocation接口。

/**
 * @module Location 位置定位
 * @description 定位工具,支持原生H5定位、腾讯地图定位、微信的sdk定位、ip定位
 */
class Location {
    
  public static locationFlag = LocationFlag;

  private static instance: Location = new Location();
  private static env;

  public static getInstance() {
    
    return this.instance;
  }

  /**
   * 获取定位信息
   * @exports getLocation
   * @param {object} options 定位参数
   * @param {number} options.timeout 定位超时时间
   * @param {boolean} options.useWxSdk  在微信环境下,是否优先使用微信Sdk定位
   * @param {boolean} options.useTencentMapApi 是否使用腾讯地图api进行IP定位
   * @param {boolean} options.useH5Geolocation 是否使用原生IP定位
   * @param {boolean} options.cache 是否缓存,推荐使用
   */
  public static getLocation(options: LocationOptions) {
    
  // 填充默认数据
  // ...

    return new Promise((resolve, reject) => {
    
      // 使用sessionStorage存储的位置信息
      // ...处理缓存的一些逻辑

      // 示例化不同场景的定位组件
      if (options.useWxSdk && Location.env.isWeixin) {
    
        this.getInstance().locationHandle = new WechatSdkLocation();
      } else if (options.useTencentMapApi) {
    
        this.getInstance().locationHandle = new TencentMapApiLocation();
      } else if (options.useH5Geolocation) {
    
        this.getInstance().locationHandle = new H5GeolocationLocation();
      }

      this.getInstance().locationHandle.getLocation(options).then((res) => {
    
        resolve(res);
        // 缓存位置信息
        // ...保存位置信息
      })
        .catch((error) => {
    
          reject(error);
        });
    });
  }

  private locationHandle: LocationInterface;

  constructor() {
    
    Location.env = initEnv();
    this.locationHandle = new TencentMapLocation();
  }
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_18738333/article/details/122189881

智能推荐

python实现在 Mac 10.9 远程桌面截屏抓取_mac 监控截屏-程序员宅基地

文章浏览阅读2k次。照样画葫芦,用python编写了一段小程序,可以使用ipad的web浏览器远程监控远端iMac主机界面(每秒截屏,非流控),与大家分享。1. 首先介绍一下需要下载的第三方工具:Flask,PyscreenshotFlask用来做web服务器,Pyscreenshot是用来截屏的。用pip install 分别安装即可2. 介绍程序文件架构如下,需要simplesvr_mac 监控截屏

centos7安装后一直出现pcieport 0000:00:1c.5的解决_dpc:error containment capabilities-程序员宅基地

文章浏览阅读4.7k次,点赞3次,收藏7次。安装完centos7后进入时一直不停出现pcieport 0000:00:1c.5字样,这个的具体原因尚不完全清楚,解决方法查到的都是一种,就是在/etc/default/grub中的GRUB_CMDLINE_LINUX的内容最后添加pci=nomsi或者pci=noaer或者pcie_aspm=off,这样的确可以,但是更新的步骤需要grub2-mkconfig -o /boot/efi/EFI..._dpc:error containment capabilities

目前看到的最好的RNN、LSTM、GRU博客:Understanding LSTM Networks_humans don鈥檛 start their thinking from scratch eve-程序员宅基地

文章浏览阅读735次。原文:http://colah.github.io/posts/2015-08-Understanding-LSTMs/Recurrent Neural NetworksHumans don’t start their thinking from scratch every second. As you read this essay, yo_humans don鈥檛 start their thinking from scratch every second.

maven/conf/settings.xml完整配置(3处)_apache-maven-3.9.2\conf\settings.xml-程序员宅基地

文章浏览阅读1.4k次。<?xml version="1.0" encoding="UTF-8"?><!--Licensed to the Apache Software Foundation (ASF) under oneor more contributor license agreements. See the NOTICE filedistributed with this work for additional informationregarding copyright ownersh._apache-maven-3.9.2\conf\settings.xml

基于Python的逆向工程:ELF文件_逆向工程 python-程序员宅基地

文章浏览阅读6.4k次。当解决复杂的逆向问题时,我们常使用radare2或IDA等成熟工具进行反汇编和调试。但有时也需要深入挖掘并了解它们是如何运作的。编写一些反汇编脚本对于自动化某些流程非常有用,并且可以形成自己的逆向工具链。至少,这是我现在正在尝试的事情。配置环境如标题所说的那样,你需要先安装Python 3。如果你无法确定是否安装了Python 3,可以运行如下命令:其中capstone是..._逆向工程 python

四种方法实现:找出数组中两个只出现一次的数字_一个数组中找出出现一次的2个数字-程序员宅基地

文章浏览阅读2.6k次。//先排序然后查找void FindNumsAppearOnce1(vector&lt;int&gt; data, int* num1, int *num2) { if (data.size() &lt; 2) return; sort(data.begin(), data.end()); vector&lt;int&gt; res; for (int i = 0; i &lt;..._一个数组中找出出现一次的2个数字

随便推点

开箱即用的 WebRTC 开发环境_xujianzhu webrtc开箱即用-程序员宅基地

文章浏览阅读333次。本文是 Piasy 原创,发表于 https://blog.piasy.com,请阅读原文支持原创 https://blog.piasy.com/2017/06/17/out-of-the-box-webrtc-dev-env/在刚刚落幕的 WWDC17 上,苹果为我们带来了一个不小的惊喜 —— 其浏览器内核WebKit将正式支持 WebRTC,而未来基于 WebKit 内核的苹果浏览器,比如m..._xujianzhu webrtc开箱即用

从ResNet101到ResNet50_resnet50 使用什么代替-程序员宅基地

文章浏览阅读3.3w次,点赞5次,收藏21次。一直用VGG训练,几天前想看下ResNet的效果如何,因为SSD源码中有python实现的ResNet网络结构实现代码,包含ResNet101和ResNet152,直接拿ResNet101来训练,GTX1060配置,batchsize竟然只降到2才跑的起来,果然一直收敛不了。看了下model_libs.py里面的实现代码:def ResNet101Body(net, from_layer, u_resnet50 使用什么代替

vivado ILA在线逻辑仪使用_vivado ila 下一触发沿-程序员宅基地

文章浏览阅读1.1w次,点赞12次,收藏131次。目录:1、在线逻辑分析仪简介2、HDL 实例化调试探针流程(实验-闪烁灯)3、Hardware Manager中观察调试信号4、网表插入调试探针流程(实验-闪烁灯)1、在线逻辑分析仪简介在线逻辑分析仪借用了传统逻辑分析仪的理念以及大部分的功能,并利用 FPGA 中的逻辑资源,将这些功能植入到 FPGA 的设计当中。一般地,在线逻辑分析仪的应用原理框图如下图所示:​ 待测设计(Design Under Test,DUT)就是用户逻辑,它和片内的在线逻辑分析仪都位于 FPGA中。在线逻辑分_vivado ila 下一触发沿

数据库索引的使用_db2数据库索引的使用-程序员宅基地

文章浏览阅读3.5k次。今天发现一个问题,问题大概是这样的,查询interface的信息,在本地使用本地的数据库访问没有问题,但是发布到服务器上以后访问速度就特别的忙,需要5分钟左右才能返回数据,这肯定是无法让人接受的,刚开始以为是服务器性能的问题,为了验证就把服务器上的数据库备份到本地,发现本地的速度也马上慢了下来,到底是什么问题的。看了一下查询interface的sql语句不禁吓了一跳: _db2数据库索引的使用

win7下mysql的安装_[root@gaojiao ~]# mysql -uroot error 1045 (28000):-程序员宅基地

文章浏览阅读3.1k次。一 , 当前mysql的最新版本是5.5.25a。到http://dev.mysql.com/downloads/mysql/下载mysql安装文件 。我们这里下载mysql-5.5.25a-win32.msi就可以了,下载完,直接点击安装。mysql有好几个版本,稍微了解下各个版本之间的区别:  MySQL Community Server :社区版本 不提供官方技术支持,是免费的_[root@gaojiao ~]# mysql -uroot error 1045 (28000): access denied for user 'r

PHP微信公众平台开发高级篇--群发接口_微信公众号根据标签群发接口支持数组传参吗-程序员宅基地

文章浏览阅读2.3k次。群发消息接口订阅号:每天一条的群发权限服务号:每月(自然月)4条群发权限实例&lt;?php/** * 群发接口 * PS:群发之前调用“预览接口”进行测试 * PS:通过第三方后台调用微信上传图片素材接口,获取图片url,如:{"url":"http:\/\/mmbiz.qpic.cn\/mmbiz_jpg\/BdxWN2kspVgJOFpRHJojlWmbl0pM..._微信公众号根据标签群发接口支持数组传参吗