下载原文
Developing JavaScript* Metro Style Apps That Use the Geolocation API and the Bing* Maps SDK [PDF 761 KB]
目标
本文介绍了如何使用 Geolocation API 检测用户 Windows* 8 设备的当前位置以及如何使用 Bing* Maps SDK 将 Bing Map 控件集成至Windows* 8 商店应用中。
1 内容简介
目前,大部分电脑/移动手持设备都支持启用地理位置。Windows.Device.Geolocation API 从所有可用资源(包括 GPS 和 Windows Location Provider)中提供了最佳地理位置数据,它使用 Wi-Fi* 三角测量或 Wi-Fi IP 地址确定设备的位置。我们可以开发大量基于位置的 Metro 风格应用,如搜索某一位置的兴趣点 (POI)、户外活动、健身和比赛。
2 在 Metro 风格应用中检测当前位置
我们将在这一章节讨论如何在 Metro 风格 JavaScript* 应用中检测地理位置数据。在您尝试实践本文中的代码范例时,您的开发电脑上必须已经安装了 Windows 8 Release Preview。可以通过以下网址下载 Windows 8 Release Preview: http://windows.microsoft.com/en-US/windows-8/download
2.1 创建基于地理位置的应用项目
Microsoft Visual Studio* 2012 RC (Release Candidate) 是用于开发 Metro 风格应用的 IDE。您可以通过以下链接下载并安装 Visual Studio 2012: http://www.microsoft.com/visualstudio/11/en-us
2.1.1 在开发电脑和部署电脑上启用位置
要想使用应用中的地理位置数据,必须开启您设备的位置设置。如要在运行 Windows 8 的设备上执行该操作,请进入"Settings"(设置),按"Change PC Settings"(更改电脑设置),选择"Privacy"(隐私),然后将"Let apps use my location"(允许应用使用我的位置)设置为"On"(开启)。
2.1.2 创建新的 JavaScript 项目
打开 Microsoft Visual Studio 2012 RC,在"New Project"(新建项目)对话框中,选择左侧窗格中的"JavaScript"和右侧窗格中的"Blank App"(空白应用)(图 1)。指定一个项目名称和目录(在范例中,我们使用"GeolocationTest"作为项目名称),并点击"OK"。

Figure 1: "New Project" dialog
2.2 显示应用的位置功能
在"Solution Explorer"(解决方案资源管理器)选项卡上,双击"package.appxmanifest",然后选择"Capacities"(功能)选项卡,勾选"Location"(位置)项目(图 2)。按 Ctrl-S 保存文件。

Figure 2: Location capacity
2.3 添加 HTML 和 JavaScript 代码
在解决方案资源管理器中,在"GeolocationTest"项目下,找到并双击"default.html"文件,将其打开,使用以下代码替换文件内容:
<!DOCTYPE html> <html> <head> <title>Test Geolocation</title> <!-- WinJS references --> <link href="//Microsoft.WinJS.1.0.RC/css/ui-light.css" rel="stylesheet" /> <script src="//Microsoft.WinJS.1.0.RC/js/base.js"></script> <script src="//Microsoft.WinJS.1.0.RC/js/ui.js"></script> <script src="/js/default.js"></script> </head> <body> <p> Click "Get Current Location" to get the current geolocation data.<br /> <button id="getCurLoc">Get Current Location</button> <br /> <br /> Lat: <span id="lat"></span><br /> Long: <span id="long"></span><br /> Data Accuracy (meters): <span id="dataAccuracy"></span><br /><br /> Data Status:<span id="dataStatus"></span><br /> Error: <span id="errMsg"></span><br /> </p> </body> </html>
Code Example 1 (**)
在"js"文件夹下,找到并双击"default.js"文件,将其打开,使用以下代码替换文件内容:
// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
WinJS.strictProcessing();
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll());
}
};
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
app.start();
var geolocator = null;
function getcurloc() {
if (geolocator == null) {
geolocator = new Windows.Devices.Geolocation.Geolocator();
}
if (geolocator != null) {
geolocator.getGeopositionAsync().then(getCurPosHandler, errHandler);
}
}
function getCurPosHandler(pos) {
document.getElementById('lat').innerHTML = pos.coordinate.latitude;
document.getElementById('long').innerHTML = pos.coordinate.longitude;
document.getElementById('dataAccuracy').innerHTML = pos.coordinate.accuracy;
document.getElementById('dataStatus').innerHTML =
getStatusStr(geolocator.locationStatus);
}
function errHandler(e) {
document.getElementById('errMsg').innerHTML = e.message;
}
function getStatusStr(status) {
switch (status) {
case Windows.Devices.Geolocation.PositionStatus.ready:
return "Ready";
break;
case Windows.Devices.Geolocation.PositionStatus.initializing:
return "Initializing";
break;
case Windows.Devices.Geolocation.PositionStatus.noData:
return "noData";
break;
case Windows.Devices.Geolocation.PositionStatus.disabled:
return "disabled";
break;
case Windows.Devices.Geolocation.PositionStatus.notInitialized:
return "notInitialized";
break;
case Windows.Devices.Geolocation.PositionStatus.notAvailable:
return "notAvailable";
break;
default:
break;
}
}
function init() {
document.getElementById('getCurLoc').addEventListener("click", function (ev) { getcurloc(); });
}
document.addEventListener("DOMContentLoaded", init, false);
})();
Code Example 2 (**)
保存这两个文件并构建解决方案。
2.4 在模拟器上运行应用
在工具栏上,点击"Start Debugging"(开始调试)右侧的下拉图标(绿色的三角图标),并选择"Simulator"(模拟器)(图3)(Figure 3).

