概述
本篇主要介紹android基站定位的基本思路,解釋了下用到的TelephonyManager的一些方法。最后介紹了google定位服務(wù)與android提供參數(shù)之間的聯(lián)系。
基站定位原理:
通過手機(jī)信號(hào)獲取基站信息,然后調(diào)用第三方服務(wù)的根據(jù)基站信息查找基站的經(jīng)緯度值。
盡管根據(jù)基站網(wǎng)絡(luò)制式不同(cdma或gsm)所獲取的基站信息也不一樣,但一般用谷歌等這樣的第三方定位服務(wù)需要獲得這些基站信息:
- MCC,Mobile Country Code,移動(dòng)國家代碼(中國的為460)。
- MNC,Mobile Network Code,移動(dòng)網(wǎng)絡(luò)號(hào)碼(中國移動(dòng)為0,中國聯(lián)通為1,中國電信為2)。
- LAC,Location Area Code,位置區(qū)域碼。
- CID,Cell Identity,基站編號(hào)。
- BSSS,Base station signal strength,基站信號(hào)強(qiáng)度。
Android基站信息api
獲取網(wǎng)絡(luò)服務(wù)商信息MNC&MCC
從系統(tǒng)服務(wù)中獲取TelephonyManager:
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
TelephonyManager#getNetworkOperator方法獲取目前注冊(cè)網(wǎng)絡(luò)MCC+MNC信息,一般是5-6位的字符串,前3位為MCC,后面的是MNC。
用戶必須在該網(wǎng)絡(luò)注冊(cè)才能獲取到信息,對(duì)于cdma網(wǎng)絡(luò)而言可能會(huì)不靠譜,因此用TelephonyManager#getPhoneType來判斷手機(jī)支持的網(wǎng)絡(luò)制式。
String operator = telephonyManager.getNetworkOperator();
String mcc = operator.substring(0, 3);
String mnc = operator.substring(3);
TelephonyManager#getSimOperator方法獲取Sim卡的MCC+MNC信息
SM卡狀態(tài)必須處于SIM_STATE_READY,用TelephonyManager#getSimState判斷Sim卡狀態(tài)。
TelephonyManager#getPhoneType 獲取手機(jī)支持網(wǎng)絡(luò)制式
一般就GSM、CDMA兩種,如果沒有獲取到則是NONE。
TelephonyManager#getNetWorkType 獲取網(wǎng)絡(luò)類型
用以區(qū)分移動(dòng)2g,電信4g等更具體的網(wǎng)絡(luò)。
獲取當(dāng)前連接基站信息LAC、CID
由于電信用的是cdma制式網(wǎng)絡(luò),移動(dòng)和聯(lián)通用的gsm網(wǎng)絡(luò),這兩種網(wǎng)絡(luò)基站信息封裝類在android中是不同的,cdma要用CdmaCellLocation,gsm要用GsmCellLocation。
從TelephonManager獲取基站定位信息CellLocation,其中封裝了需要的CID和LAC等信息。
if(telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA){
CdmaCellLocation cdmaCellLocation = (CdmaCellLocation)
telephonyManager.getCellLocation();
int cid = cdmaCellLocation.getBaseStationId(); //獲取cdma基站識(shí)別標(biāo)號(hào) BID
int lac = cdmaCellLocation.getNetworkId(); //獲取cdma網(wǎng)絡(luò)編號(hào)NID
int sid = cdmaCellLocation.getSystemId(); //用谷歌API的話cdma網(wǎng)絡(luò)的mnc要用這個(gè)getSystemId()取得→SID
}else{
GsmCellLocation gsmCellLocation = (GsmCellLocation) telephonyManager.getCellLocation();
int cid = gsmCellLocation.getCid(); //獲取gsm基站識(shí)別標(biāo)號(hào)
int lac = gsmCellLocation.getLac(); //獲取gsm網(wǎng)絡(luò)編號(hào)
}
獲取鄰近基站信號(hào)強(qiáng)度信息BSSS
每個(gè)基站信息封裝在具體CellInfo子類中,有CellInfoCdma、CellInfoGsm等。CellInfoGsm中又封裝了2個(gè)函數(shù),分別用來返回基站識(shí)別信息(CellIdentityGsm類)和基站信號(hào)強(qiáng)度信息(CellSignalStrengthGsm類)。
TelephonyManager#getAllCellInfo方法返回所有能檢測到的基站信息(包括連接的基站信息),而且返回的信息更詳細(xì)。而TelephonyManager#getNeighboringCellInfo方法不包括連接的基站信息,返回基站信息是經(jīng)過處理的,不加以cdma或gsm區(qū)分。一般用getAllCellInfo方法。
List<CellInfo> infoLists = telephonyManager.getAllCellInfo();
for (CellInfo info : infoLists) {
CellInfoCdma cellInfoCdma = (CellInfoCdma) info;
CellIdentityCdma cellIdentityCdma = cellInfoCdma.getCellIdentity();
CellSignalStrengthCdma cellSignalStrengthCdma = cellInfoCdma.getCellSignalStrength();
int strength = cellSignalStrengthCdma.getCdmaDbm();
int cid = cellIdentityCdma.getBasestationId();
// 處理 strength和id數(shù)據(jù)
}
CellSignalStrengthCdma類中封裝了各種信號(hào)處理方法,用來返回不同標(biāo)準(zhǔn)的信號(hào)強(qiáng)度。CellIdentityCdma類封裝了Cdma基站特有的識(shí)別信息,比如能通過CellIdentityCdma#getLongitude()獲取Cdma基站的經(jīng)緯度。CellIdentityGsm類封裝Gsm基站信息,能獲取MCC、MNC、CID和LAC。
Android 基站信息監(jiān)聽器
PhoneStateListener類是一個(gè)監(jiān)聽類,重寫其中方法實(shí)現(xiàn)對(duì)基站信息變化的監(jiān)聽。
private PhoneStateListener phoneStateListener; //定義監(jiān)聽器
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CELL_LOCATION); //注冊(cè)監(jiān)聽器,設(shè)定不同的監(jiān)聽類型
//設(shè)置監(jiān)聽器方法
private void setPhoneStateListener(){
phoneStateListener = new PhoneStateListener(){
@Override
public void onCellLocationChanged(CellLocation location){}
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {}
@Override
public void onCellInfoChanged(List<CellInfo> cellInfo) {}
}
}
這里主要用到的三個(gè)回調(diào)函數(shù):
onCellLocationChanged 當(dāng)cellLocation變化時(shí)會(huì)調(diào)用,傳入cellLocation類型,需要根據(jù)具體的網(wǎng)絡(luò)制式向下轉(zhuǎn)型(CdmaCellLocation或GsmCellLocation)。
onSignalStrengthsChanged 傳入的是SignalStrength類型,這個(gè)類型和CellStrength類沒關(guān)系,是一個(gè)重新寫的類。其中有自定義的一些方法返回信號(hào)強(qiáng)度,有g(shù)etCdmaDbm()、getGsmSignalStrength()。Coma和gsm類型都封裝在一起,需要調(diào)用額外的方法isGsm()。
onCellInfoChanged 傳入?yún)?shù)為CellInfo,維護(hù)一個(gè)CellInfo列表,有檢測到的基站變動(dòng)都會(huì)調(diào)用。方法跟TelephonyManager#getAllCellInfo()的使用類似。
google定位服務(wù)API
移動(dòng)電話基站Json
google的基站定位服務(wù)所需參數(shù):
"homeMobileCountryCode": 310, //即MCC
"homeMobileNetworkCode": 410, //即MNC
"radioType": "gsm",
"carrier": "Vodafone",
"considerIp": "true",
"cellTowers": [
// See the Cell Tower Objects section below.
]
cellTower就是之前說的信號(hào)強(qiáng)度BSSS參數(shù),需要一個(gè)列表來記錄周圍基站參數(shù)。cellTower并不是必要參數(shù),但是給了可以增加定位精確度。
{
"cellTowers": [
{
"cellId": 42,
"locationAreaCode": 415,
"mobileCountryCode": 310,
"mobileNetworkCode": 410,
"age": 0,
"signalStrength": -60,
"timingAdvance": 15
}
]
}
CellTowers必填字段:
- cellId(必填): GSM用的是CID,CDMA 網(wǎng)絡(luò)使用的是基站 ID (BID)。WCDMA 網(wǎng)絡(luò)使用 UTRAN/GERAN 基站標(biāo)識(shí) (UC-Id),這是一個(gè) 32 位的值,由無線網(wǎng)絡(luò)控制器 (RNC) 和基站 ID 連接而成。在 WCDMA 網(wǎng)絡(luò)中,如果只指定 16 位的基站 ID 值,返回的結(jié)果可能會(huì)不準(zhǔn)確。
- locationAreaCode(必填):GSM 和 WCDMA 網(wǎng)絡(luò)的位置區(qū)域代碼 (LAC)。CDMA 網(wǎng)絡(luò)的網(wǎng)絡(luò) ID (NID)。
- mobileCountryCode(必填):移動(dòng)電話基站的移動(dòng)國家代碼 (MCC)。
- mobileNetworkCode(必填):移動(dòng)電話基站的移動(dòng)網(wǎng)絡(luò)代碼。對(duì)于 GSM 和 WCDMA,這就是 MNC;CDMA 使用的是系統(tǒng) ID (SID)。