如何在Windows store app中使用百度地图

目前提供Windows store app API接口的地图只有两个,自带的Bing地图和高德地图。Bing地图对国外的支持很好,可是对国内的支持就不那么给力了,如果是要写一个针对国内的应用,这是显然不行的。而高德地图虽然对国内支持的很好,他的API却一直没有更新,以至于现在已经通不过WACK(Windows app certificate kit)测试了,作为一个需要能够提交到app store的应用,这条路也走不通。所以要想在Windows store app项目中使用地图,就只有另辟蹊径,采用曲线救国的办法了。

首先我查阅了国内主流的地图接口,感觉百度地图的接口还是做的比较好的,地图数据也足够丰富,那么就选定它了。

由于目前百度地图还没有针对Windows Store App的SDK,于是我就想到使用WebView控件,结合百度地图JavaScript API来使用地图。在Window Store App中,我们可以使用WebView控件在应用程序内加载地图。同时调用百度地图的JavaScript API完成与地图的互操作。

首先介绍一下我的开发环境:

操作系统:   Windows 8.1 RTM

开发工具:   Microsoft Visual Studio 2013(RC)

API:          百度地图JavaScript API

接下来是具体步骤:

1.     创建百度账户,并申请Key

第一步当然是获得Baidu地图的开发许可。从百度网站可知,Baidu地图API免费对外开放,对于非商业应用可以直接使用,对于商业应用需要得到Baidu的协议许可。自v1.5版本起,需先申请密钥才可使用,接口(除发送短信功能外)无使用次数限制。你可以通过登录https://developer.baidu.com/map/jshome.htm

按照提示申请开发者密钥,当然,你首先需要有一个百度账号,百度会让你首先注册为开发者账号,然后再创建密钥。

2.     创建Window store应用,并在应用中加载百度地图

第二步就是创建你的Windows store 应用,然后在您的应用中加入WebView控件:

<WebView x:Name="MyWebview" Source="ms-appx-web:///MapDemo.html/>

WebView加载的页面是个html网页,该网页的代码你可以参考百度地图开发者网站的示例:

https://developer.baidu.com/map/jsdemo.htm

下面就是一个最简单的网页示例代码:

<!DOCTYPE html>

<html>

<head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />

    <script type="text/javascript" src="https://api.map.baidu.com/api?v=2.0&ak=您的密钥"></script>

    <title>百度地图的Hello, World</title>

    <style type="text/css">

        body, html, #allmap {

            width: 100%;

            height: 100%;

            overflow: hidden;

            margin: 0;

        }

    </style>

</head>

<body>

    <div id="allmap"></div>

</body>

</html>

<script type="text/javascript">

    // 百度地图API功能

   var map = new BMap.Map("allmap");            // 创建Map实例

   var point = new BMap.Point(116.404, 39.915);  // 创建点坐标

   map.centerAndZoom(point, 15);               // 初始化地图,设置中心点坐标和地图级别。

   map.enableScrollWheelZoom();                //启用滚轮放大缩小

</script>

这里你需要将“您的密钥”换成第一步获得的实际的开发者密钥。经过简单的两步,您的Windows Store应用就可以加载地图了。

3.     在地图中进行浏览器定位

光能够加载地图是远远不够的,通常我们都希望地图加载的时候能够根据当前的位置进行定位。IE本身提供了浏览器定位的功能,不幸的是Webview不支持这个功能,也就是说我们没有办法在html网页中得到地理位置的信息。当时,我们知道Windows runtime提供的Geolocator API可以得到地理位置信息。那么我们就可以通过WebView的InvokeScriptAsync方法来将定位信息传给html网页。

首先,在在XAML文件中增加对页面加载完成事件的消息响应:

<WebView x:Name="MyWebview" Source="ms-appx-web:///html/MapDemo.html" NavigationCompleted="MyWebview_NavigationCompleted"/>

然后在响应的消息响应函数中实现定位:

private async void MyWebview_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)

{

        Geolocator  geolocator = new Geolocator();

        Geoposition pos = await geolocator.GetGeopositionAsync();

        Geopoint poi = pos.Coordinate.Point;

        var lat = poi.Position.Latitude; // 纬度

        var lon = poi.Position.Longitude; // 经度

        …

}

最后,我们需要将地理位置信息传递到html代码中,这可以使用InvokeScriptAsync方法调用html中得script函数来实现:

private async void MyWebview_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)

