在网上收集了一部分关于使用Google API进行手机定位的资料和大家分享

来源:互联网 发布:有机化学软件 编辑:程序博客网 时间:2024/05/01 13:45

在网上收集了一部分关于使用Google API进行手机定位的资料和大家分享:

关于基站定位方面的介绍:

http://tech.c114.net/164/a140837.html

开发方面的帮助:

http://www.dotblogs.com.tw/kylin/archive/2009/08/09/9964.aspx

http://code.google.com/intl/zh-C ... ntation/staticmaps/

http://www.codeproject.com/KB/mobile/DeepCast.aspx

http://heresy.spaces.live.com/bl ... .0&sa=334916734

以上方法的流程一般如下:

通过RIL获取CellTowerInfo----->通过google api获取经纬度------->转换成54或是地方坐标后在地图上显示位置



本人整理了代码进行了测试,效果不是很好,使用的多普达S700,windows mobile 专业版 6.1 ,地点在上海,

定位结果如下

CELLID=1346
LAC=43060
MCC=460
MNC=0

从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(',', '.') + "&center=,&size=240x320&zoom=18");
13             webBrowser1.Navigate(url);
14             Cursor.Current = Cursors.Default;