Android中的几种定位方式调用详解

目前,移动端大致通过三种方式来进行设备定位:GPS、基站、wifi。本文就详细的讲解一下这几种定位方式和实现方法。

前言

android中我们一般使用LocationManager来获取位置信息,这里面有四中provider:

public static final String NETWORK_PROVIDER = "network";
public static final String GPS_PROVIDER = "gps";
public static final String PASSIVE_PROVIDER = "passive";
public static final String FUSED_PROVIDER = "fused";

其中fused已经被废弃了,其它三种区别如下:

(1)GPS_PROVIDER:通过 GPS 来获取地理位置的经纬度信息;优点:获取地理位置信息精确度高;缺点:只能在户外使用,获取经纬度信息耗时,耗电;

(2)NETWORK_PROVIDER:通过移动网络的基站或者 Wi-Fi 来获取地理位置;优点:只要有网络,就可以快速定位,室内室外都可;缺点:精确度不高;

(3)PASSIVE_PROVIDER:被动接收更新地理位置信息,而不用自己请求地理位置信息。

        PASSIVE_PROVIDER 返回的位置是通过其他 providers 产生的,可以查询 getProvider() 方法决定位置更新的由来,需要 ACCESS_FINE_LOCATION 权限,但是如果未启用 GPS,则此provider 可能只返回粗略位置匹配;

我们通常使用gps和network这两种方式。但是我们还可以通过其它方式获取位置信息,这篇文章就详细的讲解一下在android中几种获取定位的方式。

一、GPS定位

这个用的最普遍,可以获取上次定位,也可以监听变化,代码如下:

先定义需要的权限

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

调用代码

var locManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
var loc = locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if(loc != null){Log.e("gpslocation", loc.toString())toast(loc.toString())
}
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0F, object : LocationListener{override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}override fun onProviderEnabled(provider: String?) {}override fun onProviderDisabled(provider: String?) {}override fun onLocationChanged(location: Location?) {Log.e("gpslocation", location.toString())toast(location.toString())}
})

二、NETWORK定位

        与gps定位代码基本一致,只不过将provider改成LocationManager.NETWORK_PROVIDER

三、AGPS定位

实际上是将上面两种定位结合起来,具体原理如下:

AGPS手机首先将本身的基站地址通过网络传输到位置服务器;

位置服务器根据该手机的大概位置传输与该位置相关的GPS辅助信息(包含GPS的星历和方位俯仰角等)到手机;

该手机的AGPS模块根据辅助信息(以提升GPS信号的第一锁定时间TTFF能力)接收GPS原始信号;

手机在接收到GPS原始信号后解调信号,计算手机到卫星的伪距(伪距为受各种GPS误差影响的距离),并将有关信息通过网络传输到位置服务器;

位置服务器根据传来的GPS伪距信息和来自其他定位设备(如差分GPS基准站等)的辅助信息完成对GPS信息的处理,并估算该手机的位置;

位置服务器将该手机的位置通过网络传输到定位网关或应用平台。

我的理解就是通过网络位置和位置服务器判断出最佳的卫星,减少了获取卫星信号的时间。因为网络位置获取很快,所以可以减少整体的定位时间。

AGPS并不是一种定位方式,只是一种优化方案,代码与GPS一样,只不过在设置中将定位模式设成AGPS。

上面是android自带的定位方式,我们还可以获取一些原始信息(比如基站信息、wifi信息),通过公开的接口来获取位置信息。下面几种方式就是使用原始信息通过API来获取位置信息。

四、基站定位

通过TelephonyManager我们可以拿到基站信息,再通过相关的api接口就能得到经纬度,但是基站定位精度很差。

基站信息包含如下:

  • MCC,Mobile Country Code,移动国家代码(中国的为460);
  • MNC,Mobile Network Code,移动网络号码(中国移动为00,中国联通为01);
  • LAC,Location Area Code,位置区域码;
  • CID,Cell Identity,基站编号,是个16位的数据(范围是0到65535)。

拿到这个信息后,我们可以通过一些公开的api服务拿到经纬度,如下:

http://www.google.com/loc/json google的,post请求,好像停用了

http://www.cellocation.com/interfac/目前可用,是免费的

实例:

http://api.cellocation.com:81/cell/?mcc=460&mnc=1&lac=4301&ci=20986&output=json

返回:

{"errcode":0, "lat":"40.00598145", "lon":"116.48539734", "radius":"937", "address":"北京市朝阳区来广营地区东湖渠;溪阳东路与屏翠东路路口东70米"}

接口参数:

名称

类型

必填

说明

mcc

int

mcc国家代码:中国代码 460

mnc

int

mnc网络类型:0移动,1联通(电信对应sid),十进制

lac

int

lac(电信对应nid),十进制

ci

int

cellid(电信对应bid),十进制

coord

string

坐标类型(wgs84/gcj02/bd09),默认wgs84

output

string

返回格式(csv/json/xml),默认csv

另外还有很多提供这种接口和数据的平台,自己搜索即可

代码如下:需要权限

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_CARSE_LOCATION"/>

基站定位,这里只实现了GSM的,CDMA的有些许不同

val telManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
if(telManager.cellLocation is GsmCellLocation) {val cellLoc = telManager.cellLocation as GsmCellLocationif (cellLoc != null) {val operator = telManager.networkOperatorval mcc = operator.substring(0, 3).toInt()val mnc = operator.substring(3).toInt()val cid = cellLoc.cidval lac = cellLoc.lacvar sb = StringBuilder("http://api.cellocation.com:81/cell/?")sb.append("mcc=")sb.append(mcc)sb.append("&mnc=")sb.append(mnc)sb.append("&lac=")sb.append(lac)sb.append("&ci=")sb.append(cid)sb.append("&output=json")Log.e("tellocation", sb.toString())doAsync {val result = URL(sb.toString()).readText()Log.e("tellocation", result)}}
}

五、WIFI定位

wifi定位是通过WifiManager拿到wifi的信息,主要是wifi的BSSID(即mac地址)。然后通过一些api查询经纬度,比如 http://www.cellocation.com/interfac/

实例:

http://api.cellocation.com:81/wifi/?mac=00:87:36:05:5d:ea&output=json

返回:

{"errcode":0, "lat":"39.950008", "lon":"116.230049", "radius":"222", "address":"北京市海淀区四季青镇益园文创基地c区9号楼;南平庄中路与西平庄路路口西北561米"}

接口参数:

名称

类型

必填

说明

mac

int

WIFI热点的MAC地址(BSSID)

coord

string

坐标类型(wgs84/gcj02/bd09),默认wgs84

output

string

返回格式(csv/json/xml),默认csv

代码如下:需要权限

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

wifi定位

val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
if(wifiManager.isWifiEnabled) {var mac = wifiManager.connectionInfo.bssidif(TextUtils.isEmpty(mac)) {/*** 当未链接wifi时,可以使用扫描到的wifi列表中找一个信号强度最好的。这里没进行比较,直接使用第一个了* ScanReuslt有三个字段比较重要:SSID是wifi名称,BSSID是wifi的mac,level则是信号强度(负数)* 注意结果中同一个SSID可能会有多个,如果需要链接wifi可以通过信号强度过滤出最好的来链接*/val scanlist = wifiManager.scanResultsfor(info in scanlist){Log.e("wifiinfo", info.toString())}if(scanlist.size > 0) {mac = wifiManager.scanResults[0].BSSID}}if(!TextUtils.isEmpty(mac)) {var sb = StringBuilder("http://api.cellocation.com:81/wifi/?")sb.append("mac=")sb.append(mac)sb.append("&output=json")Log.e("wifilocation", sb.toString())doAsync {val result = URL(sb.toString()).readText()Log.e("wifilocation", result)}}
}

六、混合定位

混合定位就是获取附近的wifi列表信息(包括信号强度)和附近的基站列表信息(包括信号强度),通过一些api获取经纬度。

这种方式相对于单一的基站和wifi定位要更精确一些。

