开发使用 Geolocation API 和 Bing* Maps SDK 的 JavaScript* Windows* 8 商店应用

下载原文

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 是英特尔公司软件及服务事业部软件工程师.

*文中涉及的其它名称及商标属于各自持有者。

** 该样本源代码根据"英特尔样本源代码许可协议"发布.

有关编译器优化的更完整信息,请参阅优化通知