Figure 3: Run the simulator
现在按下 F5,您将看到模拟器已启动、应用已开启(Figure 4).

Figure 4: "Get Current Location" UI
如果您的开发电脑连接到了 Wi-Fi 接入点,在您点击"Get Current Location"(获取当前位置)按钮后,您将看到地理坐标(经度和纬度)显示在相应的区域。.
2.5 章节概述
在这一简单应用中,首次调用getcurloc() 功能时呈现了一个 Geolocator 对象。然后它调用 getGeoPositionAsyn() 并提供两个处理程序:getCurPosHandler() 处理成功的返回,errHandler() 处理失败的返回。
3 在Windows* 8 商店应用中追踪位置
在一些查找附近 POI 的使用情形中,获取用户的当前位置就足够了。在其他使用情形中(如记录用户徒步路线及距离的应用),我们需要追踪用户的行程线路并随线路进行位置更新。
如要追踪用户位置,您可以为 Geolocator 对象添加两个事件侦听器。一个用于 positionchanged 事件,另一个用于 statuschanged 事件。
您可以使用以下源代码替换之前范例中的 default.html 和 default.js,然后构建并运行应用:
default.html:
Click "Track Location" to receive location updates. Track Location Click "Stop Tracking" to stop receiving location updates. Stop Tracking Lat: Long: Data Accuracy (meters): Data Status: Error:
Code Example 3 (**)
default.js:
// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
WinJS.strictProcessing();
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll());
}
};
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
app.start();
var geolocator = null;
function getStatusStr(status) {
switch (status) {
case Windows.Devices.Geolocation.PositionStatus.ready:
return "Ready";
break;
case Windows.Devices.Geolocation.PositionStatus.initializing:
return "Initializing";
break;
case Windows.Devices.Geolocation.PositionStatus.noData:
return "noData";
break;
case Windows.Devices.Geolocation.PositionStatus.disabled:
return "disabled";
break;
case Windows.Devices.Geolocation.PositionStatus.notInitialized:
return "notInitialized";
break;
case Windows.Devices.Geolocation.PositionStatus.notAvailable:
return "notAvailable";
break;
default:
break;
}
}
function starttracking() {
if (geolocator == null) {
geolocator = new Windows.Devices.Geolocation.Geolocator();
}
if (geolocator != null) {
geolocator.addEventListener("positionchanged", onPositionChanged);
geolocator.addEventListener("statuschanged", onStatusChanged);
}
document.getElementById('trackLocation').disabled = true;
document.getElementById('stopTracking').disabled = false;
}
function stoptracking() {
if (geolocator != null) {
geolocator.removeEventListener("positionchanged", onPositionChanged);
}
document.getElementById('trackLocation').disabled = false;
document.getElementById('stopTracking').disabled = true;
document.getElementById('lat').innerHTML = "waiting for update...";
document.getElementById('long').innerHTML = "waiting for update...";
document.getElementById('dataAccuracy').innerHTML = "waiting for update...";
document.getElementById('dataStatus').innerHTML =
"waiting for update...";
}
function onPositionChanged(args) {
var position = args.position;
//use the position ifnormation (lat/lon/accuracy) to do some work
document.getElementById('lat').innerHTML = position.coordinate.latitude;
document.getElementById('long').innerHTML = position.coordinate.longitude;
document.getElementById('dataAccuracy').innerHTML = position.coordinate.accuracy;
document.getElementById('dataStatus').innerHTML =
getStatusStr(geolocator.locationStatus);
}
// Handle change in status to display an appropriate message.
function onStatusChanged(args) {
var status = args.status;
//handle the new status
}
function init() {
document.getElementById('lat').innerHTML = "waiting for update...";
document.getElementById('long').innerHTML = "waiting for update...";
document.getElementById('dataAccuracy').innerHTML = "waiting for update...";
document.getElementById('dataStatus').innerHTML =
"waiting for update...";
document.getElementById('trackLocation').addEventListener("click", function (ev) { starttracking(); });
document.getElementById('stopTracking').addEventListener("click", function (ev) { stoptracking(); });
document.getElementById('trackLocation').disabled = false;
document.getElementById('stopTracking').disabled = true;
}
document.addEventListener("DOMContentLoaded", init, false);
})();
Code Example 4 (**)
4 向Windows* 8 商店应用中添加 Bing Map
地图和地理位置两者之间通常密切相关。同时使用 Bing Maps SDK 和 Geolocation API 可为开发大量 Metro 风格应用提供一个平台。我们将在这一章节使用一个范例介绍如何编写 Metro 风格的应用,以在 Bing Map 上显示用户的当前位置。
4.1 为Windows* 8 商店应用中安装 Bing Maps SDK
您可以通过以下链接为 Metro 风格应用 (Release Preview) 下载并安装 Bing Maps SDK: http://visualstudiogallery.msdn.microsoft.com/0c341dfb-4584-4738-949c-daf55b82df58
作为 Visual Studio 2012 RC (Release Candidate) 的扩展,Bing Maps SDK 支持开发人员将 Bing Map 控件集成至 Metro 风格应用。Bing Maps SDK 支持 JavaScript以及 Visual Basic、C++ 和 C#。
本文将着重介绍如何使用面向 JavaScript 的 Bing Maps SDK,后者基于 Bing Maps AJAX Control 7.0。
4.2 获取 Bing Map 密钥
要想在您的应用中添加 Bing Map 控件,您需要一个"Bing Maps 密钥"。要想获得这个密钥,请使用以下链接进入 Bing Map 帐户中心:http://www.bingmapsportal.com/。您创建一个帐户并登录后,请选择"My Account"(我的帐户)下的"Create and View Keys"(创建并查看密钥)。为了创建一个 Bing map 密钥,您需要提供应用名称。在我们的范例中,我们使用"GeolocationTest"。对于应用类型,我们从下拉方框中选择"Metro style apps (BETA)"(Metro 风格应用 (BETA))(Figure 5).

