Android API更新很快,我只是这路上的一个火炬手,希望我这星星之火,可以燎原吧!诚然,我写本文的初衷跟参考文献一样都是基于项目的。
概要
本篇文章主要介绍Android基站定位,第三方APP如何监听通信状态等等。另外,本文用Kotlin作为演示代码
基础知识
首先你要明白这是基于WiFi或手机卡来获取基站信息,再通过第三方服务接口(或自己实现)来进行定位。
MCC (Mobile Country Code) // 移动国家代码(中国的为460)
MNC (Mobile Network Code) // 基站编号(移动为0,联通为1,电信为2)
LAC (Location Area Code) // 位置区域码
CID (Cell Identity) // 基站编号
BSSS (Base station signal strength) // 基站信号强度
dBm //手机主卡信号强度单位
信号强度取值范围
等级 | 标准 |
---|---|
较好 | > -80dBm |
一般 | -80dBm ~ -100dBm |
较差 | -100dBm ~ 115dBm |
很差 | < -115dBm |
Android 基站定位
TelephonyManager
源码注释是这样写的
怎么使用?
@SystemService(Context.TELEPHONY_SERVICE)
public class TelephonyManager {
所以这样用
val tm = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
下面我们来看下他为我们提供了哪些常用的方法
- TelephonyManager#getPhoneType
很多人对这个方法都做过说明,但我测试,好像这个并不能为我们提供什么有效信息,所以去看了下原文注释。
Returns a constant indicating the device phone type. This
indicates the type of radio used to transmit voice calls.
@see #PHONE_TYPE_NONE
@see #PHONE_TYPE_GSM
@see #PHONE_TYPE_CDMA
@see #PHONE_TYPE_SIP
- TelephonyManager#getNetworkType
获取网络类型。这个看源码你可能会吓一跳,我建议你直接百度手机网络类型
。
中国移动:GSM(2G)/TD-SCDMA(3G)/TD-LTE(4G)
中国联通:GSM(2G)/WCDMA(3G)/TD-LTE(4G)/FDD-LTE(4G)
中国电信:CDMA1X(2G)/EVDO(3G)/TD-LTE(4G)/FDD-LTE(4G)
所以你要记住这样几个关键词 GSM
、CDMA
、LTE
获取信息的一些代码:
val networkType = tm.networkType
val networkOperator = tm.networkOperator
val networkOperatorName = tm.networkOperatorName
val phoneType = tm.phoneType
val id = tm.deviceId // tm.imei //(API 26)
注意:val id = tm.deviceId // tm.imei //(API 26)
获取邻近基站信息
如果你网上搜,可能会是这样的:
tm.cellLocation
进入源码就知道是这样的
val lists : List = tm.allCellInfo
如何解析?这样吗?
List infoLists = telephonyManager.getAllCellInfo();
for (CellInfo info : infoLists) {
CellInfoCdma cellInfoCdma = (CellInfoCdma) info;
如果你去看 CellInfo
你会发现他是有子类的。
CellInfoCdma // 电信3G的基站数据
CellInfoGsm // 通用的移动联通电信2G的基站数据
CellInfoLte // 4g网络的基站数据
CellInfoWcdma // 联通3G的基站数据
你还记得上面说几个关键词吗?下面贴上逻辑代码
for (cellInfo in lists) {
sbCellInfo.append(cellInfo.toString())
/**
* 1、GSM是通用的移动联通电信2G的基站。
* 2、CDMA是3G的基站。
* 3、LTE,则证明支持4G的基站。
*/
val bean = BaseDataBean()
when {
cellInfo.toString().contains("CellInfoLte") -> {
}
cellInfo.toString().contains("CellInfoGsm") -> {
}
cellInfo.toString().contains("CellInfoCdma") -> {
}
// 特殊的在这里处理
}
}
下面来说下留白的地方可能需要填写的代码
有两种情况,第一种我们一个为例
val cellInfo : CellInfoLte = cellInfo as CellInfoLte
val cellSignalStrength : CellSignalStrengthLte = cellInfo.cellSignalStrength
val cellIdentity : CellIdentityLte = cellInfo.cellIdentity
val dbm : Int = cellSignalStrength.dbm
val lac : Int = cellIdentity.tac
val mcc : Int = cellIdentity.mcc
val ci : Int = cellIdentity.ci
val mnc : Int = cellIdentity.mnc
bean.cellId = ci
bean.lac = lac
bean.mcc = mcc
bean.mnc = mnc
bean.dbm = dbm
第二种,也就是第三个,代码如下:
val cellInfo : CellInfoCdma = cellInfo as CellInfoCdma
val cellSignalStrength : CellSignalStrengthCdma = cellInfo.cellSignalStrength
val cellIdentity : CellIdentityCdma = cellInfo.cellIdentity
val dbm : Int = cellSignalStrength.dbm
val lac : Int = cellIdentity.networkId //获取cdma网络编号NID
val mcc = 0
val ci : Int = cellIdentity.basestationId //获取cdma基站识别标号
val mnc = 0
/**
* cellIdentity.longitude // 经度
* cellIdentity.latitude // 纬度
* cellIdentity.systemId //用谷歌API的话cdma网络的mnc要用这个getSystemId()取得→SID
*/
bean.cellId = ci
bean.lac = lac
bean.mcc = mcc
bean.mnc = mnc
bean.dbm = dbm
还是贴下bean
的代码吧:
class BaseDataBean {
var cellId : Int = 0
var lac : Int = 0
var mcc : Int = 0
var mnc : Int = 0
var dbm : Int = 0 // 信号强度
override fun toString(): String {
return "BaseDataBean(cellId=$cellId, lac=$lac, mcc=$mcc, mnc=$mnc, dbm=$dbm)"
}
}
之后,你就可以去条用基站地位接口了(收费的、自己写或是用Google的)
关于Goole的调用,在Goole的文档中,已经说得非常明确了,见Google Maps Geolocation API
PhoneStateListener
如果你是第三方APP开发者,可以对这里感兴趣。
我们需要先创建一个listener
对象,来获取TelephonyManager服务
private val listener : PhoneStateListener = object : PhoneStateListener() {
}
然后,你需要去listen
tm.listen(listener, PhoneStateListener.LISTEN_CELL_LOCATION) // 变化监听
来看下 的源码注释吧
A listener class for monitoring changes in specific telephony states
on the device, including service state, signal strength, message
waiting indicator (voicemail), and others.
Override the methods for the state that you wish to receive updates for, and
pass your PhoneStateListener object, along with bitwise-or of the LISTEN_
flags to {@link TelephonyManager#listen TelephonyManager.listen()}.
到这里你就可以去做更多的事了。
权限
最后值得一提的是,不要忘记添加权限
参考文献
1、Android基站定位基本应用
2、Android获取基站信息
3、获取wifi和基站定位的基础信息
4、PhoneStateListener
5、Google Maps Geolocation API
6、Android参考文档 TelephonyManager
6、Android Network --判断网络状态(网络的连接,改变,和判断2G/3G/4G)