如何在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,你可以不断完善,实现你想要的各种功能。我这里仅作为抛砖引玉,如果各位有其他更好的做法,欢迎与我一起探讨。