Android基站定位、第三方APP监听通信状态

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

源码注释是这样写的


Android基站定位、第三方APP监听通信状态_第1张图片
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)

所以你要记住这样几个关键词 GSMCDMALTE

获取信息的一些代码:

        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)

你可能感兴趣的:(Android基站定位、第三方APP监听通信状态)