Friday, May 30, 2014

Offline Mapping with Phonegap Build and mbTiles

Guest post by SilviaTerra intern Jim Miller


One of SilviaTerra's most popular products is Plot Hound, but navigating and mapping becomes tricky when you're deep in the woods without a data connection.

A little over a year ago, this post was created to shed some light on a possible solution where map tiles could be stored locally and then displayed in an HTML5 Mobile App, but it wasn't all that we were hoping for.

Ideally, the map tiles wouldn't be stored in a raw, uncompressed format on the local file system; instead, they could be efficiently stored in an mbTiles database. We wanted something similar to Scott Davis's solution to the problem: accessing an mbTiles database with tiles from MapBox with the Cordova SQLite Plugin and a custom Leaflet Tile Adapter. The dilemma was that there was no supported SQLite plugin for Phonegap Build, so to read an mbTiles database would mean sacrificing the hassle-free compiling and building that Phonegap Build does so nicely.

Finally, with Phonegap Build's feature to add your own plugin, we were able to submit a forked version of Brodysoft's Cordova SQLite plugin with a tweaked plugin.xml to get it to Build's standards. If you are interested in using an SQLite plugin for Android and iOS, feel free to grab his here. This allows us to access an mbTiles database stored on the phone rather than downloading individual tiles. All that was left to do was get the database to the phone and to display the tiles on a map (using a custom TileLayer).

This is the Phonegap app for Android that we made, integrating all of these processes together, and here is the source (most of the work is done in js/main.js).

A few notes on key steps to the final product: The SQLite plugin specifically looks for databases inside /data/data/{your package name}/databases, and because of this we used a few preferences in config.xml to make sure we were always saving to the internal file system of the Android device with the Phonegap FileTransfer API. And a special shout out to Scott Davis again: his custom TileLayer is the basis for js/TileLayer.MBTiles.js with a few modifications to account for a different SQLite plugin.

We're looking forward to integrating this proof-of-concept into Plot Hound in the coming month. Look for future updates on how we continue to develop HTML5 offline mapping technologies.

Saturday, February 16, 2013

Offline Mapping in HTML5 Mobile Apps

One of our top feature requests for Plot Hound has been to add satellite/terrain layers to the cruise maps.  We couldn't just drop in normal Google or Bing Maps because we needed the maps to be available out in the woods with no data connection.

There are fairly straightforward ways to do this in native apps (like offline map caching in the Google Maps Android app and the MapBox iOS SDK), but there aren't great solutions for HTML5 apps built with PhoneGap.  And you have to stay away from using Google's map tiles because they have a pretty restrictive terms of service (MapBox seems to be the current leader in programmatic access to raw map tiles).  The best solution I've seen was by Scott Davis who used MapBox's TileMill to create an mbTiles SQLite database which he then accessed through the Cordova SQLite plugin and a custom Leaflet TileLayer.  The cool thing about this solution is that it leverages SQLite's built-in compression to store map tiles in a really efficient way.

But... there was a problem.  We're heavy users of PhoneGap Build to compile our PhoneGap app, and PhoneGap Build only supports a small set of plugins right now.  And no, the SQLite plugin isn't one of them.

Still, it seemed like I could take the basic structure of Scott's solution but just store the raw tiles locally with the PhoneGap Files API and then point a standard Leaflet TileLayer at the local directory.  My only concern was that the uncompressed raw tiles would be too big to reasonably download.  However, for our use-case (high-zoom on a relatively small area, low-zoom on the surrounding area), it seemed like we might be able to get away with it.  After a quick test in Python, I found that even doing zoom levels 3-17, we only were downloading about 600 tiles totaling about 6MB.  Good enough!

After hacking on it for two days, I came up with a working proof of concept.  The source is available on GitHub.  The instructions and technical details are in the file.  I hope this code is a helpful start for developers trying to add offline mapping to their own apps - it was certainly a fun learning experience for me!

The final results: