Towards a native maps plugin for PhoneGap/Cordova and Android

I recently did some prototyping for a native maps plugin for Android.  For iOS/phonegap, you have the mapkit plugin which I was able to get working on phonegap 2.0, with some help from the google group.  But for Android, the concensus seems to be that you should use the web version of Google Maps (either the javascript version or the static map images).  While that advice works for a subset of users, if you pull out your Android phone and compare the performance between the web version of Google Maps and the native app, you’ll quickly choose the native app.

There are two paths forward for a native map plugin.  The main limiting factor is that a native map view is only instantiable by a MapActivity,”because it depends on threads which access the network and filesystem in the background; these threads must be shepherded by the lifecycle management” of the MapActivity.

So, you can either:

  • have your app be managed by a MapActivity and embed a Cordova webview in the app.  This would probably work well for apps that are really really map heavy, and only have a slight bit of webUI.  I’m not sure what value PhoneGap brings to that type of app, though.  It also seems pretty complex.
  • or have the PhoneGap app transition from DroidGap activity to the MapActivity and then back.
I went with the second choice.  As I said, this was an exploration, so there are plenty of problems that I skipped that will need to be solved to have a robust plugin:
  • which activity/technology gets the points to display initially
  • which activity/technology gets points as the map is moved around
  • testing on a real device (what do you do when you are running an Android device without native Google maps)
  • passing full featured events back and forth between PhoneGap and the MapActivity

 


More details on moving away from Google Maps

Well, our move from Google Maps to MapQuest is pretty much done (the start was mentioned here), so I thought I’d give a more exhaustive overview, including some more insight into our thinking.  For context, we, in this post, refers to 8z Real Estate, a real estate brokerage with a great website that drives a huge chunk of business.  (Of course, errors and opinions expressed here are all mine.)

First, if you are considering switching from Google Maps, definitely think about not leaving!  Depending on your customizations, it can be a real pain.  You can also think about it in terms of spending dollars with Google or spending dollars with your developers.

A good place to start is to make sure you know how many map views you are using.  I found three good ways to do this.

  • estimate using your web analytics tools (page A uses 1 map, and is viewed X times a day, page B uses two maps and a streetview and is viewed Y times a day).  This has the benefit of being free and in your control, and not requiring you to make any code changes.  It has the detriment of being imprecise, especially if you are displaying maps via javascript that might not be tracked by your analytics tool.  I used six months of our highest traffic days to get a feel for maximum map views per day.
  • ask a Google sales rep.  This has the benefit of being very precise–they can tell you how many map views they recorded for you on a given day, and, again, doesn’t require any code changes.  It has a number of downsides, though.  First, you have to get ahold of Google sales (using the ‘contact sales’ button here).  I had to submit this form at least twice before I got a call from them.  Second, you have to interact with a live person.  And third, they only have information for a single day.
  • install the new Google Maps API key and look at the API console.  The upside to this is that reviewing your usage doesn’t have any external dependencies and the console  is very precise in tracking your usage.  The downside is that you are now on Google’s radar, and it may require a bit of work (depending on when you added Google Maps to your site).

We actually ended up using all three of these methods at different times, but found the API console to be the best option long term because it is the most accurate.

Once you’ve found your map view usage, check out the usage limits, which will inform your decision.  Two other considerations before you decide to move off the free Google Maps.

  • If you have used the free Google geocoding service, you should re-geocode all your points, as it is outside the terms of service to display these points anywhere other than on a Google map.
  • It is unclear to me when they will start the clock on the new usage limits (as announced here).  I read the new terms carefully, and you have a grace period of three months (you have to be above the free limit for three months straight) before charges start.  Note however, that once you are over for the grace period, you never can get back into it (100 days of over 25K usage followed by 3 years of under it followed by 1 day over it will still result in charges for that 1 day overage).  Additionally, Google will give a months notice of the usage limits enforcement on the Google Geo Developer blog.  That means that you’ll have at least four months of lead time.  And note that they’ve moved the enforcement deadline at least once.

Ok, you’ve decided that it simply isn’t worth the risk, and that you need to take action to avoid being charged for Google Maps lickety split.  If you haven’t, godspeed.

The options for avoiding being charged are outlined very clearly:

  • Decrease your usage
  • Pay for a license
  • Pay for daily overages

