首页 > android > android基站定位

android基站定位

最近各种蛋疼事,所以已经很久没有写文章了。今天就谈谈关于基站定位方面我的了解吧。

以前一直以为,基站定位就跟网络定位是一回事。但最近才明白,原来两者还是有点差别的。

首先,网络定位主要是通过wifi热点的位置来确定手机的位置,这个手机上有设置“使用无线网络确定位置”的选项,至于具体它是通过什么方式来确定位置的(IP?),就不太了解了;而基站定位,是通过移动运营商的基站的来定位的,主要手段是获取手机当前连接的基站,然后通过基站的数据库查找当前用户所处的大概位置。这些基站位置的数据库貌似只有运营商有,但是谷歌通过某些手段,也掌握了基站的位置。

基站定位和网络定位一样,精度跟GPS没得比,但是定位速度更快,更适合在室内定位。另外,感觉基站定位比网络定位还是会快一点的~

过程大概如下:

1.先获得TelephonyManager ,用户获取当前用户所处的基站信息。

TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Service.TELEPHONY_SERVICE);

2.需要确定用户用的是哪种网络,是CDMA还是GSM(这里主要是说2G的网络,3G的网络可能还要做另外的处理)。如果是CDMA网络,我参考的是这个博客说的,但手头上没有CDMA的机器,没有测试能不能;如果是GSM网络,就通过谷歌的API发送请求获取信息。

private int getPhoneInfo() {
    //CellLocation location = null;
    //mcc是指Mobile Country Code,移动国家代码,中国是460
    mcc = Integer.valueOf(mTelephonyManager.getNetworkOperator().substring(0, 3));
    //mnc是指Mobile Network Code,移动网络号码,移动是00,联通是01
    mnc = Integer.valueOf(mTelephonyManager.getNetworkOperator().substring(3, 5));

    //获取网络类型
    type = mTelephonyManager.getNetworkType();
    //如果是CDMA网络
    if(type == TelephonyManager.NETWORK_TYPE_1xRTT || type == TelephonyManager.NETWORK_TYPE_CDMA || 
        type == TelephonyManager.NETWORK_TYPE_EVDO_A) {
        CdmaCellLocation location = (CdmaCellLocation)mTelephonyManager.getCellLocation();
        double lat = (double)location.getBaseStationLatitude() / 14400;
        double lng = (double)location.getBaseStationLongitude() / 14400;
        mLocation = new Location(LocationManager.NETWORK_PROVIDER);
        mLocation.setLatitude(lat);
        mLocation.setLongitude(lng);

        return CDMA;
    }
    //如果是GSM网络
    else if(type == TelephonyManager.NETWORK_TYPE_EDGE || type == TelephonyManager.NETWORK_TYPE_GPRS) {
        GsmCellLocation location = (GsmCellLocation)mTelephonyManager.getCellLocation();
        cellId = location.getCid();    //cid是指Cell Identity,基站编号,是一个16位的数据
        lac = location.getLac();       //lac是指Location Area Code,位置区域码
        return GSM;
    }
    return -1;
}

3.GSM网络获取了获取了mnc、mcc、cid、lac这些手机信息以后,就可以构造json,往谷歌的服务器发post请求获取数据,返回的结果也是一个json。谷歌API的地址是:http://www.google.com/loc/json

/**
 * GSM网络获取基站位置的方法
 *
 * @return	返回location
 */
private Location getGSMLocation() {
        //先构建一个参数的json
	JSONObject object = new JSONObject();
	try {
		object.put("version", "1.1.0");
		object.put("host", "maps.google.com");
		object.put("request_address", true);
		if(mcc == 460)
			object.put("address_language", "zh_CN");
		else
			object.put("address_language", "en_US");

		JSONArray jArray = new JSONArray();
		JSONObject jObject = new JSONObject();
		jObject.put("cell_id", cellId);
		jObject.put("location_area_code", lac);
		jObject.put("mobile_country_code", mcc);
		jObject.put("mobile_network_code", mnc);
		jArray.put(jObject);
		object.put("cell_towers", jArray);

		//使用post方法想服务器发送请求,获得结果
		String json = Post(SERVER_URL, object);
		if(json == null)
			return null;

		//解析出当前的location和地址信息
		JSONObject result = new JSONObject(json);
		Location loc = new Location(LocationManager.NETWORK_PROVIDER);
		if(result != null) {
			//获得location的经纬度和精度
			JSONObject locationObject = result.getJSONObject("location");
			loc.setLatitude((Double)locationObject.get("latitude"));
			loc.setLongitude((Double)locationObject.get("longitude"));
			loc.setAccuracy(Float.parseFloat(locationObject.getString("accuracy")));
			loc.setTime(GetUTCTime());
			mLocation = loc;

			//获取地址信息
			JSONObject  addressObject = locationObject.getJSONObject("address");
			addressString = addressObject.getString("country") + addressObject.getString("region") + addressObject.getString("city") +
					addressObject.getString("street");
		}
		return mLocation;
	} catch (JSONException e1) {
		// TODO Auto-generated catch block
		e1.printStackTrace();
		Log.e("yong", "JSON error");
	}
	return null;
}

 

/**
 * 发送post请求
 *
 * @param url				服务器的地址
 * @param params		要发送的json
 * @return
 */
private String Post(String url, JSONObject params) {
	StringEntity entity;
	try {
		entity = new StringEntity(params.toString());

		Log.e("yong", params.toString());

		DefaultHttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost(url);
		post.setEntity(entity);

		HttpResponse response = client.execute(post);
		HttpEntity httpEntity = response.getEntity();

		BufferedReader reader = new BufferedReader(new InputStreamReader(httpEntity.getContent()));
		StringBuffer buffer = new StringBuffer();
		String line = null;
		while((line = reader.readLine()) != null) {
			buffer.append(line);
		}

		if(buffer.length() > 0)  {
			Log.e("yong", buffer.toString());
			return buffer.toString();
		}
		else
			return null;
	} catch (UnsupportedEncodingException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	return null;
}

从上面两段代码可以看出,发送json的格式是:

{"address_language":"zh_CN",
 host":"maps.google.com",
 "cell_towers":[{
	"mobile_network_code":0,
	"location_area_code":9442,
	"mobile_country_code":460,
	"cell_id":29325}],
"request_address":true,
"version":"1.1.0"}

接收到的数据的json格式是:

{"location":{
	"latitude":23.0603079,
	"longitude":113.3825974,
	"address":{
		"country":"中国",
		"country_code":"CN",
		"region":"广东省",
		"city":"广州市",
		"street":"官洲隧道"},
	"accuracy":657.0},
"access_token":"2:q4Pi37cjPgd8A1rH:H03rY0xNCk6v5FXX"}

4.最后也是最重要的一点就是,记得在manifest.xml中加入相应的权限

<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION”/>
<uses-permission android:name=”android.permission.INTERNET”/>
<uses-permission android:name=”android.permission.READ_PHONE_STATE”/>

 

最后说一下,这个其实还跟我所理解的基站定位有点区别的,我觉得基站定位就是不用联网就可以获取位置的,就像GPS那样。于是理所当然地想到了如果有离线数据库的支持,这个是可以实现的,因为这个联网也是让谷歌帮我们查数据库而已,而这移动通信的基站位置在一定时期内也是固定不变的。搜了一下发现,这样的数据库确实是存在的,但要付费使用的。不过联网其实也问题不大 ,因为现在用到定位的很大一部分是网络软件,如LBS社交之类的,不联网不就是坑爹。。。

 

该类的源码下载:

CellStationLocation

分类: android 标签: , ,