技术开发 频道

如何在任何手机上找到GPS定位

        【IT168技术】前一段时间,我曾在另一篇文章提到,我想采取的位置广播思想,开发后续移动解决方案。当时的问题是我没有办法摆脱手机来获取位置信息,或者使位置数据变得有用的一种方法。在这篇文章中,我将演示如何让你的手机获取GPS坐标.即使您的手机没有内置的全球定位系统。

  定位为什么如此的困难?

  电话技术成熟的速度是惊人的。目前有一大批手机都内置了全球定位系统,“智能”手机有数百人的平均价格标签,而我们大多数人没有争先购买以更换我们目前的手机。事实上,全球定位系统还不包括无处不在的位置,这是真正的困难。我们的目标是让手机获得任何地点的位置,不只是GPS功能的手机。困难就在于此。

  谷歌能做到,为什么我们不能?

  如果您尚未与谷歌的移动地图进行比赛,我强烈推荐它。这实在是一种方便的小应用程序,尤其是当您在旅途中,需要你的地图时。但是,在我的电话中也有移动地图的作品,而我并没有全球定位系统。这怎么可能?在没有全球定位系统的情况下,谷歌利用普通手机的数据通过他们的手机地图已经找到了如何确定您的位置。也就是说,没有全球定位系统的情况下,寻找位置是可能的。事实上,让我们先来解构谷歌移动地图工程的项目,并用C#构建它备份。

  协议分析

  我不打算在此详述有关协议或数据包分析器(我使用Microsoft网络监视器)。我只想说,第一步解构谷歌手机地图是分析HTTP请求,而手机地图是通过ActiveSync运行。

  快速浏览移动地图揭示了几件事情。首先,谷歌发布请求http://www.google.com/glm/mmap的位置数据。我已经冲刷了它们的API。这意味着,我们正在寻找自己如何包装和发送数据。其次,他们的数据发送四个关键部分:

  1、Cell Tower编号

  2、位置区码(LAC)

  3、移动网络代码(MNC)

  4、移动国家代码(MCC)

  这是个好消息!事实证明,几乎所有的手机都具有这样随时可用的数据。

  Cell Tower数据-无线接口层

  我们需要破解打开Windows Mobile无线接口层Cell塔获取数据。此外,您可以从MSDN 搜索RIL来获取整个RIL 库的细节。我们只关心RIL的Cell Tower端口部分。我们首先需要做的是添加必要的PInvoke DLL Import签名,调用无线接口层。

  代码片段:

1 [DllImport("ril.dll")]
2
3   private static extern IntPtr RIL_Initialize(uint dwIndex, RILRESULTCALLBACK pfnResult,
4
5   RILNOTIFYCALLBACK pfnNotify, uint dwNotificationClasses,
6
7   uint dwParam, out IntPtr lphRil);
8
9   [DllImport("ril.dll", EntryPoint = "RIL_GetCellTowerInfo")]
10
11   private static extern IntPtr RIL_GetCellTowerInfo(IntPtr hRil);
12
13   [DllImport("ril.dll", EntryPoint = "RIL_Hangup")]
14
15   private static extern IntPtr RIL_Hangup(IntPtr hRil);
16
17   [DllImport("ril.dll")]
18
19   private static extern IntPtr RIL_Deinitialize(IntPtr hRil);
20
21

  这四个方法包含在ril.dll中,是我们获得Cell Tower数据的通路。有了这些方法,以及他们的回调RILRESULTCALLBACK和RILNOTIFYCALLBACK结构,我们可以很容易地调用Windows 窗口来获得我们的Cell Tower 数据。

  代码片段:

1 public static CellTower GetCellTowerInfo()
2
3   {
4
5   IntPtr radioInterfaceLayerHandle = IntPtr.Zero;
6
7   IntPtr radioResponseHandle = IntPtr.Zero;
8
9   // Initialize the radio layer with a result callback parameter.
10
11   radioResponseHandle = RIL_Initialize(1, new RILRESULTCALLBACK(CellDataCallback),
12
13   null, 0, 0, out radioInterfaceLayerHandle);
14
15   // The initialize API call will always return 0 if initialization is successful.
16
17   if (radioResponseHandle != IntPtr.Zero)
18
19   {
20
21   return null;
22
23   }
24
25   // Query for the current tower data.
26
27   radioResponseHandle = RIL_GetCellTowerInfo(radioInterfaceLayerHandle);
28
29   // Wait for cell tower info to be returned since RIL_GetCellTowerInfo invokes the
30
31   // callback method asynchronously.
32
33   waithandle.WaitOne();
34
35   // Release the RIL handle
36
37   RIL_Deinitialize(radioInterfaceLayerHandle);
38
39   // Convert the raw tower data structure data into a CellTower object
40
41   return new CellTower()
42
43   {
44
45   TowerId = Convert.ToInt32(_towerDetails.dwCellID),
46
47   LocationAreaCode = Convert.ToInt32(_towerDetails.dwLocationAreaCode),
48
49   MobileCountryCode = Convert.ToInt32(_towerDetails.dwMobileCountryCode),
50
51   MobileNetworkCode = Convert.ToInt32(_towerDetails.dwMobileNetworkCode),
52
53   };
54
55   }
56
57

  现在,我们可以调用GetCellTowerInfo(),我们将得到强类型CellTower类以及所有细节返回值。我总是喜欢在一个强类型的PInvoke输出,而不是代表编组工作的指针。

  注释:此代码将不能在一个仿真器运行,除非你配置蜂窝仿真并且能够很好的运行。我建议使用手机,而不是仿真器。

  Cell 数据服务

  我们有了Cell Tower的数据,但现在能够做什么?我们还没有全球定位系统坐标。我们知道,谷歌正在使这种转换发生,Cell Tower数据为纬度和长,我们要继续剖析谷歌手机地图。他们正在给上述URL上传二进制数据。同样,分析协议超出了本文的范围。你会发现,我们需要换一个55字节数组的数据。字节的大部分是空的(0),但我们确实需要填补数组中的几个关键项。下面的代码来创建和用Cell Tower数据填充字节数组:

  代码片段:

1 private static byte[] GetFormPostData(int cellTowerId, int mobileCountryCode,
2
3   int mobileNetworkCode, int locationAreaCode)
4
5   {
6
7   byte[] pd = new byte[55];
8
9   pd[1] = 14; //0x0e;
10
11   pd[16] = 27; //0x1b;
12
13   pd[47] = 255; //0xff;
14
15   pd[48] = 255; //0xff;
16
17   pd[49] = 255; //0xff;
18
19   pd[50] = 255; //0xff;
20
21   // GSM uses 4 digits while UTMS used 6 digits (hex)
22
23   pd[28] = ((Int64)cellTowerId > 65536) ? (byte)5 : (byte)3;
24
25   Shift(pd, 17, mobileNetworkCode);
26
27   Shift(pd, 21, mobileCountryCode);
28
29   Shift(pd, 31, cellTowerId);
30
31   Shift(pd, 35, locationAreaCode);
32
33   Shift(pd, 39, mobileNetworkCode);
34
35   Shift(pd, 43, mobileCountryCode);
36
37   return pd;
38
39   }
40
41   ///
42
43   /// Shifts specified data in the byte array starting at the specified array index.
44
45   ///
46
47   /// The data.
48
49   /// The start index.
50
51   /// The left operand.
52
53   private static void Shift(byte[] data, int startIndex, int leftOperand)
54
55   {
56
57   int rightOperand = 24;
58
59   for (int i = 0; i < 4; i++, rightOperand -= 8)
60
61   {
62
63   data[startIndex++] = (byte)((leftOperand >> rightOperand) & 255);
64
65   }
66
67   }
68
69

  总之,我们可以通过在我们的4个参数:Cell Tower的 ID,LAV,MNC,和MCC,我们得到一个字节数组,并且可以通过HTTP上传到谷歌。下面的代码演示了整个HTTP请求,这需要我们的强类型的Cell Tower的数据(从上述的PInvoke),从谷歌的数据库中返回纬度和经度!

  代码片段:

  1 internal static GeoLocation GetLocation(CellTower tower)
  2
  3   {
  4
  5   try
  6
  7   {
  8
  9   // Translate cell tower data into http post parameter data
10
11   byte[] formData = GetFormPostData(tower.TowerId,
12
13   tower.MobileCountryCode,
14
15   tower.MobileNetworkCode,
16
17   tower.LocationAreaCode);
18
19   HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
20
21   new Uri(Google_Mobile_Service_Uri));
22
23   request.Method = "POST";
24
25   request.ContentLength = formData.Length;
26
27   request.ContentType = "application/binary";
28
29   Stream outputStream = request.GetRequestStream();
30
31   // Write the cell data to the http stream
32
33   outputStream.Write(formData, 0, formData.Length);
34
35   outputStream.Close();
36
37   HttpWebResponse response = (HttpWebResponse)request.GetResponse();
38
39   return ReadResponse(response);
40
41   }
42
43   catch{}
44
45   return GeoLocation.Empty;
46
47   }
48
49   private static GeoLocation ReadResponse(HttpWebResponse response)
50
51   {
52
53   byte[] responseData = new byte[response.ContentLength];
54
55   int bytesRead = 0;
56
57   // Read the response into the response byte array
58
59   while (bytesRead < responseData.Length)
60
61   {
62
63   bytesRead += response.GetResponseStream()
64
65   .Read(responseData, bytesRead, responseData.Length - bytesRead);
66
67   }
68
69   // Check the response
70
71   if (response.StatusCode == HttpStatusCode.OK)
72
73   {
74
75   int successful = Convert.ToInt32(GetCode(responseData, 3));
76
77   if (successful == 0)
78
79   {
80
81   return new GeoLocation()
82
83   {
84
85   Latitude = GetCode(responseData, 7) / 1000000,
86
87   Longitude = GetCode(responseData, 11) / 1000000
88
89   };
90
91   }
92
93   }
94
95   return GeoLocation.Empty;
96
97   }
98
99   ///
100
101   /// Gets the latitude or longitude from the byte array.
102
103   ///
104
105   /// The byte array.
106
107   /// The start index.
108
109   ///
110
111   private static double GetCode(byte[] data, int startIndex)
112
113   {
114
115   return ((double)((data[startIndex++] << 24) |
116
117   (data[startIndex++] << 16) |
118
119   (data[startIndex++] << 8) |
120
121   (data[startIndex++])));
122
123   }
124
125

  简要的Cell Tower说明

  让我花一点时间来描述刚刚发生。我们从系统中读取Cell Tower 数据,发送通过HTTP协议发送给谷歌,并回来经度和纬度。这样能行得通吗?

  联邦通讯委员会保留了在美国的每一个Cell Tower纪录。谷歌没有做任何(太)神奇的事情。他们只是简单地为我们提交的Cell Tower数据查找细节。以纬度/经度的格式返比较知名的Tower的具体位置。

  但是,谷歌并不是塔的具体位置的唯一数据库。 OpenCellID.org是一个开源的倡议,来标记所有的Cell Tower地图和GPS坐标。雅虎!正在用他们的ZoneTag服务做同样的事情。

  如果有更容易的选择为什么还要不厌其烦地使用谷歌?

  这是一个很大的问题!简单地说,谷歌是最全面的数据库。 OpenCellID和ZoneTag较新,他们的数据库不完整,用这些“测试”服务其中之一,在主要城市郊区的家里甚至不能获得一个有效的全球定位系统。但是,谷歌的作品在任何地方我已经测试过。

  如果我的手机有GPS那将会是怎样一个情况?

  当然,Cell Tower的数据并不能像全球定位系统那样精确。你并不能利用手机中Cell Tower 的数据告诉我你的具体位置,如果在你附近10英尺或1000英尺有Cell Tower。换句话说,最好使用全球定位系统,因为它的精确度。但是有例外,如当你在室内,无法获得的GPS信号时,你很可能仍然有Cell Tower连接。

  从兼容的手机获取GPS数据比获取Cell Tower的数据更容易。更好的是-微软已经分发了一个库来做所有繁重的事情。

  代码片段:

1 private Gps _gps = new Gps();
2
3   private GpsPosition _currentPosition;
4
5   public void Start()
6
7   {
8
9   _gps.LocationChanged += new
10
11   Microsoft.Location.LocationChangedEventHandler(_gps_LocationChanged);
12
13   if (!_gps.Opened)
14
15   {
16
17   _gps.Open();
18
19   }
20
21   }
22
23   private void _gps_LocationChanged(object sender,
24
25   Microsoft.Location.LocationChangedEventArgs args)
26
27   {
28
29   _currentPosition = args.Position;
30
31   }
32
33

  到目前为止,我们已经建立了两个机制来获取您的手机的经度和纬度。我们现在有尽可能多的潜力,例如,谷歌地图!

  什么是好的位置呢?

  我一般知道我在哪里,所以知道我的位置并没有多大帮助。像谷歌手机地图的应用已经显示我的位置,但他们没有利用它做任何东西。这是我的意见,即基于位置服务的真正价值在分享您的位置,而不仅仅是知道你的位置。这是社交网络下一个必然会发生的。

  充分利用位置

  你应该拿出下次如何处理您的位置的很建议。我的第一个创造性的催化剂就是利用您的经度和纬度更新您的Yahoo!火鹰帐户。火鹰是从雅虎开的新服务!将你的位置,“广播”到您的订阅(在其快速增长的库应用程序)。其实,这就是这个项目被命名为DeepCast的原因。我们正在广播的位置给(潜在的)深度的服务和服务提供者。

  火鹰

  火鹰使用Oauth作为其授权的平台。我不是那么熟悉所有Oauth细节。我所知道的是,有一个授权的手工过程可以在任何应用程序进行更新。在Oauth认证的第一步是生成一个请求令牌和秘密对。

     然后,您可以浏览(通过您的桌面浏览器)授权网址。

        您必须手动确认应用程序可以更新您的个人资料。

        最后,您有您的要求,交换令牌和授权令牌和秘密。这些价值观您需要保存和使用每次应用程序尝试更新您的位置。

        Twitter

  有很少来形容更新Twitter的条款。它像发送一个HTTP请求那样简单。一个困难是增加一个链接到邮件中。 Twitter的使用形式的URL编码截断最查询字符串。我们将生成一个TinyUrl避开这个问题。

  下面是我们如何更新Twitter的:

1 internal override void Update(GeoLocation location)
2
3   {
4
5   if (!string.IsNullOrEmpty(Settings.TwitterEmail) &&
6
7   !string.IsNullOrEmpty(Settings.TwitterPassword))
8
9   {
10
11   string googleMapLink = string.Format(Google_Map_Uri,
12
13   location.Latitude, location.Longitude);
14
15   string tilyMapLink = TinyUrlService.GetTinyUrl(googleMapLink);
16
17   string place = string.Format("I'm here: {0} - 'L:{1}, {2}'",
18
19   new object[] { tilyMapLink, location.Latitude, location.Longitude });
20
21   string data = string.Format("status={0}", place);
22
23   HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Twitter_Api_Uri);
24
25   request.Credentials = new NetworkCredential(Settings.TwitterEmail,
26
27   Settings.TwitterPassword);
28
29   request.ContentType = "application/x-www-form-urlencoded";
30
31   request.Method = "POST";
32
33   request.AllowWriteStreamBuffering = true;
34
35   byte[] bytes = Encoding.UTF8.GetBytes(data);
36
37   request.ContentLength = bytes.Length;
38
39   using (Stream requestStream = request.GetRequestStream())
40
41   {
42
43   requestStream.Write(bytes, 0, bytes.Length);
44
45   requestStream.Flush();
46
47   requestStream.Close();
48
49   using (WebResponse response = request.GetResponse())
50
51   {
52
53   using (StreamReader reader =
54
55   new StreamReader(response.GetResponseStream()))
56
57   {
58
59   reader.ReadToEnd();
60
61   }
62
63   }
64
65   }
66
67   }
68
69   }
70
71

  请注意,有一个位置的公约,'长:纬度,离子',那就是我们更深层的目的。这种格式可以通过在TwitterMap.com解析的乡亲。同样,我们试图使有益的位置深的受众群。

  内部事务

  当然,分享您的位置并不是使信息有用的唯一的方式。例如,使同一地点使用面向外部的服务。在主页上的地图只是一个浏览器的控制,其网址被设置为一个Yahoo!地图图像。优雅而简单,这正是我想要!

        你可以享受的服务

  我能想到的位置可能的若干用途是:

  1、通过Web服务跟踪你去哪儿。支持创建一个网站,显示您的轨道地图-何时何地。画出你在哪里旅行的轨迹。

  2、跟踪你的孩子,让您始终知道他们在哪里。

  3、地理标记您的照片。Flickr支持地理标记图像,例如。记录您的车队。

        4、地理博客。

  5、更新您的Facebook / MySpace的/社会网站与您的位置。

0
相关文章