Armed with your daily usage information (don’t forget to factor in traffic increases), you can see which of these options makes the most sense.  Contact Google enterprise sales if you feel a license purchase makes sense.  Be aware that the 25K daily limit works out to over 9M map views a year.  So if you are buying a license just to deal with daily traffic (as opposed to wanting the application to live on an intranet or some other non publicly available location, or a seasonal traffic spike), you’ll want to price out at least a 10M view license.

Once I got to talking to the Google representative, it became clear that the map license was pretty expensive.  The price range for a 30M license ranged from the mid 5 figures to the low 6 figures, per year.  We also looked at daily overages as an option.  Unfortunately this turned out to be hundreds of dollars a day.  Neither of these solutions made sense economically, so we decided to spend developer hours instead of dollars to decrease our Google Maps usage.

There are two ways to decrease Google Map usage, of course.  You can decrease use of maps all around (for example, by not having maps show up unless a user takes some action or removing extra maps), or you can migrate some or all of your current Google Maps to a different provider.

We tried both paths forward.  We removed some extra maps from the site (again, determined by our usage data), but that didn’t reduce usage enough, and also impacted users (as determined by email complaints!).

Therefore, we determined it was better to show the javascript maps every time.  We also had a technical wrinkle.  We use GWT  and are locked into Google Maps v2 (due to dependence on this library).  Google Maps v2 will no longer be supported in 2013.  I don’t believe there is a supported GWT binding for Google Maps v3, although that may get written later (here are two open source, non Google supported bindings that I found: http://code.google.com/p/gwt-google-maps-v3/ and http://code.google.com/p/gwt-maps3/ that may solve the problem for others).  Since v2 was deprecated on May 19, 2010, we knew we’d have to revisit Google Maps in the next year (by May 19, 2013, at worst), so that meant a hybrid solution (part Google Maps, part some other provider) was less appealing than otherwise.

We looked at a few different contenders to replace Google Maps.  Our criteria included:

  • quick to set up
  • accurate display
  • free for our usage leverl
  • close in features to Google Maps, at least the features we used
  • looked good

In the end, I prototyped three solutions that met the first four criteria above, and asked the team for feedback on the fourth.

The solutions included:

Some options that might be worth looking at for some, but didn’t work for us were:

  • Bing Maps, which we ignored due to license limits
  • Google Maps v3.  This version has significantly cheaper overages, so if you are right around the 25K usage, that might be worthwhile, but we were way over 25K mapviews, and also, as mentioned above, had GWT ties to v2.
  • Rolling our own maps (ht briantimoney).  I think this wasn’t the right solution for us two reasons.  One, we were looking for something that was a relatively easy ‘drop in’ replacement for Google Maps, and crunching a bunch of map tiles didn’t seem to fit that requirement.  Two, I’m not sure there’s a lot of value in unique maps for our real estate web application (though there is in having points of interest and accurate mapping of properties).

We ended up choosing the Mapquest Javascript API for the best look and feel.

The next step was to update the pages where maps were used.  There were two main types of pages that used maps.  One type of page showed a single property on a map.  The other showed multiple markers on a map, as results of a search.

The single property page was trivial to replace.  There were a couple of interesting wrinkles.  The first was replacing the default marker icon.  I had to tweak the iconoffset and shadowoffset properties of the icon object for correct display.  Additionally, the new map had to be displayable from GWT.  This required a JSNI method run in a deferred command, in order to make sure that the MapQuest javascript has loaded.

Based on map usage data, I was hoping we could get by just replacing the single property maps, but this didn’t decrease our map usage enough.  On to search results! (If you aren’t interested in GWT, you can skip to the bottom of this post, as the next section is all about GWT gyrations.)

Replacing the search results was slightly more complex.  I reviewed all the current code and categorize our existing GWT/Google Maps based functionality into three groups.

  • functionality that the MapQuest API could exactly replicate (putting a marker on a map)
  • functionality that the MapQuest API had an equivalent for (displaying information on click of a marker)
  • functionality that we had previously built but, in the name of simplification, weren’t going to port to the MapQuest based solution

After this categorization was done, it was fairly simple to port the needed functionality from GWT to javascript (jQuery/MapQuest).

One additional twist is formatting code shared between GWT and java (displaytag decorators, among other code).  The MapQuest javascript needed to be able to call that formatting code, as well as other GWT functionality (for example, creating a lightbox).  No sweat, right?  Here’s an example of calling GWT code from javascript.  The javascript that was calling the GWT code was running in a windows.load jQuery anonymous function.

Well, that worked fine in FF, and often in Chrome, but I was getting an error message from Chrome occasionally and IE all the time.  The Chrome error was pretty clear: ReferenceError: gwtListingUtilgetMLSIDLogoandOfficeName is not defined (gwtListingUtilgetMLSIDLogoandOfficeName is the name of one of the GWT methods that was exported for javascript to use).  The issue was that the map javascript was executing before the GWT code was fully loaded, and not finding methods it was expecting.

The solution was to chain the javascript, so that the map javascript was run via a GWT JSNI call after GWT was fully loaded, and all needed GWT functions were exported.  To provide for other GWT on load chaining, I used the onload pattern outlined here and created an addGWTOnLoadEvent.

Then I needed to create an anonymous function that GWT could call after it was loaded .  So, to recap the path of the map creation code (because it is kind of confusing to me):

  • on page load, addGWTOnLoadEvent(startupSearchMap()); where startupSearchMap returns an anonymous function
  • in GWT code, we export needed GWT functions to javascript: $wnd.gwtListingUtilgetMLSIDLogoandOfficeName = function(mlsId, source Id, baseImageURL, officeName, listingStatus, withBreaks) { return @com.cohomefinder.util.sharedwithgwt.ListingUtil::getMLSIDLogoandOfficeName(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)(mlsId, sourceId, baseImageURL, officeName,listingStatus,withBreaks);};
  • at the end of the export JSNI function, we call gwtonload: if ($wnd.gwtonload) { $wnd.gwtonload(); }
  • which executes the anonymous function returned by startupSearchMap which then binds to the DOM element and creates the map.  Needed GWT functions are guaranteed to be present.

This would all be a lot simpler if we didn’t have valuable code written in GWT, but that is a sunk cost that I don’t ever see rewriting.

After that, it was all just testing and making a few UI tweaks.  However, the depth and maturity of the MapQuest API and community scared me a bit, with forums that weren’t as deep as the Google Maps groups I had been accustomed too, and with posts like “IE9 not supported” by the latest MapQuest API.  The API documentation was also underwhelming, with plenty of methods undocumented.  But it all worked out.  If I was doing some aggressive, bounds pushing map functionality, I don’t know if these concerns would have been more of a hindrance.

So, to recap, if you are thinking about moving off of Google Maps:

  • find out your map views per day
  • consider usage solutions that allow you to remain with Google Maps
  • if you must move off of Google Maps, consider all other solution providers and find the one that fit
  • make sure you replicate your current functionality with the map provider you choose

In general, I would rather not have moved off Google Maps (it felt like running just to keep in place, and Google Maps is a great product), but the economics dictated this choice.  I hope this post helps you decide if moving off Google Maps is right for you.


Moving away from Google Maps

A while back I wrote about Google Maps charging.  This caused an uproar around many map dependent sites.   (Brian Timoney, ever reliable, delivers snark on that front.)

I, for one, don’t begrudge Google the chance to charge for their excellent product.  What that does, however, is make certain business models that were previously viable now unviable.  That is, if they remain with Google Maps.  In my previous post, I went over some alternatives.

The company I work for, after evaluating all the alternatives, including paying Google for a license, has decided to go with Mapquest.  While the API is not as gorgeously documented (both on the company site and on the web), it has the same licensure as Google Maps used to (free for any publicly accessible website), with much of the same base functionality.

I’ll be very interested to see how many people are doing such high value work with Google maps that they can afford to pay for licenses or per use.


Google Maps is now charging

…if you reach a certain number of mapviews.  You have up to 25K/day mapviews free, which works out to just over 9 million map views a year.  My understanding of those limits is that they are per-business, not per domain or site.  Here’s the announcement on their blog.

Alternatives for javascript map generation:

Google Maps has made mapping ubiquituous (I’m sure Brian Timoney would agree), and in doing so has done the web a great service.  It will be interesting to see what happens as they try to charge for this service.


Gray Tiles with Google Maps

Just thought I’d put this out there, since it caused me much gnashing of teeth.  If you have google maps on your site, you want to make sure that the max-width is set to none: div.google-maps img{ max-width: none; } or you’ll have a nice gray screen where your maps are supposed to be, but no error messages at all.  See below:

Google Map with Just Gray Tiles


Google Maps API versioning

The Google Maps API is constantly changing–they say they are releasing weekly.  Of course, no one is perfect, so sometimes bugs appear.  First, you should read this about maps API updates:

The v parameter within the http://maps.google.com/maps?file=api&v=2 URL refers to the version number of the Google Maps API to use. Most users of the API will want to use the current “Version 2″ API by passing the v=2 parameter within that URL. You may instead obtain the latest release (including the latest features) by passing v=2.x instead. However, be aware that the latest release may not be as reliable as the v=2 release. We update the Google Maps API often (sometimes every week), at which point features within the v=2.x release are migrated into the v=2 release unless problems are discovered.

If you want to know exactly what version of code you are pulling down when you put a ‘v=2′ on your maps javascript load, view this API changelog page on the google maps wiki.


Announcement: FRUGOS GeoSummit 2007

One of my clients is helping out with this unconference. If you’re into GIS, it seems like it’d be worth going. I certainly had fun at the last unconference I went to.  I am planning to attend; hope I see you there.
———————–

FRUGOS (Front Range Users of Geospatial Open Source) is holding its
first GeoSummit on Saturday, June 16th at Churchill Navigation–100
Arapahoe–in Boulder.

This will be a unique gathering of a variety of folks interested in
Place–geo-types, hackers, academics, artists, amateur enthusiasts,
etc. While there certainly will be representation from the GIS and open
source worlds, we encourage all who are fascinated about the
intersections of technology and engagement with the world around us to
participate.

Also, we’ll be structuring the day around the “un-conference” model (see
http://www.barcamp.org), so, for starters, you
can expect:
No Pitches
No PowerPoint
No Passivity (unless you’re a little sleepy after lunch)

Bring your laptop (we’ll have wireless), and a project or enthusiasm
you’d like to talk about with the group, get feedback, and collaborate
on fresh solutions: the agenda of the day will be structured during
the morning registration/sign-up/socializing period.

If interested–
1) RSVP by joining the Google Groups set up for this event–

http://groups.google.com/group/geosummit

2) Bring a laptop (and cellphone/GPS if your enthusiasms tilt that
way), your idea/project, and willingness to collaborate

3) Spread the word

Tentative Schedule

9:30-10:30AM Registration, refreshment, socializing
10:30-12ish Sessions
12ish-2 Lunch (there’s a grill, beverages, and hiking trails)
2-? Sessions

This promises to be a great combination of creativity, intellectual
engagement, eating and drinking, and socializing.

————————

Technorati Tags: , ,



Comments on upgrading to version two of Google Maps

I recently upgraded a simple simple Google Map that I built last spring to display some of the cross country skiing around Boulder. You can see the original version here. I built this based on this XML.com article, using XMLHttpRequest to retrieve the data from the server and Gmarker.openInfoWindoXSLT() with this XSL stylesheet to present the data.

I decided to upgrade this map last week to version two. Since openInfoWindowXSLT is no longer supported on every browser, I feared that the upgrade would take significant effort, even though the map very simple. However, the upgrade ended up being easier than I thought it would be. To get started, I read the Google Upgrade Guide–this document explains just what changes were made in the API. The changes that affected my map included:

  • A few method name changes–centerAndZoom becomes setCenter
  • GPoint is no longer used to indicate a latitude and longitude location on a map, and its replacement, GLatLng, reverses the order of the constructor’s arguments.
  • Zoom levels are flipped around, with larger numbers now signifying higher resolutions
  • The biggest effort was modifing the code not to use the XSLT process for generating infoWindows. However, this was easier than I thought it would be. I simply wrote a javascript method that mimicked what the XSL had previously done. Sure, accessing the DOM elements was a bit of a hassle that required some debugging (that’s the win of XSL–declarative DOM access), but the alternatives were either ignore browsers that don’t have built-in XSLT support (Safari) or integrate AJAXSLT, a Google sponsored project to provide cross browser XSLT support. If this were a larger project that depended on more XSLT, I probably would have done the latter.

Upgrading my (admittedly very simple map) took about 1.5 hours. Visit the new map and take a look at the code.

Technorati Tags:


Book Review: Google Maps API V2

Seven months ago, I wrote about Google Maps Gotchas. I mentioned Scott Davis’ Google Maps API Pragmatic Friday article, published by the Pragmatic Programmer folks. Well, a few things have happened since then. In April, Google released version two of their maps API (though they still haven’t set a date when version one will no longer be supported), Scott revised his article and I spent a tax deductible $8.50 to give it a read. What you’ll find below is my take on his article.

The good: first, the ordering was easy, and I received my custom PDF (complete with “Prepared Exclusively for Daniel Scott Moore” as a footer on every page) in less than 20 minutes. Scott explains in a very easy to understand fashion how to create a map. He also covers each of the API’s javascript objects and how to use them. In particular, I thought the list of events and objects that fire them (in the ‘Events’ chapter) was a good reference. Now, Google provides a class reference, but Scott’s are a bit easier to understand here’s a comparison, for the Gmarker class:

Google API:

A GMarker marks a position on the map. It implements the GOverlay interface andthus is added to the map using the GMap2.addOverlay() method.A marker object has a point, which is the geographical position where the marker is anchored on the map, and an icon. If the icon is not set in the constructor, the default icon G_DEFAULT_ICON is used.

