在网上收集了一部分关于使用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-CN/apis/maps/documentation/staticmaps/
http://www.codeproject.com/KB/mobile/DeepCast.aspx
http://heresy.spaces.live.com/blog/cns!E0070FB8ECF9015F!7866.entry?wa=wsignin1.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 上面都不是必须被实现的
下面是我的代码和注释,有些地方还是不能理解:
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)
{
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 */
///
/// 通过基站信息获取经纬度
///
///
///
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两个参数就可以获取经纬度的方法:
2 /// 判断是否正确获取经纬度信息
3 ///
4 /// cellid
5 /// LocationAreaCode
6 /// latitude
7 /// longgitude
8 ///
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控件,添加一个按键代码如下:
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 进行手机基站定位,精度较高的方法,请告诉我,本人不胜感激啊!