Cross Platform Development with Bing Maps and PhoneGap

Bing Maps provides a variety of APIs and controls. One of which is the Bing Maps AJAX Control that was originally designed to provide interactive maps for the web, but meanwhile also powers the WinJS control in the Bing Maps SDK for Windows Store apps. The Bing Maps AJAX control has a slim core to speed up the initial load of a website, is optimized for performance using HTML5 technologies and implements a modular concept that allows the loading of additional modules on-demand. Official modules include the search for locations and business listings, driving directions, traffic overlays, venue maps and more. Our friends in the developer community have picked up this modular concept and developed further modules which extend the AJAX control. An Interactive SDK makes it very simple to become familiar with the control and implement your first maps within minutes.

Another big point for the AJAX control is that it cannot only be used for websites, but also in the context of PhoneGap / Apache Cordova. PhoneGap enables JavaScript developers to build native applications for a number of platforms including Android, iOS and Windows Phone. Getting Started Guides help you over the first hurdles for all supported platforms. No matter if you are used to Visual Studio, Blend, Eclipse or Xcode, if you are familiar with HTML, JavaScript and CSS, you can get your first mobile applications off the ground very quickly.

CrossPlatformDevtScreenshot1

 

Once you have your app running on one platform, it is a walk in the park to move it over to other platform. You don’t need to be an expert on Objective C, Java and .NET to support Windows Phone, Android and iOS. You can simply write your application in HTML, JavaScript and CSS and let PhoneGap / Apache Cordova handle the rest.

Getting Started

Let’s put that concept to a test. We start with the projects from the Getting Started Guides for PhoneGap as well as a simple web application that features Bing Maps and allows us to search for locations and business listings. Below you will find the HTML-document.

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8" /> 
<link rel="stylesheet" type="text/css" href="css/index.css" /> 
<script 
   type="text/javascript" 
   src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0">
</script>        <script type="text/javascript" src="js/index.js"></script> 
<title>Bing Maps</title> 
</head> 
<body> 
<div id='divSearch' 
 style="position:absolute; top:5px; left:0px; right:0px; height:50px; 
   background-color:White; "> 
<input id="txtSearch" type="text" class="searchBox" /> 
<img id="btnSearch" src="./img/search.png" alt="" 
 style="position:absolute; top:0px; right:0px; 
   cursor:pointer" onclick="LoadSearchModule()" /> 
</div> 
  <div id="divMap" style="width:100%; height:92%; 
   position:absolute; left:0px; top:55px;"></div> 
</body> 
</html>

And here is the JavaScript-file that loads the map, applies some themes for controls and pushpins, handles the search for business listings and displays pushpins along with the infoboxes that appear when you click on such a pushpin. You can find all the pieces for this sample in the above mentioned interactive SDK.

window.onload  = GetMap;
var map = null;
var searchManager = null;
var currInfobox = null;
function GetMap(){
   Microsoft.Maps.loadModule('Microsoft.Maps.Themes.BingTheme', { callback: function() 
       {
           map = new  Microsoft.Maps.Map(document.getElementById('divMap'), 
           { 
              credentials: "Your Bing Maps Key",
              mapTypeId:  Microsoft.Maps.MapTypeId.road,
              enableClickableLogo: false,
              enableSearchLogo: false,
              center: new  Microsoft.Maps.Location(47.603561, -122.329437),
              zoom: 10,
              theme: new  Microsoft.Maps.Themes.BingTheme()
           }); 
       }
    });
}
   
function createSearchManager() {
   map.addComponent('searchManager', new  Microsoft.Maps.Search.SearchManager(map));
   searchManager = map.getComponent('searchManager');
}
function LoadSearchModule() {
   Microsoft.Maps.loadModule('Microsoft.Maps.Search', {  callback: searchRequest })
}
function searchRequest() {
   createSearchManager();
   var query = document.getElementById('txtSearch').value;
   var request =
       {
           query: query,
           count: 20,
           startIndex: 0,
           bounds: map.getBounds(),
           callback: search_onSearchSuccess,
           errorCallback:  search_onSearchFailure
       };
   searchManager.search(request);
 }
function search_onSearchSuccess(result, userData) {
   map.entities.clear();
   var searchResults = result && result.searchResults;
   if (searchResults) {
       for (var i = 0; i < searchResults.length; i++) {
           search_createMapPin(searchResults[i]);
       }
       if (result.searchRegion &&  result.searchRegion.mapBounds) {
           map.setView({ bounds:  result.searchRegion.mapBounds.locationRect });
       }
       else {
           alert('No results');
       }
    }
}
function search_createMapPin(result) {
   if (result) {
       var pin = new Microsoft.Maps.Pushpin(result.location, null);
       Microsoft.Maps.Events.addHandler(pin, 'click', function () {  
  search_showInfoBox(result) });
       map.entities.push(pin);
   }
}
function search_showInfoBox(result) {
   if (currInfobox) {
   currInfobox.setOptions({ visible: true });
   map.entities.remove(currInfobox);
   }
   currInfobox = new Microsoft.Maps.Infobox(
       result.location,
       {
           title: result.name,
           description: [result.address,  result.city, result.state, 
             result.country,  result.phone].join(' '),
           showPointer: true,
           titleAction: null,
           titleClickHandler: null 
       });
   currInfobox.setOptions({ visible: true });
   map.entities.push(currInfobox);
}
function search_onSearchFailure(result, userData) {
   alert('Search  failed');
}

Building the First Mobile App

Let’s create a Windows Phone application from the web application outlined above. If you followed the Getting Started Guides for PhoneGap, you have a project structure with a folder "www" under which the HTML-document, the styles, images and JavaScripts are organized.

CrossPlatformDevtSolutionExplorer

In the head of index.html we need to introduce two additional meta-tags: one to prevent the browser from capturing pinch-to-zoom events and another one that disables format-detection for phone numbers. Next, we need to reference the main PhoneGap / Apache Cordova script.

<head><meta name="format-detection" content="telephone=no" /> 
   <meta name="viewport" 
         content="user-scalable=no, initial-scale=1, 
                  maximum-scale=1,  minimum-scale=1, 
                  width=device-width,  height=device-height, 
                  target-densitydpi=device-dpi" /><script type="text/javascript" src="cordova.js"></script></head>

We also need to verify if the path to the images and style sheets is correct.

In the JavaScript we only need to replace a function that fires in the web browser when the window is loaded with one that PhoneGap has implemented to detect when the app is launched ready to interpret the JavaScript code. We simply search for the following:

window.onload =  GetMap;
…and replace it with
document.addEventListener('deviceready', GetMap, false);

And that’s really it. Run your code in the device emulator or a physical device to check it out.

Porting the App to Other Platforms

There can certainly be a bit of effort required in applying typical styles for the different platforms, but if we just look at a simple user interface and the application logic itself, the porting from Windows Phone to iOS or Android is literally just copy and paste. PhoneGap will take care of the device-specific implementations. We can copy the HTML and JavaScript documents from the Windows Phone project to the Android…

CrossPlatformDevtPackageExplorer

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

…or iOS project…

CrossPlatformDevtXcode

Et voila, we’re done.

 

CrossPlatformDevtScreenshot2