本文实现的基本原是,在windows mobile带手机功能的手机通过RIL调用就可以获取到基站的编号、区域号、国家代码等信息,通过这些信息访问google提供的一个网址就可以返回该基站的经纬度。(本文参考了很多网上的资料)
在网上查看资料说是可以获取多个基站,但我一直不能实现,还有我在一款CDMA的手机也实现不了。
定义NativeMethods类,写入要调用的方法。
internal static class NativeMethods { //初始化RIL接口 [DllImport("ril.dll")] public static extern IntPtr RIL_Initialize(uint dwIndex, RILRESULTCALLBACK pfnResult, RILNOTIFYCALLBACK pfnNotify, uint dwNotificationClasses, uint dwParam, out IntPtr lphRil); //获取基站信息 [DllImport("ril.dll")] public static extern IntPtr RIL_GetCellTowerInfo(IntPtr hRil); //释放资源 [DllImport("ril.dll")] public static extern IntPtr RIL_Deinitialize(IntPtr hRil); //这个方法为最小化窗口时使用到的,非定位所需方法 [DllImport("coredll")] public static extern bool ShowWindow(IntPtr hwnd, int nCmdShow); }
定义接收基站信息结构和委托
public class RILCELLTOWERINFO { public uint cbSize; //字节。 public uint dwParams; //合法的参量。 必须是其中一个或RILCELLTOWERINFO参量常数的组合。 public uint dwMobileCountryCode; //国家或区域代码。中国的MCC为460 public uint dwMobileNetworkCode; //流动网络的代码。 public uint dwLocationAreaCode; //当前地点的区号。 public uint dwCellID; //多孔的塔的ID。 public uint dwBaseStationID; //基地的ID。 public uint dwBroadcastControlChannel;//广播控制通道(BCCH)。 public uint dwRxLevel; //被接受的信号电平。 public uint dwRxLevelFull; //在充分的网络的被接受的信号电平。 public uint dwRxLevelSub; //在子系统的被接受的信号质量。 public uint dwRxQuality; //被接受的信号质量。 public uint dwRxQualityFull; //在充分的网络的被接受的信号质量。 public uint dwRxQualitySub; //在子系统的被接受的信号质量。 public uint dwIdleTimeSlot; //无所事事的时隙。 public uint dwTimingAdvance; //时间前进。 public uint dwGPRSCellID; //GPRS多孔的塔的ID。 public uint dwGPRSBaseStationID; //GPRS基地的ID。 public uint dwNumBCCH; //BCCH的数量。 } public delegate void RILRESULTCALLBACK(uint dwCode, IntPtr hrCmdID, IntPtr lpData, uint cbData, uint dwParam); public delegate void RILNOTIFYCALLBACK(uint dwCode, IntPtr lpData, uint cbData, uint dwParam);
好现在就可以来实现获取基站信息了
System.IntPtr hRes; System.IntPtr hRil; private static AutoResetEvent waithandle = new AutoResetEvent(false); private static RILCELLTOWERINFO rilCellTowerInfo; private void GetCellInfo_Click(object sender, EventArgs e) { //获取手机CellID hRes = NativeMethods.RIL_Initialize(1, new RILRESULTCALLBACK(rilResultCallback), null, 0, 0, out hRil); NativeMethods.RIL_GetCellTowerInfo(hRil); //等待回调函数返回 waithandle.WaitOne(); //释放RIL handle NativeMethods.RIL_Deinitialize(hRil); } public static void rilResultCallback(uint dwCode, IntPtr hrCmdID, IntPtr lpData, uint cbData, uint dwParam) { //构造一个RILCELLTOWERINFO类用于存放数据 rilCellTowerInfo = new RILCELLTOWERINFO(); Marshal.PtrToStructure(lpData, rilCellTowerInfo); //回调通知 waithandle.Set(); }
获取时会卡一小会,建议把这部分放入单独的线程中。
获取到基站后就使用google来查询出经纬度了。
访问google进行查询的类
/// <summary> /// LocationService 的摘要说明 /// </summary> public class LocationService { public static string ErrorMessage; public LocationService(string postData) { GetLocationInfomation(postData); } /// <summary> /// 返回经纬度信息 /// 格式如下: /// 22.506421,113.918245|22.497636,113.912647|22.496063,113.91121 /// </summary> /// <param name="postData"></param> /// <returns></returns> public string GetLocationInfomation(string postData) { List<CellInfo> list = GetCellInfos(postData); StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.Count; i++) { CellInfo info = list[i]; //基本步骤 //1. 生成发往google的json串 //2. 接收google返回的json串 //3. 解析json串,只取得经纬度 //4. 拼接经纬度 string json = GenerateRequestJson(info); string content = GetResponseJson(json); string latLon = ParseResponseJson(content); sb.Append(latLon); sb.Append("|"); } return sb.ToString().Substring(0, sb.Length - 1); //return sb.ToString(); } /// <summary> /// 接收从手机端发送过来的数据 /// '|'分割对象,','分割属性 /// </summary> /// <param name="postData"></param> /// <returns></returns> private List<CellInfo> GetCellInfos(string postData) { string[] strInfos = postData.Split('|'); List<CellInfo> list = new List<CellInfo>(); for (int i = 0; i < strInfos.Length; i++) { string[] properties = strInfos[i].Split(','); CellInfo info = new CellInfo(); info.CID = properties[0]; info.LAC = properties[1]; info.MCC = properties[2]; info.MNC = properties[3]; list.Add(info); } return list; } /// <summary> /// 发送一个基站信息,并返回一个位置信息 /// 位置信息是以json串的形式存在 /// 需要对json串进行解析 /// </summary> /// <param name="requestJson"></param> private string GetResponseJson(string requestJson) { string responseJson = string.Empty; try { ServicePointManager.Expect100Continue = false; System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); byte[] data = encoding.GetBytes(requestJson); HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(@"http://www.google.com/loc/json"); // myRequest.Timeout = 5000; // myRequest.Proxy = null; myRequest.Method = "POST"; myRequest.ContentType = "application/requestJson"; myRequest.ContentLength = data.Length; Stream newStream = myRequest.GetRequestStream(); // Send the data. newStream.Write(data, 0, data.Length); newStream.Close(); // Get response JSON string HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse(); StreamReader reader = new StreamReader(myResponse.GetResponseStream(), System.Text.Encoding.Default); responseJson = reader.ReadToEnd(); myResponse.Close(); } catch(Exception ex) { string pp = ex.Message; } return responseJson; } /// <summary> /// 解析从google Response的JSON串,获取经纬度 /// </summary> /// <param name="responseJson"></param> /// <returns></returns> private string ParseResponseJson(string responseJson) { StringBuilder latLon = new StringBuilder(); JObject obj = JObject.Parse(responseJson); string lat = obj["location"]["latitude"].ToString(); string lon = obj["location"]["longitude"].ToString(); latLon.Append(lat); latLon.Append(","); latLon.Append(lon); return latLon.ToString(); //return responseJson; } /// <summary> /// 生成发往http://www.google.com/loc/json的json串 /// 仅仅只有一个基站 /// </summary> /// <param name="info"></param> /// <returns></returns> private string GenerateRequestJson(CellInfo info) { string json = ""; json += "{"; json += "/"version/":/"1.1.0/"" + ","; json += "/"host/":/"maps.google.com/"" + ","; json += "/"cell_towers/":["; json += "{"; json += "/"cell_id/":" + info.CID + ","; json += "/"location_area_code/":" + info.LAC + ","; json += "/"mobile_country_code/":" + info.MCC + ","; json += "/"mobile_network_code/":" + info.MNC; json += "}"; json += "],"; json += "/"wifi_towers/": [{}]"; json += "}"; return json; } }
里面我引用了,using Newtonsoft.Json.Linq;
这个程序集是用于json的解析,可以在网上下载得到,稍后也会在csdn的下载添加一个下载连接。
写好后使用它就非常简单了
string postData=rilCellTowerInfo.dwCellID.ToString() + "," +
rilCellTowerInfo.dwLocationAreaCode.ToString() + "," +
rilCellTowerInfo.dwMobileCountryCode.ToString() + "," +
"1";
LocationService service = new LocationService(postData);
string _location = service.GetLocationInfomation(postData);
这个_location就是转换出来的经纬度。
再次建议写在线程里。因为转换需要1-几秒钟的时间。
由于项目有其它功能,就不把源文件上传上来了。但其它有关的代码都已经在文章中了。
如何有人知道多基站定位的,也请您指导一下。谢谢!