After it is added to a map, the info window of that map can be opened through the marker. The marker object will fire mouse events and infowindow events.

Davis’ Book:

In the Core Objects section, we introduced the GLatLng. A GLatLng stores a Latitude / Longitude coordinate, but it doesn’t offer you a way to visualize it on a map. A GMarker is the way to add GLatLngs GMarker to the map for display purposes. The GMarker constructor takes a GLatLng as the only required argument.Once we have the marker, we need to tell the map to display it; map.addOverlay(myMarker) should do the trick. (Objects that you superimpose over the map are called Overlays.) You can remove the Overlays marker using map.removeOverlay(myMarker). To remove all overlays, use map.clearOverlays( ).

var myPoint = new GLatLng(38.898748, -77.037684);
var myMarker = new GMarker(myPoint);
map.addOverlay(myMarker);

Theoretically a map can support an unlimited number of markers, but anecdotal evidence suggests that performance starts to slow down significantly after a hundred or so markers. (File under, “Doc, it hurts when I do this.”)

I liked the real world examples–the fact that you could click through and see the code Scott was writing about in action on his website is a real plus. In addition, he builds a decently complex example in Chapter 7 where the user can add and delete cities. He also gives a good warning about examples that use Gmap, rather than Gmap2.

However, there were some issues. Scott’s coverage of the upgrade to version two of the API is, unfortunately, rather spotty. In his blog, the June release of that feature, and the April revision of the book). He also doesn’t cover GDownloadURL, a convenience method for XMLHttpRequest processing, or the GUnload methods. I’ll freely admit that the maps API is a moving target, and some of the omissions above may be due to that.

However, there are other problems. Though billed as a beginner book, he omits what I consider to be one of the fundamental challenges of Google Maps development–the performance obstacles large numbers of database driven markers (other than the comment mentioned above in the GMarker reference). In addition, he doesn’t cover design options, nor cross browser issues (like the transparent PNG in IE issue).

In the last chapter, he mentions good examples of mapping websites, but Scott omits references to useful websites–something that even dead tree books do. In particular, he doesn’t mention mapki.com (a wiki full of useful user provided data) nor the Google Maps group (which some users consider a primary differentiator between Google and Yahoo Maps).

One final gripe is that the 75 pages of content that I expected were really only 45–text only filled about 60% of the column width. I expect that in articles I read for free on the web, but in books that I pay for, I like a bit higher content to page ratio.

In short, this ebook is a good choice for the first time Google Maps builder. This is due to the tutorial nature of much of the book, the examples, and the explanation of typical good javascript code, such as using anonymous functions for the event handlers. It is not entirely adequate in covering version 2 of the API, possibly due to API changes, and it ignored some of the more complex aspects of the API.

If you’re looking for a folksy introduction to Google Maps api, it’s worth the $8.50 to have a coherent guide. If you’ve muddled through one google maps project, piecing together things from the API docs and various blogs, it becomes less worthwhile. But if you want some kind of discussion about complex Google Maps issues this document is not the right place to look.

Technorati Tags: , ,



© Moore Consulting, 2003-2010 +