Better

Ethan的博客,欢迎访问交流

移动定位

公司app开发过程中需要用到定位功能,在这里对一些定位的常识做一下记录。

平台区别

  • IOS平台都是通过系统SDK接口获取的,因此所有App获取定位及精度的能力是相同的,即使Google Maps、百度地图、高德地图这种专业地图App也是如此。
  • Android平台由于Google Service被阉割,国内App通常是通过高德、百度等第三方SDK接口获取定位信息,因此在定位能力和精度上会有些差异。

坐标系

由于安全性等因素的考虑,我们使用定位功能得到的坐标都不是真实的坐标,都是经过地址转换的,了解坐标系对于我们做逆地址解析有很重要的帮助,因为仅仅得到经纬度对我们用处很小,更多的时候我们需要得到语义化描述,这里我们就需要用到高德或者百度的数据源。

目前常见的坐标系有下面三种

  1. 地球坐标(WGS84,国际公认坐标)
  2. 火星坐标(GCJ02,国家标准,适用于高德百度地图大陆+港澳部分、Google地图大陆部分)
  3. 百度坐标(BD09,适用于百度地图大陆+港澳台部分)。

坐标系需要和地图关连才有意义,只有正确匹配地图坐标系的坐标才能在该地图上完美标识位置,否则就会存在偏移。

其他注意事项:

  • IOS系统上通过定位服务CLLocation相关接口获取定位信息时,获取的经纬度坐标系是WGS84地球坐标。
  • 如果使用高德或者百度IOS定位SDK中的接口,是可以直接获得火星偏移后的坐标的。
  • 如果不集成集成第三方SDK,可以采取近似偏移算法:transform From WGS To GCJ。
  • 如果在iOS系统地图中获取当前位置,同时在国内,那么获取到的坐标系直接是GCJ02火星坐标系。
  • Android系统上通常使用高德或者百度定位SDK获取定位信息。
    • 高德SDK没有坐标系参数设定,在大陆和港澳地区获取的坐标系即为GCJ02坐标系,在台湾和海外地区都是WGS84坐标系;
    • 百度SDK可以自行设定坐标系参数,即返回WGS84坐标系,还是GCJ02坐标系或者BD09坐标系(注意BD09坐标系只适用于百度地图),如果设定的是GCJ02坐标系,它在大陆+港澳台地区获取的坐标系都是GCJ02坐标系。
  • 海外地图(非大陆和非港澳台地区)是没有火星坐标或者百度坐标之说,都是标准的WGS84地球坐标系。

精度问题

通常手机的定位方式有如下三种:

  1. GPS:根据系统GPS模块获取经纬度,精度10-100米左右,限制是容易受环境影响,在室内几乎不起作用。
  2. 基站:根据运营商基站位置计算经纬度,精度1000-3000米左右,限制是定位较慢,精度差。
  3. WIFI:根据周围WIFI路由器位置计算经纬度,精度100-200米左右,限制是受周围WIFI数量和分布影响,需要打开手机WIFI开关。

切记:如果用户没有打开WIFI开关,定位的精度会受到极大的影响。

具体应用

Cordova提供官方定位插件cordova-plugin-geolocation供开发者使用,但是由于国内网络大环境的影响,Android版无法使用,但是IOS是可以使用的,因此有大神写了基于百度定位的Android版插件。这样一来开发者需要针对版本进行区别开发,事实上由于历史原因,公司项目也是区别版本开发的。即便后来出现了基于百度定位的Android和IOS通用版本。

这里贴出封装好的代码:

(function (app) {

  //调用api得到经纬度
  function ios_location(success,error) {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(function (position) {
        console.log("(IOS)Latitude: " + position.coords.latitude + "Longitude: " + position.coords.longitude);
        //注意:在得到准确位置前,需要对原生的坐标系转化成百度的坐标系
        var point = new BMap.Point(position.coords.longitude, position.coords.latitude);
        BMap.Convertor.translate(point, 0, function(point){
          //调用百度的逆地址解析
          var geoc = new BMap.Geocoder();
          geoc.getLocation(point, function (rs) {
            success(rs);
          }, function (err) {
            error({code:-1,message:'定位出错(IOS)'});
          });
        });

      }, function (err) {
        if (err.code === 1) {
          error({code:-3,message:'手机定位功能未开启(IOS)'});
        }else{
          error({code:-1,message:'定位出错(IOS)'});
        }
      }, {
        enableHighAccuracy: true
      });
    } else {
      error({code:-2,message:'不支持定位(IOS)'});
    }
  }

  //创建位置详细信息
  function createDetailAddr(data) {
    var addr,
        pois,
        addrDatas = [],
        isAndroid = ionic.Platform.isAndroid();

    if (isAndroid) {
      addr = data.addr.substring(2);
      pois = data.pois;
      if (pois == null) {
        addrDatas.push(addr);
      } else {
        var isArray = angular.isArray(pois);
        if (isArray) {
          if (pois.length == 0) {
            addrDatas.push(addr);
          } else {
            for (var i = 0; i < pois.length; i++) {
              if (pois[i].name) {
                addrDatas.push(addr + pois[i].name);
              }
            }
          }
        } else {
          if (pois.name) {
            addrDatas.push(addr + pois.name);
          }
        }
      }
    } else {
      addr = data.address;
      pois = data.surroundingPois;
      if (pois == null) {
        addrDatas.push(addr);
      } else {
        var isArray = angular.isArray(pois);
        if (isArray) {
          if (pois.length == 0) {
            addrDatas.push(addr);
          } else {
            for (var i = 0; i < pois.length; i++) {
              if (pois[i].title) {
                addrDatas.push(addr + pois[i].title);
              }
            }
          }
        } else {
          if (pois.title) {
            addrDatas.push(addr + pois.title);
          }
        }
      }
    }
    return addrDatas;
  }

  var LocationUtil = {

    startLocation: function (callback) {
      // 手机环境
      if (window.cordova) {
        if (ionic.Platform.isAndroid()) {
          baidumap_location.getCurrentPosition(function (data) {
            console.log("android location success");
            callback({
              code:0,
              message:'定位成功',
              position:createDetailAddr(data)
            });
          }, function (err) {
            console.log("android location error");
            // 没有权限进入error
            callback({
              code:-1,
              message:'手机定位功能未开启(Android)'
            });
          });
        } else {
          ios_location(function(data){
            console.log("ios location success");
            callback({
              code:0,
              message:'定位成功',
              position:createDetailAddr(data)
            });
          },function(err){
            console.log("ios location error");
            callback(err);
          });
        }
      }
    }

  }

  app.LocationUtil = LocationUtil;
})(window);

更多资料



留言