Making Your Application Location-Aware
Making Your Application Location-Aware
One of the things that make mobile applications unique is that they can detect and make use of your current physical location. One of the most famous applications that use this information is foursquare, an app that allows people to “check into” particular places and share this information with others.
For a long time, these kinds of features were only possible with native applications, which had access to lower-level hardware such as the GPS sensor. Again, W3C’s HTML5 team came up with a revolutionary proposal by allowing the browser to access the GPS of your device and expose it through a JavaScript library. In other words, mobile web applications can now be location-aware, thus bridging a huge gap between native and web-based applications. This topic will be central to the discussion in this chapter.
NOTE: For a long time, mobile web applications didn’t have access to low-level hardware, such as the camera or the GPS sensor. However, things are changing—the browser is a native application and has access to low-level hardware APIs, and can expose them to web applications by providing extra JavaScript functions. For the moment, only a few low-level APIs are exposed (e.g., Geolocation and DeviceOrientation events) Camera and contact list access are still unavailable, but with the growing popularity of mobile web applications, it’s likely that such access will be added in the future.
The W3C Geolocation API Specification
The entry point of the W3C Geolocation API is a simple JavaScript function with its callback function:
navigator.geolocation.getCurrentPosition(showMap);
function showMap(position) {
// handle position variable
} This will be sufficient to retrieve our current location; the callback function showMap takes
a position parameter that contains all the information we need to make our application location-aware. Tables 6–1 and 6–2 outline the Position object and its associated Coordinates object.
Table 6–1. The Position Object
Property Name
Type
coords Coordinates timestamp DOMTimestamp
CHAPTER 6: Competing with Native Apps
Table 6–2. The Coordinates Object
Property Name
Type
longitude double latitude double altitude double accuracy double altitudeAccuracy double heading double speed double
That may seem like a lot of information, but for now we are really interested in only two attributes: longitude and latitude, which will be enough to determine our geolocation and eventually display it on a map. So, position.coords.longitude and position.coords.latitude are the properties we want to handle.
Let’s take advantage of the local storage feature discussed previously, and store our position on the browser side when we start our application so we will be able to access this information whenever we want. First, we have to retrieve our location—let’s do that inside the ready function and store the location in the callback function:
$(document).ready(function() {
[..] navigator.geolocation.getCurrentPosition(
function storePosition(position) {
Download from Wow! eBook <www.wowebook.com>
localStorage.setItem('longitude',position.coords.longitude);
localStorage.setItem('latitude',position.coords.latitude);
$("#geolocation") .html("Your position : " + position.coords.latitude + ","+ position.coords.longitude) .css("display","block"); });
}); Notice that at the end of the function we manipulate the geolocation DOM element; this
will be an information banner displayed on the main screen that shows our current position. So we also add a geolocation div element on the main screen:
<div id="geolocation"> </div> Next, we apply some styling: #geolocation {
margin: 8px 6px 2px 6px; padding: 6px 14px;
CHAPTER 6: Competing with Native Apps
background: -webkit-gradient(linear, left top, left bottom, color-stop(0.0, #71D90F), color-stop(0.7, #529E0B)); -webkit-border-radius: 4px; color: white; display: none;
} Start your application, and a pop-up will ask permission to share your location. After
accepting, you should see the screen shown in Figure 6–4.
Figure 6–4. Displaying your geolocation Now that we are sure our location has been retrieved and stored offline, we can enhance
our Task object with the new data. This will be very simple—we just have to change the structure of our Task table by adding two columns: longitude and latitude. And once we save a new task, we just have to retrieve the geoinformation from our local storage. Let’s start by updating our database structure:
// open/create a database for the application (expected size ~ 100K) var db = null;
try { db = openDatabase("todolist", "1.2", "To Do List Database", 100 * 1024);
// check that we have the required tables created db.transaction(function(transaction) {
transaction.executeSql( "CREATE TABLE IF NOT EXISTS task(" + " name TEXT NOT NULL, " + " description TEXT, " + " due DATETIME, " + " completed DATETIME, " +
CHAPTER 6: Competing with Native Apps
" longitude REAL, " + " latitude REAL";"); }); } catch (e) {
db = openDatabase("todolist", "1.1", "To Do List Database", 100 * 1024);
// check that we have the required tables created db.transaction(function(transaction) {
transaction.executeSql( "CREATE TABLE IF NOT EXISTS task(" + " name TEXT NOT NULL, " + " description TEXT, " + " due DATETIME, " + " completed DATETIME);");
db.changeVersion("1.1", "1.2", function(transaction) { transaction.executeSql("ALTER TABLE task ADD longitude REAL;"); transaction.executeSql("ALTER TABLE task ADD latitude REAL;"); }); }
This should remind you of what we did in Chapter 3 to update an existing database. Here we try to open the updated database with its two new columns. If it fails, we can fall back in the catch section and manually alter the existing database.
Next, we refactor our saveTask function: saveTask: function(task, callback) {
db.transaction(function(transaction) { // if the task id is not assigned, then insert if (! task.id) {
transaction.executeSql(
"INSERT INTO task(name, description, due,longitude,latitude) VALUES (?, ?, ?, ?, ?);",
[task.name, task.description,
task.due,parseFloat(localStorage["longitude"]),parseFloat(localStorage["latitude"])],
function(tx) { transaction.executeSql( "SELECT MAX(rowid) AS id from task", [], function (tx, results) {
task.id = results.rows.item(0).id; if (callback) {
callback(); } // if } ); } );
} // otherwise, update else {
transaction.executeSql(
CHAPTER 6: Competing with Native Apps
"UPDATE task " + "SET name = ?, description = ?, due = ?, completed = ?,
longitude = ?, latitude = ? " +
"WHERE rowid = ?;", [task.name, task.description, task.due, task.completed,
parseFloat(localStorage["longitude"]),parseFloat(localStorage["latitude"]), task.id],
function (tx) { if (callback) { callback(); } // if } ); } // if..else }); }
Our application is now totally location-aware; each task is bound to a location. In the next chapters, you will see how to combine this information with maps and process your location against other locations.