{

        Geolocator  geolocator = new Geolocator();

        Geoposition pos = await geolocator.GetGeopositionAsync();

        Geopoint poi = pos.Coordinate.Point;

        var lat = poi.Position.Latitude; // 纬度

        var lon = poi.Position.Longitude; // 经度

        …

        //调用并传递地理位置信息给html中的getloc函数

        String[] loc = { lon.ToString(),lat.ToString() };

        await MyWebview.InvokeScriptAsync("getloc", loc);

 

}

MapDemo.html中定义getloc(x)函数如下:

function getloc(lon,lat)

{

        var point = new BMap.Point(lon, lat); //根据经纬度新建一个point

        map.centerAndZoom(point, 15); //缩放视图至定位得到的城市

}

这样,我们就可以根据当前的地理位置信息在地图中进行定位了。同样的方法,我们也可以实现对地图的搜索功能:

private async void Button_Click(object sender, RoutedEventArgs e)

{

            String[] str = { tbxSearch.Text };

            await MyWebView.InvokeScriptAsync("search", str); 

}

 

function search(str) {

     map.clearOverlays();

     var options = {

           onSearchComplete: function (results) {

             // 判断状态是否正确

             if (local.getStatus() == BMAP_STATUS_SUCCESS) {

                 var defnotify=null; //搜索完成返回所有兴趣点的地址

                 if (results.getCurrentNumPois() != 0) {

                     for (var i = 0; i < results.getCurrentNumPois() ; i++)

                     {

                         //在地图上添加标注

                         var marker = addMarker(results.getPoi(i).point, i);

                     }  

                 }

             }

         }

     };

     var local = new BMap.LocalSearch(map, options);

     local.search(str);

}

 

function addMarker(point, index) {

           var myIcon = new BMap.Icon("https://api.map.baidu.com/img/markers.png",new BMap.Size(23, 25), {

               offset: new BMap.Size(10, 25),

               imageOffset: new BMap.Size(0, 0 - index * 25)

           });

           var marker = new BMap.Marker(point, { icon: myIcon });

           map.addOverlay(marker);

           return marker;

}

 

4.     将地图中获得的地图信息传递给应用

当然,如果仅仅是从应用传递数据给地图是远远不够的,我们还需要随时能够拿到地图上的数据。这就需要依靠ScriptNotify事件了。ScriptNotify能够使 HTML 页面在页面调用 window.external.notify的时候激发此事件并传递字符串到 XAML 应用程序。在这里,如果应用程序想拿到搜索的结果,则需要这样实现:

首先在XAML和cs文件中增加一个ScriptNotify的消息触发函数,在这个事件响应函数中显示所有得到的搜索结果:

<WebView x:Name="MyWebview" Source="ms-appx-web:///html/MapPage.html" ScriptNotify="MyWebview_ScriptNotify" NavigationCompleted="MyWebview_NavigationCompleted"/>

 

private void MyWebView_ScriptNotify(object sender, NotifyEventArgs e)

{

            if (e.Value != "")

            {

                string[] splits = e.Value.Split('|');

                for (int i = 0; i < splits.Length-1;i++)

                        lbxResult.Items.Add(splits[i]); //添加地址             

            }

        }

}

 

然后改写script中的search函数,让它能够触发ScriptNotify消息并返回想要的值,这里我们返回搜索得到的所有地址:

function search(str) {

       map.clearOverlays();

       var options = {

           onSearchComplete: function (results) {

               // 判断状态是否正确

               var defnotify="";

               if (local.getStatus() == BMAP_STATUS_SUCCESS) {

                   if (results.getCurrentNumPois() != 0) {

                       for (var i = 0; i < results.getCurrentNumPois() ; i++)

                       {

                           //添加标注

                           var marker = addMarker(results.getPoi(i).point, i);

                           defnotify += results.getPoi(i).title + "-" +                                  

                                        results.getPoi(i).address +"|";

                       }  

                   }

                   window.external.notify(defnotify);

               }

           }

       };

       var local = new BMap.LocalSearch(map, options);

       local.search(str);

}

最终的运行效果如下图所示:

 

 这样,我们就在Windows Store 应用中实现了地图的定位搜索功能,我这里附上相应的示例代码供大家参考。

我这里只是完成了一个基本的功能,通过灵活使用InvokeScriptAsync和ScriptNotify,你可以不断完善,实现你想要的各种功能。我这里仅作为抛砖引玉,如果各位有其他更好的做法,欢迎与我一起探讨。

 

 

 

 

 

MapDemo.zip