C# 使用Google API进行手机基站定位资料整理在网上收集了一部分关于使用Google API进行手机定位的资料和大家分享: 关于基站定位方面的介绍: 开发方面的帮助: http://www./kylin/archive/2009/08/09/9964.aspx http://code.google.com/intl/zh-CN/apis/maps/documentation/staticmaps/ http://www./KB/mobile/DeepCast.aspx http://heresy.spaces./blog/cns!E0070FB8ECF9015F!7866.entry?wa=wsignin1.0&sa=334916734 以上方法的流程一般如下: 通过RIL获取CellTowerInfo----->通过google api获取经纬度------->转换成54或是地方坐标后在地图上显示位置
本人整理了代码进行了测试,效果不是很好,使用的多普达S700,windows mobile 专业版 6.1 ,地点在上海, 定位结果如下 CELLID=1346 从google获取的坐标31.109,121.368,定位位置到了莘西路上 经过计算与实际位置直线距离在8KM左右
而通过Google Maps在手机上测试当前位置提示精度为18000m,呵呵,这个精度恐怕只能确定在那个城市了,个人认为:原因可能有以下几点: 1.周围基站分布较少或是真的很远,上海的移动2G基站每年的数量都在减少,有时在公司的时候都会出现盲区,信号不是很好 2.直接通过cellid,lac,mcc,mnc等信息在Google上获取的经纬度没有经过误差分析,没有太大的精度可言 3.绕开中国移动运营商进行手机基站定位比较难,人家要靠这个赚钱的,当然也牵涉到国家安全,呵呵 4.RIL相关函数严格来说在Windows Mobile 上面都不是必须被实现的 下面是我的代码和注释,有些地方还是不能理解:
1 public class RIL 2 { 3 //CellTower信息 4 private static string celltowerinfo = ""; 5 6 //通过RIL获取CellID 7 public static string GetCellTowerInfo() 8 { 9 //初始化句柄 10 IntPtr hRil = IntPtr.Zero; 11 IntPtr hRes = IntPtr.Zero; 12 13 //初始化结果变量 14 celltowerinfo = ""; 15 16 //为一个Client初始化RIL 17 hRes = RIL_Initialize(1, 18 new RILRESULTCALLBACK(rilResultCallBack), 19 null, 20 0, 21 0, 22 out hRil); 23 24 if (hRes != IntPtr.Zero) 25 { 26 return "不能初始化RIL"; 27 } 28 29 //获取当前Phone使用的基站信息 30 hRes = RIL_GetCellTowerInfo(hRil); 31 32 waithandle.WaitOne(); 33 34 //解除RIL 35 RIL_Deinitialize(hRil); 36 37 return celltowerinfo; 38 39 40 } 41 42 private static AutoResetEvent waithandle = new AutoResetEvent(false); 43 44 public static void rilResultCallBack(uint dwCode, 45 IntPtr hrCmdID, 46 IntPtr lpData, 47 uint cdData, 48 uint dwParam) 49 { 50 RILCELLTOWERINFO rilCellTowerInfo = new RILCELLTOWERINFO(); 51 52 //将数据lpData从非托管内存块封送到rilCellTowerInfo托管对象中 53 Marshal.PtrToStructure(lpData, rilCellTowerInfo); 54 55 celltowerinfo = rilCellTowerInfo.dwCellID + "-" + rilCellTowerInfo.dwLocationAreaCode + "-" + 56 rilCellTowerInfo.dwMobileCountryCode+"-"+rilCellTowerInfo.dwMobileNetworkCode; 57 58 //将事件状态设置为终止状态,允许一个或多个等待线程继续 59 waithandle.Set(); 60 } 61 62 public delegate void RILRESULTCALLBACK(uint dwCode,IntPtr hrCmdID,IntPtr lpData,uint cbData,uint dwParam); 63 64 public delegate void RILNOTIFYCALLBACK(uint dwCode,IntPtr lpData,uint cbData,uint dwParam); 65 66 //RIL基站信息类 67 public class RILCELLTOWERINFO 68 { 69 public uint cbSize; 70 public uint dwParams; 71 public uint dwMobileCountryCode; 72 public uint dwMobileNetworkCode; 73 public uint dwLocationAreaCode; 74 public uint dwCellID; 75 public uint dwBaseStationID; 76 public uint dwBroadcastControlChannel; 77 public uint dwRxLevel; 78 public uint dwRxLevelFull; 79 public uint dwRxLevelSub; 80 public uint dwRxQuality; 81 public uint dwRxQualityFull; 82 public uint dwRxQualitySub; 83 public uint dwIdleTimeSlot; 84 public uint dwTimingAdvance; 85 public uint dwGPRSCellID; 86 public uint dwGPRSBaseStationID; 87 public uint dwNumBCCH; 88 89 90 } 91 92 /* 调用API 93 * 初始化RIL 94 * MSDN: http://msdn.microsoft.com/zh-cn/library/aa919106(en-us).aspx */ 95 [DllImport("ril.dll")] 96 private static extern IntPtr RIL_Initialize(uint dwIndex, RILRESULTCALLBACK pfnResult, RILNOTIFYCALLBACK pfnNotify, uint dwNotificationClasses, uint dwParam, out IntPtr lphRil); 97 [DllImport("ril.dll")] 98 private static extern IntPtr RIL_GetCellTowerInfo(IntPtr hRil); 99 [DllImport("ril.dll")] 100 private static extern IntPtr RIL_Deinitialize(IntPtr hRil); 101 102 }
之后是有关通信方面的,通过基站信息获取经纬度(GOOGLE API)
代码
public class GMM { static byte[] PostData(int MCC, int MNC, int LAC, int CID, bool shortCID) { byte[] pd = new byte[]{ 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, // Offset 0x11 0x00, 0x00, 0x00, 0x00, // Offset 0x15 0x00, 0x00, 0x00, 0x00, // Offset 0x19 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Offset 0x1f 0x00, 0x00, 0x00, 0x00, // Offset 0x23 0x00, 0x00, 0x00, 0x00, // Offset 0x27 0x00, 0x00, 0x00, 0x00, // Offset 0x2b 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }; bool isUMTSCell = ((Int64)CID > 65535); if (isUMTSCell) Console.WriteLine("UMTS CID.{0}", shortCID ? "Using short CID to resolve." : ""); else Console.WriteLine("GSM CID given."); if (shortCID) CID &= 0xFFFF; /* Attempt to resolve the cell using the if ((Int64)CID > 65536) /* GSM: 4 hex digits, UTMS: 6 hex digits */ if ((Int64)CID > 65536) pd[0x1c] = 5; else pd[0x1c] = 3; pd[0x11] = (byte)((MNC >> 24) & 0xFF); pd[0x12] = (byte)((MNC >> 16) & 0xFF); pd[0x13] = (byte)((MNC >> 8) & 0xFF); pd[0x14] = (byte)((MNC >> 0) & 0xFF); pd[0x15] = (byte)((MCC >> 24) & 0xFF); pd[0x16] = (byte)((MCC >> 16) & 0xFF); pd[0x17] = (byte)((MCC >> 8) & 0xFF); pd[0x18] = (byte)((MCC >> 0) & 0xFF); pd[0x27] = (byte)((MNC >> 24) & 0xFF); pd[0x28] = (byte)((MNC >> 16) & 0xFF); pd[0x29] = (byte)((MNC >> 8) & 0xFF); pd[0x2a] = (byte)((MNC >> 0) & 0xFF); pd[0x2b] = (byte)((MCC >> 24) & 0xFF); pd[0x2c] = (byte)((MCC >> 16) & 0xFF); pd[0x2d] = (byte)((MCC >> 8) & 0xFF); pd[0x2e] = (byte)((MCC >> 0) & 0xFF); pd[0x1f] = (byte)((CID >> 24) & 0xFF); pd[0x20] = (byte)((CID >> 16) & 0xFF); pd[0x21] = (byte)((CID >> 8) & 0xFF); pd[0x22] = (byte)((CID >> 0) & 0xFF); pd[0x23] = (byte)((LAC >> 24) & 0xFF); pd[0x24] = (byte)((LAC >> 16) & 0xFF); pd[0x25] = (byte)((LAC >> 8) & 0xFF); pd[0x26] = (byte)((LAC >> 0) & 0xFF); return pd; } //GSM CID part */ /// <summary> /// 通过基站信息获取经纬度 /// </summary> /// <param name="args"></param> /// <returns></returns> static public string GetLatLng(string[] args) { if (args.Length < 4) { return string.Empty; } string shortCID = ""; /* Default, no change at all */ if (args.Length == 5) shortCID = args[4].ToLower(); try { String url = "http://www.google.com/glm/mmap"; HttpWebRequest req = (HttpWebRequest)WebRequest.Create( new Uri(url)); req.Method = "POST"; int MCC = Convert.ToInt32(args[0]); int MNC = Convert.ToInt32(args[1]); int LAC = Convert.ToInt32(args[2]); int CID = Convert.ToInt32(args[3]); byte[] pd = PostData(MCC, MNC, LAC, CID, shortCID == "shortcid"); req.ContentLength = pd.Length; req.ContentType = "application/binary"; Stream outputStream = req.GetRequestStream(); outputStream.Write(pd, 0, pd.Length); outputStream.Close(); HttpWebResponse res = (HttpWebResponse)req.GetResponse(); byte[] ps = new byte[res.ContentLength]; int totalBytesRead = 0; while (totalBytesRead < ps.Length) { totalBytesRead += res.GetResponseStream().Read( ps, totalBytesRead, ps.Length - totalBytesRead); } if (res.StatusCode == HttpStatusCode.OK) { short opcode1 = (short)(ps[0] << 8 | ps[1]); byte opcode2 = ps[2]; int ret_code = (int)((ps[3] << 24) | (ps[4] << 16) | (ps[5] << 8) | (ps[6])); if (ret_code == 0) { double lat = ((double)((ps[7] << 24) | (ps[8] << 16) | (ps[9] << 8) | (ps[10]))) / 1000000; double lon = ((double)((ps[11] << 24) | (ps[12] << 16) | (ps[13] << 8) | (ps[14]))) / 1000000; return lat + "|" + lon; } else return string.Empty; } else return string.Empty; } catch (Exception ex) { MessageBox.Show(ex.ToString()); return string.Empty; } } }
下面在介绍一种只要知道cellid和lac两个参数就可以获取经纬度的方法:
1 /// <summary> 2 /// 判断是否正确获取经纬度信息 3 /// </summary> 4 /// <param name="cellid">cellid</param> 5 /// <param name="lac">LocationAreaCode</param> 6 /// <param name="Lat">latitude</param> 7 /// <param name="Lng">longgitude</param> 8 /// <returns></returns> 9 public static bool LocateGooleMapApi(uint cellid, uint lac, out double Lat, out double Lng) 10 { 11 HttpWebRequest request =(HttpWebRequest)WebRequest.Create("http://www.google.com/glm/mmap"); 12 request.Method = "POST"; 13 14 15 byte[] byteArray = {0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02, 16 0x65, 0x6E, // en 17 0x00, 0x07, 18 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 19 0x00, 0x03, 20 0x31, 0x2E, 0x30, // 1.0 21 0x00, 0x03, 22 0x57, 0x65, 0x62, // web 23 0x1B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 24 0x00,0x00,0x00,0x00,0x03,0x00,0x00, 25 0xFF, 0xFF, 0xFF, 0xFF, // CellID 26 0xFF, 0xFF, 0xFF, 0xFF, // LAC 27 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 28 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; 29 30 // write CellID 31 byte[] intByte = BitConverter.GetBytes(cellid); 32 byteArray[48] = intByte[3]; 33 byteArray[49] = intByte[2]; 34 byteArray[50] = intByte[1]; 35 byteArray[51] = intByte[0]; 36 37 // write LAC 38 intByte = BitConverter.GetBytes(lac); 39 byteArray[52] = intByte[3]; 40 byteArray[53] = intByte[2]; 41 byteArray[54] = intByte[1]; 42 byteArray[55] = intByte[0]; 43 44 // set request 45 request.ContentLength = byteArray.Length; 46 Stream postStream = request.GetRequestStream(); 47 postStream.Write(byteArray, 0, byteArray.Length); 48 postStream.Close(); 49 50 // Get the response. 51 HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 52 Console.WriteLine("[I] Request response: {0}", response.StatusDescription); 53 54 // Read response 55 Stream dataStream = response.GetResponseStream(); 56 BinaryReader BR = new BinaryReader(dataStream); 57 // skip 3 byte 58 BR.ReadByte(); 59 BR.ReadByte(); 60 BR.ReadByte(); 61 62 // check state 63 if (0 == BR.ReadInt32()) 64 { 65 // read lat 66 byte[] tmpByte = new byte[4]; 67 tmpByte[3] = BR.ReadByte(); 68 tmpByte[2] = BR.ReadByte(); 69 tmpByte[1] = BR.ReadByte(); 70 tmpByte[0] = BR.ReadByte(); 71 Lat = (double)(BitConverter.ToInt32(tmpByte, 0)) / 1000000D; 72 73 // read lng 74 tmpByte[3] = BR.ReadByte(); 75 tmpByte[2] = BR.ReadByte(); 76 tmpByte[1] = BR.ReadByte(); 77 tmpByte[0] = BR.ReadByte(); 78 Lng = (double)(BitConverter.ToInt32(tmpByte, 0)) / 1000000D; 79 80 BR.Close(); 81 dataStream.Close(); 82 response.Close(); 83 return true; 84 } 85 else 86 { 87 BR.Close(); 88 dataStream.Close(); 89 response.Close(); 90 Lat = 0; 91 Lng = 0; 92 return false; 93 } 94 95 96 }
最后只要用C#2008 建立一个新项目,添加webbrowser控件,添加一个按键代码如下:
1 Cursor.Current = Cursors.WaitCursor; 2 string [] cellidFields = RIL.GetCellTowerInfo().ToString().Split('-'); 3 4 string[] args ={ 5 cellidFields[2], 6 "0", 7 cellidFields[1], 8 cellidFields[0] 9 }; 10 string[] latlng = GMM.GetLatLng(args).Split('|'); 11 12 Uri url = new Uri("http://maps.google.com/staticmap?&maptype=satellite&key=xxx&markers=" + latlng[0].ToString().Replace(',', '.') + "," + latlng[1].ToString().Replace(',', '.') + "¢er=,&size=240x320&zoom=18"); 13 webBrowser1.Navigate(url); 14 Cursor.Current = Cursors.Default;
就只有这些了,如果谁有更好的利用GOOGLE 进行手机基站定位,精度较高的方法,请告诉我,本人不胜感激啊! |
|