获取附近的wifi列表在WIFI定位已经提到过了,通过WifiManager的getScanResults函数获取扫描到的wifi列表,其中level就是信号强度,可能需要做一下去重。

获取附近的基站列表则有些问题。

官方提供了一个方式,通过TelephonyManager的getNeighboringCellInfo函数获得,其中mRssi就是信号强度。

需要权限

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

获取附近基站信息

val telManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val neighborCells = telManager.neighboringCellInfo
for(cell in neighborCells){//这里将rssi转化为dBmval level = -131 + 2 * cell.rssiLog.e("neighboringCellInfo", "cid:${cell.cid} lac:${cell.lac} rssi:$level")
}

但是实际使用时发现cid和lac都是-1。

检查NeighboringCellInfo的构造方法,如下:

  public NeighboringCellInfo(int rssi, String location, int radioType) {// set default valuemRssi = rssi;mNetworkType = NETWORK_TYPE_UNKNOWN;mPsc = UNKNOWN_CID;mLac = UNKNOWN_CID;mCid = UNKNOWN_CID;// pad location string with leading "0"int l = location.length();if (l > 8) return;if (l < 8) {for (int i = 0; i < (8-l); i++) {location = "0" + location;}}// TODO - handle LTE and eHRPD (or find they can't be supported)try {// set LAC/CID or PSC based on radioTypeswitch (radioType) {case NETWORK_TYPE_GPRS:case NETWORK_TYPE_EDGE:mNetworkType = radioType;// check if 0xFFFFFFFF for UNKNOWN_CIDif (!location.equalsIgnoreCase("FFFFFFFF")) {mCid = Integer.parseInt(location.substring(4), 16);mLac = Integer.parseInt(location.substring(0, 4), 16);}break;case NETWORK_TYPE_UMTS:case NETWORK_TYPE_HSDPA:case NETWORK_TYPE_HSUPA:case NETWORK_TYPE_HSPA:mNetworkType = radioType;mPsc = Integer.parseInt(location, 16);break;}} catch (NumberFormatException e) {// parsing location errormPsc = UNKNOWN_CID;mLac = UNKNOWN_CID;mCid = UNKNOWN_CID;mNetworkType = NETWORK_TYPE_UNKNOWN;}}

可以看到只对GPRS和EDGE网络进行了处理,而3G、4G网络都是UNKNOWN_CID,即-1。说明这种方法不支持,已经过时。

官方还有另外一个方式,通过TelephonyManager的getAllCellInfo函数获得。这个函数要求minsdkverison必须在17及以上

需要权限

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

获取基站信息,这里只处理了LTE网络的

val telManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val cells = telManager.allCellInfo
for(cell in cells){if(cell is CellInfoLte) {Log.e("celllist", "cid:${cell.cellIdentity.ci} lac:${cell.cellIdentity.tac} dbm:${cell.cellSignalStrength.dbm} isRegistered:${cell.isRegistered}")}
}

得到的信息如下:

E/celllist: cid:3912981 lac:4154 dbm:-87 isRegistered:true

E/celllist: cid:2147483647 lac:2147483647 dbm:-101 isRegistered:false

E/celllist: cid:2147483647 lac:2147483647 dbm:-102 isRegistered:false

E/celllist: cid:2147483647 lac:2147483647 dbm:-108 isRegistered:false

E/celllist: cid:2147483647 lac:2147483647 dbm:-101 isRegistered:false

其中第一个是我们正在使用的基站,可以看到正常的返回了信息,而其余的则返回默认的信息(Integer.MAX_VALUE)

说明这个方法也只能拿到当前使用的基站信息。而且据网上的说法,当使用2G网络,getAllCellInfo得到的是NULL。

这样目前没有更好的方式获取多个基站信息了。

当我们拿到附近的基站信息和wifi信息,可以通过http://www.cellocation.com/interfac/提供的混合定位接口查询位置信息,与上面类似,这里不细说了。

总结

一般情况下,我们使用系统提供的LocationManager即可获取位置信息,方便简单。如果我们有自己的基站或wifi信息库,也可以获取相关源信息通过接口来实现个性化服务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/721924.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

怎样获取html网页中<ul >中的数据?

您可以使用Python中的BeautifulSoup库来获取HTML网页中<ul>标签中的数据。以下是一个示例代码&#xff1a; rom bs4 import BeautifulSoup import requests# 发送HTTP请求并获取网页内容 url "http://example.com" # 替换为目标网页的URL response request…

YOLOv8从入门到入土使用教程!(一)训练模型

⭐⭐⭐瞧一瞧看一看&#xff0c;新鲜的YOLOv9魔改专栏来啦&#xff01;⭐⭐⭐ 专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文将演示如何使用YOLOv8进行训练及预测&#xff01; 二…

线性dp 最长公共子序列(二分版本)

本题由于1e5的数据&#xff0c;n方的做法不再适用&#xff0c;但是简单的一维并不能满足动态转移。这时&#xff0c;我们就可以考虑引入最长上升子序列来处理 用样例来看 5 序列&#xff1a;3 2 1 4 5序号&#xff1a;1 2 3 4 5序列&#xff1a;1 2 3 4 5序号&#xff1a;3 2…

1.1 Java 注解(Annotation)

1.1 注解&#xff08;Annotation&#xff09; 1.1.1 什么是注解 注解的定义&#xff1a;它提供了一种安全的类似注释的机制&#xff0c;用来将任何信息或元数据&#xff08;metadata&#xff09;与程序元素&#xff08;类、方法、成员变量等&#xff09;进行关联。为程序的元…

九型人格测试,2号人格助人型的职业分析

九型人格测试中的助人型&#xff0c;也叫二号人格&#xff0c;解读专业选择和职业选择。 助人型人格&#xff0c;在九型人格中&#xff0c;被视作一种给予者&#xff0c;他们总是喜欢帮助别人&#xff0c;有一个观念&#xff1a;“我不帮助别人&#xff0c;就没有人愿意喜欢我…

透明玻璃屏幕为什么那么贵

透明玻璃屏幕之所以价格较高&#xff0c;主要是由于以下几个方面的原因&#xff1a; 技术研发与创新&#xff1a;透明玻璃屏幕作为一种先进的显示技术&#xff0c;其研发和制造过程涉及到许多复杂的技术。这些技术的研发和创新需要投入大量的资金和时间。此外&#xff0c;透明玻…

鸿蒙应用native开发入门以及运行native项目报错spawn EPERM问题解决以及so包调用

目录 DevEco Studio新建native项目 新建第一个native项目 解决spawn EPERM报错 点击运行 分析流程

无冬之夜:增强版 Neverwinter Nights Mac 激活版

Neverwinter Nights是一款角色扮演游戏。游戏的剧情发生在虚构的城市Neverwinter&#xff0c;玩家扮演一个冒险者&#xff0c;在这个城市中探索并完成各种任务。游戏中有许多不同的职业、种族、技能和法术可供玩家选择。游戏的主要特点包括多人游戏模式、自定义模块和工具包&am…

【Mc生存】插火把

【Mc生存】插火把 题目描述 话说有一天 linyorson 在“我的世界”开了一个 n n n \times n nn 的方阵&#xff0c;现在他有 m m m 个火把和 k k k 个萤石&#xff0c;分别放在 ( x 1 , y 1 ) ∼ ( x m , y m ) (x_1, y_1) \sim (x_m, y_m) (x1​,y1​)∼(xm​,ym​) 和 …

【书生·浦语大模型实战营】第5节 课后作业

LMDeploy 的量化和部署 0. 课程链接1. 课后作业1.1 基础作业1.2 进阶作业&#xff08;可选做&#xff09; 0. 课程链接 链接&#xff1a;https://github.com/InternLM/tutorial/blob/main/lmdeploy/lmdeploy.md 1. 课后作业 1.1 基础作业 使用 LMDeploy 以本地对话、网页Gra…

大模型技术在测试领域应用的方向思考

方向1&#xff1a;利用大模型技术生成测试用例 方向2&#xff1a;利用大模型技术进行测试用例推荐 如何利用大模型技术生成测试用例 大模型技术&#xff0c;如自然语言处理&#xff08;NLP&#xff09;中的大型预训练模型&#xff0c;如BERT、GPT等&#xff0c;已经在许多领…

HTML5:七天学会基础动画网页5

CSS3渐变 (可以给背景颜色设置一个渐变的效果) 线性渐变:Linear Gradients(从直线上向远处见面) 语法: background:linear-gradient(direction&#xff0c;color-stop1&#xff0c;color-stop2…)&#xff1b; direction:方向 to left, to right, 90deg 径向渐变:Radial …

Python Flask Web + PyQt 前后端分离的项目—学习成绩可视化分析系统

简介 使用工具&#xff1a; Python&#xff0c;PyQt &#xff0c;Flask &#xff0c;MySQL 注&#xff1a;制作重点在网页端&#xff0c;因此网页端的功能更全 WEB界面展示: 系统登录分为管理员&#xff0c;老师&#xff0c;学生3部分 管理员统一管理所有的账号信息以及登录…

Jenkins发送邮件、定时执行、持续部署

集成Allure报告只需要配置构建后操作即可。但如果是web自动化&#xff0c;或是用HTMLTestRunner生成报告&#xff0c;构建后操作要选择Publish HTML reports&#xff0c;而构建中还要添加Execute system Groovy script插件&#xff0c;内容&#xff1a; System.setProperty(&q…

【数据结构】用队列实现栈

下面是一些思路分析和代码分享&#xff0c;有需要借鉴即可。 1.问题描述 我想用队列来实现栈的功能&#xff0c;具体而言是用两个队列做底层做出栈的功能来。 有人可能会疑问会不会多次一举&#xff0c;这里仅作练习&#xff0c;为了更加进一步了解栈/队列的性质 2.思路分析 …

基于Spring Boot+ Vue的房屋租赁系统

末尾获取源码作者介绍&#xff1a;大家好&#xff0c;我是墨韵&#xff0c;本人4年开发经验&#xff0c;专注定制项目开发 更多项目&#xff1a;CSDN主页YAML墨韵 学如逆水行舟&#xff0c;不进则退。学习如赶路&#xff0c;不能慢一步。 目录 一、项目简介 二、开发技术与环…

抉择与发展:详解程序员在前端、后端与数据科学赛道上的职业定位与成长路径

作为一个程序员&#xff0c;选择职业赛道就像是在一座迷宫中探索前端的美丽花园&#xff0c;后端的黑暗洞穴&#xff0c;还有数据科学的神秘密室。每一条赛道都充满了挑战和机遇&#xff0c;而选择哪一条赛道将直接影响到你未来的职业发展和成就。对于每一位准备投身或已经在编…

搜维尔科技:捕获、分析、优化,使用 Xsens Ergo 创建更安全的工作空间

简化人体工程学分析&#xff0c;优先考虑员工福祉&#xff0c;并利用客观数据和见解提高生产力。 捕获。分析。优化。使用 Xsens Ergo 创建更安全的工作空间 1.质量数据 使用高质量、客观且经过验证的运动数据进行详细的人体工程学分析 2.随处使用 在最具挑战性的工作环境中…

HarmonyOS Stage模型 用程序运行切换 验证UIAbility 启动模式(下) 验证:specified启动模式 Ability间切换

上文 HarmonyOS Stage模型 用程序运行切换 验证UIAbility 启动模式(上) 验证:singleton、multiton、standard启动模式 我们已经验证完了 singleton multiton standard 三种启动模式 留下了毕竟复杂的 specified 这里 首先 我们要写两个不同的界面 index 编写代码如下 import…

centos 搭建ftp服务器

项目上需要用到ftp文件服务同步&#xff0c;所以在测试环境进行搭建&#xff0c;其中遇到了一些问题&#xff0c;遂记录。 1、安装vsftpd软件包 打开终端并输入以下命令来安装vsftpd yum install vsftpd -y 2、运行vsftpd systemctl start vsftpd 3、测试匿名连接 我这里…