Figure 5: The "Create Key" dialog
创建 Bing Map 密钥后,如果您在左侧窗格中选择"Create or view keys"(创建或查看密钥),新的密钥将显示在类似图 6 的列表中,但是并非完全相同。您需要将您在"Key/URL"(密钥/URL)栏中创建的密钥字符串复制并粘贴到您应用的 Bing Map 选项"credentials"(凭证)属性中。

Figure 6: The Bing Maps key list
4.3 添加 Bing Map 引用
使用 Visual Studio 2012 RC,执行以下步骤,添加面向 JavaScript 扩展的 Bing Map 引用:
- 在解决方案资源管理器窗格中,右键点击 JavaScript 项目"GeolocationTest".
- 从弹出的菜单中选择"Add Reference..."(添加引用...)将会显示"Reference Manager"(引用管理器)对话框(Figure 7).
- 选择"Extensions"(扩展)并勾选"Bing Maps for JavaScript (RP)"
- 点击"OK"按钮。

Figure 7: The "Reference Manager" dialog
您还需要在 default.html 文件中添加以下内容,将一个引用添加至 veapicore.js:
Code Example 5 (**)
4.4 加载"Map"(地图)模块
您可以添加 JavaScript 代码,加载"Map"(地图)模块:
Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: initMap });
…
function initMap() {
try {
var mapOptions =
{
credentials: 'Your Bing Map Key',
center: new Microsoft.Maps.Location(37.38826, -121.962502),
mapTypeId: Microsoft.Maps.MapTypeId.road,
zoom: 12
};
map = new Microsoft.Maps.Map(document.getElementById("mapdiv"), mapOptions);
}
catch (e) {
var md = new Windows.UI.Popups.MessageDialog(e.message);
md.showAsync();
}
Code Example 6
您需要使用您在 4.2 章节创建的 Bing Map 密钥替换"Your Bing Map Key"(您的 Bing Map 密钥)内的字符串.
4.5 在地图上显示当前位置
我们修改了第 2 章节的范例。获取当前位置后,不再显示经度、纬度和精确值,而是在 Bing Map 上将它显示为一个图钉。
以下提供了完整的源代码:
default.html:
Code Example 7 (**)
default.js:
// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
var app = WinJS.Application;
// This function responds to all application activations.
app.onactivated = function (eventObject) {
if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
WinJS.UI.processAll();
}
};
app.start();
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
WinJS.strictProcessing();
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll());
}
};
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
app.start();
var geolocator = null;
function getcurloc() {
if (geolocator == null) {
geolocator = new Windows.Devices.Geolocation.Geolocator();
}
if (geolocator != null) {
geolocator.getGeopositionAsync().then(getCurPosHandler, errHandler);
}
}
function getCurPosHandler(pos) {
map.setView({ center: new Microsoft.Maps.Location(pos.coordinate.latitude, pos.coordinate.longitude), mapTypeId: Microsoft.Maps.MapTypeId.road, zoom: 16.0 });
var pin = new Microsoft.Maps.Pushpin(pos.coordinate);
map.entities.push(pin);
}
function errHandler(e) {
//handle errors here
}
function init() {
Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: initMap });
getcurloc();
}
document.addEventListener("DOMContentLoaded", init, false);
})();
var map;
function initMap() {
try {
var mapOptions =
{
credentials: 'Your Bing Map Key',
center: new Microsoft.Maps.Location(37.38826, -121.962502),
mapTypeId: Microsoft.Maps.MapTypeId.road,
zoom: 12
};
map = new Microsoft.Maps.Map(document.getElementById("mapdiv"), mapOptions);
}
catch (e) {
var md = new Windows.UI.Popups.MessageDialog(e.message);
md.showAsync();
}
}
Code Example 8 (**)
应用开启后,您将看到您地图上的当前位置(图 8)(Figure 8):

