一、通过手机信号获取基站信息
通过TelephonyManager 获取lac:mcc:mnc:cell-id(基站信息)的解释:
MCC,Mobile Country Code,移动国家代码(中国的为460);
MNC,Mobile Network Code,移动网络号码(中国移动为0,中国联通为1,中国电信为2);
LAC,Location Area Code,位置区域码;
CID,Cell Identity,基站编号;
BSSS,Base station signal strength,基站信号强度。
具体实现代码如下:
package com.easipass.test; import java.util.List; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.telephony.NeighboringCellInfo; import android.telephony.TelephonyManager; import android.telephony.cdma.CdmaCellLocation; import android.telephony.gsm.GsmCellLocation; import android.util.Log; import android.view.View; /** * 功能描述:通过手机信号获取基站信息 * # 通过TelephonyManager 获取lac:mcc:mnc:cell-id * # MCC,Mobile Country Code,移动国家代码(中国的为460); * # MNC,Mobile Network Code,移动网络号码(中国移动为0,中国联通为1,中国电信为2); * # LAC,Location Area Code,位置区域码; * # CID,Cell Identity,基站编号; * # BSSS,Base station signal strength,基站信号强度。 * @author android_ls */ public class GSMCellLocationActivity extends Activity { private static final String TAG = "GSMCellLocationActivity"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 获取基站信息 findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { TelephonyManager mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); // 返回值MCC + MNC String operator = mTelephonyManager.getNetworkOperator(); int mcc = Integer.parseInt(operator.substring(0, 3)); int mnc = Integer.parseInt(operator.substring(3)); // 中国移动和中国联通获取LAC、CID的方式 GsmCellLocation location = (GsmCellLocation) mTelephonyManager.getCellLocation(); int lac = location.getLac(); int cellId = location.getCid(); Log.i(TAG, " MCC = " + mcc + "\t MNC = " + mnc + "\t LAC = " + lac + "\t CID = " + cellId); // 中国电信获取LAC、CID的方式 /*CdmaCellLocation location1 = (CdmaCellLocation) mTelephonyManager.getCellLocation(); lac = location1.getNetworkId(); cellId = location1.getBaseStationId(); cellId /= 16;*/ // 获取邻区基站信息 List<NeighboringCellInfo> infos = mTelephonyManager.getNeighboringCellInfo(); StringBuffer sb = new StringBuffer("总数 : " + infos.size() + "\n"); for (NeighboringCellInfo info1 : infos) { // 根据邻区总数进行循环 sb.append(" LAC : " + info1.getLac()); // 取出当前邻区的LAC sb.append(" CID : " + info1.getCid()); // 取出当前邻区的CID sb.append(" BSSS : " + (-113 + 2 * info1.getRssi()) + "\n"); // 获取邻区基站信号强度 } Log.i(TAG, " 获取邻区基站信息:" + sb.toString()); } }); } } |
在AndroidManifest.xml添加获取位置信息的权限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> |
点击“获取基站信息”的按钮后,Logcat的日志输出如下:
1、中国联通:
2、中国移动:
一、通过手机信号获取基站信息-单基站定位
TelephonyManager mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); // 返回值MCC + MNC String operator = mTelephonyManager.getNetworkOperator(); mcc = Integer.parseInt(operator.substring(0, 3)); mnc = Integer.parseInt(operator.substring(3)); // 中国移动和中国联通获取LAC、CID的方式 GsmCellLocation location = (GsmCellLocation) mTelephonyManager.getCellLocation(); lac = location.getLac(); cid = location.getCid(); Log.i(TAG, "MCC = " + mcc + "\t MNC = " + mnc + "\t LAC = " + lac + "\t CID = " + cid); |
二、调用第三方公开的API(根据基站信息查找基站的经纬度值及地址信息)
1、组拼JSON形式的请求参数
/** * 获取JSON形式的基站信息 * @param mcc 移动国家代码(中国的为460) * @param mnc 移动网络号码(中国移动为0,中国联通为1,中国电信为2); * @param lac 位置区域码 * @param cid 基站编号 * @return json * @throws JSONException */ private String getJsonCellPos(int mcc, int mnc, int lac, int cid) throws JSONException { JSONObject jsonCellPos = new JSONObject(); jsonCellPos.put("version", "1.1.0"); jsonCellPos.put("host", "maps.google.com"); JSONArray array = new JSONArray(); JSONObject json1 = new JSONObject(); json1.put("location_area_code", "" + lac + ""); json1.put("mobile_country_code", "" + mcc + ""); json1.put("mobile_network_code", "" + mnc + ""); json1.put("age", 0); json1.put("cell_id", "" + cid + ""); array.put(json1); jsonCellPos.put("cell_towers", array); return jsonCellPos.toString(); } |
2、通过HTTP协议网络请求源码:
request URL:http://www.minigps.net/minigps/map/google/location Request Method:POST Status Code:200 OK Request Headersview source Accept:application/json, text/javascript, */*; q=0.01 Accept-Charset:GBK,utf-8;q=0.7,*;q=0.3 Accept-Encoding:gzip,deflate,sdch Accept-Language:zh-CN,zh;q=0.8 Connection:keep-alive Content-Length:191 Content-Type:application/json; charset=UTF-8 Cookie:bdshare_firstime=1356366713546; JSESSIONID=68243935CD3355089CF07A3A22AAB372 Host:www.minigps.net Origin:http://www.minigps.net Referer:http://www.minigps.net/map.html User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4 X-Requested-With:XMLHttpRequest Request Payload {"cell_towers":[{"mobile_network_code":"1","location_area_code":"43018","cell_id":"11152773","age":0, "mobile_country_code":"460"}],"host":"maps.google.com","version":"1.1.0"} Response Headersview source Content-Type:application/json Date:Sat, 03 Jan 2013 14:03:15 GMT Server:Apache-Coyote/1.1 Transfer-Encoding:chunked |
3、用JAVA代码具体实现
/** * 调用第三方公开的API根据基站信息查找基站的经纬度值及地址信息 */ public String httpPost(String url, String jsonCellPos) throws IOException{ byte[] data = jsonCellPos.toString().getBytes(); URL realUrl = new URL(url); HttpURLConnection httpURLConnection = (HttpURLConnection) realUrl.openConnection(); httpURLConnection.setConnectTimeout(6 * 1000); httpURLConnection.setDoOutput(true); httpURLConnection.setDoInput(true); httpURLConnection.setUseCaches(false); httpURLConnection.setRequestMethod("POST"); httpURLConnection.setRequestProperty("Accept", "application/json, text/javascript, */*; q=0.01"); httpURLConnection.setRequestProperty("Accept-Charset", "GBK,utf-8;q=0.7,*;q=0.3"); httpURLConnection.setRequestProperty("Accept-Encoding", "gzip,deflate,sdch"); httpURLConnection.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8"); httpURLConnection.setRequestProperty("Connection", "Keep-Alive"); httpURLConnection.setRequestProperty("Content-Length", String.valueOf(data.length)); httpURLConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); httpURLConnection.setRequestProperty("Host", "www.minigps.net"); httpURLConnection.setRequestProperty("Referer", "http://www.minigps.net/map.html"); httpURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4X-Requested-With:XMLHttpRequest"); httpURLConnection.setRequestProperty("X-Requested-With", "XMLHttpRequest"); httpURLConnection.setRequestProperty("Host", "www.minigps.net"); DataOutputStream outStream = new DataOutputStream(httpURLConnection.getOutputStream()); outStream.write(data); outStream.flush(); outStream.close(); if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream inputStream = httpURLConnection.getInputStream(); return new String(read(inputStream)); } return null; } |
4、读取返回的JSON数据流代码:
/** * 读取IO流并以byte[]形式存储 * @param inputSream InputStream * @return byte[] * @throws IOException */ public byte[] read(InputStream inputSream) throws IOException { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); int len = -1; byte[] buffer = new byte[1024]; while ((len = inputSream.read(buffer)) != -1) { outStream.write(buffer, 0, len); } outStream.close(); inputSream.close(); return outStream.toByteArray(); } |
三、请求参数及返回结果的JSON形式:
1、请求的JSON参数值:
{ "cell_towers": [ { "mobile_network_code":"1", "location_area_code":"43018", "cell_id":"11152773", "age":0, "mobile_country_code":"460" } ], "host":"maps.google.com", "version":"1.1.0" } |
2、返回的JSON结果值:
{ "location": { "latitude":"31.211389541625977", "longitude":"121.60332489013672", "address": {"city": "上海市浦东新区居里路432号;浦东新区光启安老院、第一三共制药上海公司、SUNPLUS[附近]", "country":"", "country_code":"", "county":"", "postal_code":"", "region":"", "street":"", "street_number":"" } }, "access_token":"dummytoken" } |
四、完整代码及所需权限:
Java代码:
{ "location": { "latitude":"31.211389541625977", "longitude":"121.60332489013672", "address": {"city": "上海市浦东新区居里路432号;浦东新区光启安老院 、第一三共制药上海公司、SUNPLUS[附近]", "country":"", "country_code":"", "county":"", "postal_code":"", "region":"", "street":"", "street_number":"" } }, "access_token":"dummytoken" } |
在AndroidManifest.xml添加获取位置信息的权限:
package com.easipass.test; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.telephony.TelephonyManager; import android.telephony.gsm.GsmCellLocation; import android.util.Log; import android.view.View; /** * 功能描述:单基站定位 * @author android_ls */ public class GSMCellLocationActivity extends Activity { private static final String TAG = "GSMCellLocationActivity"; private int mcc; private int mnc; private int lac; private int cid; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 获取基站信息 findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { TelephonyManager mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); // 返回值MCC + MNC String operator = mTelephonyManager.getNetworkOperator(); mcc = Integer.parseInt(operator.substring(0, 3)); mnc = Integer.parseInt(operator.substring(3)); // 中国移动和中国联通获取LAC、CID的方式 GsmCellLocation location = (GsmCellLocation) mTelephonyManager.getCellLocation(); lac = location.getLac(); cid = location.getCid(); Log.i(TAG, "MCC = " + mcc + "\t MNC = " + mnc + "\t LAC = " + lac + "\t CID = " + cid); new Thread() { @Override public void run() { try { String json = getJsonCellPos(mcc, mnc, lac, cid); Log.i(TAG, "request = " + json); String url = "http://www.minigps.net/minigps/map/google/location"; String result = httpPost(url, json); Log.i(TAG, "result = " + result); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); } }); } /** * 调用第三方公开的API根据基站信息查找基站的经纬度值及地址信息 */ public String httpPost(String url, String jsonCellPos) throws IOException{ byte[] data = jsonCellPos.toString().getBytes(); URL realUrl = new URL(url); HttpURLConnection httpURLConnection = (HttpURLConnection) realUrl.openConnection(); httpURLConnection.setConnectTimeout(6 * 1000); httpURLConnection.setDoOutput(true); httpURLConnection.setDoInput(true); httpURLConnection.setUseCaches(false); httpURLConnection.setRequestMethod("POST"); httpURLConnection.setRequestProperty("Accept", "application/json, text/javascript, */*; q=0.01"); httpURLConnection.setRequestProperty("Accept-Charset", "GBK,utf-8;q=0.7,*;q=0.3"); httpURLConnection.setRequestProperty("Accept-Encoding", "gzip,deflate,sdch"); httpURLConnection.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8"); httpURLConnection.setRequestProperty("Connection", "Keep-Alive"); httpURLConnection.setRequestProperty("Content-Length", String.valueOf(data.length)); httpURLConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); httpURLConnection.setRequestProperty("Host", "www.minigps.net"); httpURLConnection.setRequestProperty("Referer", "http://www.minigps.net/map.html"); httpURLConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome /22.0.1229.94 Safari/537.4X-Requested-With:XMLHttpRequest"); httpURLConnection.setRequestProperty("X-Requested-With", "XMLHttpRequest"); httpURLConnection.setRequestProperty("Host", "www.minigps.net"); DataOutputStream outStream = new DataOutputStream(httpURLConnection.getOutputStream()); outStream.write(data); outStream.flush(); outStream.close(); if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream inputStream = httpURLConnection.getInputStream(); return new String(read(inputStream)); } return null; } /** * 获取JSON形式的基站信息 * @param mcc 移动国家代码(中国的为460) * @param mnc 移动网络号码(中国移动为0,中国联通为1,中国电信为2); * @param lac 位置区域码 * @param cid 基站编号 * @return json * @throws JSONException */ private String getJsonCellPos(int mcc, int mnc, int lac, int cid) throws JSONException { JSONObject jsonCellPos = new JSONObject(); jsonCellPos.put("version", "1.1.0"); jsonCellPos.put("host", "maps.google.com"); JSONArray array = new JSONArray(); JSONObject json1 = new JSONObject(); json1.put("location_area_code", "" + lac + ""); json1.put("mobile_country_code", "" + mcc + ""); json1.put("mobile_network_code", "" + mnc + ""); json1.put("age", 0); json1.put("cell_id", "" + cid + ""); array.put(json1); jsonCellPos.put("cell_towers", array); return jsonCellPos.toString(); } /** * 读取IO流并以byte[]形式存储 * @param inputSream InputStream * @return byte[] * @throws IOException */ public byte[] read(InputStream inputSream) throws IOException { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); int len = -1; byte[] buffer = new byte[1024]; while ((len = inputSream.read(buffer)) != -1) { outStream.write(buffer, 0, len); } outStream.close(); inputSream.close(); return outStream.toByteArray(); } } |
基站:类似于WIFI热点,官方解释,移动通信系统中,连接固定部分与无线部分,并通过空中的无线传输与移动台相连的设备。基站即公用移动通信基站是无线电台站的一种形式,是指在一定的无线电覆盖区中,通过移动通信交换中心,与移动电话终端之间进行信息传递的无线电收发信电台。
单基站定位是指:通过手机获取当前连接到的基站信息,来确定用户的大概位置(用户可能在某个基站(手机当前连接的基站)发出的无线电覆盖区域中)。
三基站或多基站:通过手机获取附近区域的基站信息(不是用户当前连接的基站,得到的是一组基站信息),来确定用户的大概位置。
获取邻区基站信息:
// 获取邻区基站信息 List<NeighboringCellInfo> infos = mTelephonyManager.getNeighboringCellInfo(); StringBuffer sb = new StringBuffer("总数 : " + infos.size() + "\n"); for (NeighboringCellInfo info1 : infos) { // 根据邻区总数进行循环 sb.append(" LAC : " + info1.getLac()); // 取出当前邻区的LAC sb.append(" CID : " + info1.getCid()); // 取出当前邻区的CID sb.append(" BSSS : " + (-113 + 2 * info1.getRssi()) + "\n"); // 获取邻区基站信号强度 } |
注:中国联通的基本上获取不到附近的基站,我测的时候使用的是中国移动。
一、探索:
1、我猜想请求参数的Json是这样组装的:
JSONObject json = new JSONObject(); json.put("version", "1.1.0"); json.put("host", "maps.google.com"); json.put("location_area_code", "6338"); json.put("mobile_country_code", "460"); json.put("mobile_network_code", "0"); json.put("age", 0); JSONArray array = new JSONArray(); JSONObject json1 = new JSONObject(); json1.put("cell_id", "62291"); json1.put("signal_strength", -95); array.put(json1); JSONObject json2 = new JSONObject(); json2.put("cell_id", "62290"); json2.put("signal_strength", -101); array.put(json2); json.put("cell_towers", array); |
2、组拼好的JSON字符串:
{ "mobile_network_code":"0", "location_area_code":"6338", "host":"maps.google.com", "cell_towers": [ { "signal_strength":-95, "cell_id":"62291" }, { "signal_strength":-101, "cell_id":"62290" } ], "age":0, "mobile_country_code":"460", "version":"1.1.0" } |
3、通过HTTP请求返回的JSON形式结果:
{ "location": { "latitude":"0.0", "longitude":"0.0", "address": { "city":"基站信息不存在,请从手机上读取正确的基站信息。", "country":"", "country_code":"" ,"county":"", "postal_code":"", "region":"", "street":"", "street_number":"" } }, "access_token":"dummytoken" } |
二、可行的方式:
1、通过单个附近的基站信息定位:
组装参数:
/** * 获取JSON形式的基站信息 * @param mcc 移动国家代码(中国的为460) * @param mnc 移动网络号码(中国移动为0,中国联通为1,中国电信为2); * @param lac 位置区域码 * @param cid 基站编号 * @param bsss 基站信号强度 * @return json * @throws JSONException */ private String getJsonCellPos(int mcc, int mnc, int lac, int cid, int bsss) throws JSONException { JSONObject jsonCellPos = new JSONObject(); jsonCellPos.put("version", "1.1.0"); jsonCellPos.put("host", "maps.google.com"); JSONArray array = new JSONArray(); JSONObject json1 = new JSONObject(); json1.put("location_area_code", "" + lac + ""); json1.put("mobile_country_code", "" + mcc + ""); json1.put("mobile_network_code", "" + mnc + ""); json1.put("age", 0); json1.put("cell_id", "" + cid + ""); json1.put("signal_strength", bsss); array.put(json1); jsonCellPos.put("cell_towers", array); return jsonCellPos.toString(); } |
请求的JSON字符串:
{ "cell_towers": [ { "mobile_network_code":"0", "location_area_code":"6338", "cell_id":"62291", "signal_strength":-95, "age":0, "mobile_country_code":"460" } ], "host":"maps.google.com", "version":"1.1.0" } |
返回JSON形式结果:
{ "location": {   ; "latitude":"31.214667405", "longitude":"121.59903152499999", &nbs p; "address": {   ; "city":" 上海市浦东新区郭守敬路;上海奥威科技开发公司、 科威国际技术转移中心公司、张江高科技园区热力中心[附近]", "country":"", "country_code":"",   ; "county":"",   ; "postal_code":"", "region":"", "street":"", "street_number":"" } }, "access_token":"dummytoken" } |
2、通过多个附近的基站信息定位:
又一次猜想:
请求JSON:
{ "cell_towers": [ { "mobile_network_code":"0", "location_area_code":"6338", "cell_id":"62291", "signal_strength":-95, "age":0, "mobile_country_code":"460" }, { "mobile_network_code":"0", "location_area_code":"6338", "cell_id":"62290", "signal_strength":-101, "age":1, "mobile_country_code":"460" } ], "host":"maps.google.com", "version":"1.1.0" } |
返回JSON:
{ "location": { "latitude":"31.21485922285714", "longitude":"121.59990774285711", "address": { "city":"上海市浦东新区郭守敬路276号;上海奥威科技开发公司、科威国际技术转移中心公司、 张江高科技园区热力中心[附近]", "country":"", "country_code":"", "county":"", "postal_code":"", "region":"", "street":"", "street_number":"" } }, "access_token":"dummytoken" } |
结论:第三方服务器端可能有限制,每次只接受JSONArray中的第一个元素。如果要想一次性查找附近多个基站的经纬度及所在的地址,就只能编写for循环,一次一次的访问第三方的服务器。
3、个人观点:所谓的三点定位或多点定位,只是让想知道用户当前位置的人多了一个选择而已。三点定位得到的是三个点,并非是一个比较准确的点。