Figure 8: Displaying the current location on Bing Maps
5 能效
使用系统的位置服务开发应用时,我们需要注意能效问题,因为使用 GPS 通常会比使用基于 Wi-Fi 的位置检测方法耗费更多的能源。
以下是开发位置感知应用时您需要遵循的一些准则:
-
不需要更新时请使用一次性位置请求
在许多使用情形时,您无需在所有时间都追踪位置,例如将当前位置连接至一个文档或一张照片。在这些情形中,应用应该调用 getGeolocationAsyn() 方式获取当前位置。.
-
最小化位置更新请求的频率和持续时间
应用应该最小化位置更新请求的频率和持续时间。可以通过调整 Geolocator 属性来实现:
- MovementThreshold
- ReportInterval
您的应用还需通过调用 geolocator.removeEventListener() 来取消位置更新.
-
仅请求必要的精确级别
如果您的应用需要 GPS 数据,您可以将 DesiredAccuracy 属性设置为"HIGH"(高)。请注意 GPS 通常会比其他位置检测方法消耗更多的电源,您应该寻求节约电源的方式.
6 总结
本文提供了如何开发使用 Geolocation API 和 Bing Maps SDK 的 JavaScript Metro 风格应用的教程。它涵盖了开发位置感知 Windows* 8 商店应用时所使用的常用工具和插件。它还提供了开发节能的基于位置的应用的准则.
作者简介
Miao Wei 是英特尔公司软件及服务事业部软件工程师.
*文中涉及的其它名称及商标属于各自持有者。
** 该样本源代码根据"英特尔样本源代码许可协议"发布.
