Android and iOS both provide powerful geolocation platform APIs to find the geographical latitude and longitude of a given address. You can use the basicGeo
module to access these platform APIs in your Titanium module.
This recipe discusses how to leverage this module in your Titanium app to perform forward and reverse geolocation operations. The following screenshots illustrate this recipe running on both an iPhone and an Android device:
This recipe uses the benCode.basicGeo
native module. This module can be downloaded from the source code provided by the book, or individually through the links provided in the See also section at the end of this recipe. Installing these in your project is straightforward. Simply copy the modules
folder into your project as highlighted in the following screenshot:
After copying the modules
folder, you will need to click on your tiapp.xml file in Titanium Studio and add a reference to the bencoding.basicgeo
module as shown in the following screenshot:
Once you have added the bencoding.basicgeo
module to your project, you next need to create your application namespaces in the app.js
file and use require
to import the module into your code as the following code snippet demonstrates:
//Create our application namespace var my = { basicGeo : require('bencoding.basicgeo'), isAndroid : Ti.Platform.osname === 'android' };
With an ever-increasing number of devices each having different capabilities, it is a common requirement to provide progressive enhancements based on the ability of sensors. The availability feature in the basicGeo
module provides a series of properties that can be used to determine the capabilities of the devices. The following snippet shows how to create the Availability
proxy, for later use in this recipe:
my.available = my.basicGeo.createAvailability();
To use location services on iOS, Apple requires a purpose or reason for the app to access the GPS. On first request, this message will be used in the message presented to the user for approval to use their device's location services. The following snippet demonstrates how to add this purpose to the basicGeo
module.
my.basicGeo.purpose = 'Demo of basicGeo';
This following code snippet describes how to create the UI shown in this recipe's earlier screenshots:
Ti.UI.Window
to which all visual elements will be attached.var win = Ti.UI.createWindow({ backgroundColor: '#fff', title: 'benCoding Geo Recipe', barColor:'#000',fullscreen:false });
Ti.UI.TextField
is added to the recipe's Ti.UI.Window
. The contents of this Ti.UI.TextField
will be used during the forward geolocation lookup detailed later in this recipe.var txtAddress = Ti.UI.createTextField({ hintText:'enter address', height:40, left:5, right:60, top:55 }); win.add(txtAddress);
Ti.Map.View
to the recipe's Ti.UI.Window
. This UI component will be used to display the address entered in the txtAddress Ti.UI.TextField
.var mapView = Ti.Map.createView({ top:160, bottom:0, left:5, right:5, userLocation:false }); win.add(mapView);
When performing geolocation lookups, the basicGeo
module returns a collection of places that match the address provided. The placeHelpers
object provides convenient functions for working with the results returned from the basicGeo
module.
var placeHelpers = {
address
function provides a formatted address from a basicGeo
place object. This is used by the "find current location" feature in this recipe.address :function(place){ if(my.isAndroid){
address
field already formatted.return place.address; }else{
var lines = place.addressDictionary .FormattedAddressLines; var iLength = lines.length, address = ''; for (iLoop=0;iLoop < iLength;iLoop++){ if(address.length>0){ address += ' ' + lines[iLoop]; }else{ address = lines[iLoop]; } } return address; } },
addToMap
methods add the place information provided by the basicGeo
reverse geolocation to the Ti.Map.View
created earlier in this recipe.addToMap: function(place){ var lat = place.latitude, lng = place.longitude, title = placeHelpers.address(place); var pin = Ti.Map.createAnnotation({ latitude:lat,longitude:lng, title:title }); mapView.addAnnotation(pin);
basicGeo
module. The setLocation
method is then called to zoom the Ti.Map.View
to the pin's coordinates.var region = {latitude:lat, longitude:lng,animate:true, latitudeDelta:0.04, longitudeDelta:0.04}; mapView.setLocation(region); } };
Perform the following steps to find the current location:
findButton
demonstrates how to perform a reverse geolocation lookup using the device's current coordinates. These coordinates are then used to find the current address of the user.var findButton = Ti.UI.createButton({ right:5, top:55, height:40, width:50, title:'Find' }); win.add(findButton);
findButton
, the getCurrentPlace
method is called on the basicGeo
module's currentGeoLocation
proxy.findButton.addEventListener('click',function(e){
resultsCallback
method is created to handle the results returned by the getCurrentPlace
method. The result from the getCurrentPlace
method is provided to the e
argument.function resultsCallback(e){
e.success
property provides a flag to determine if the geolocation operation has encountered an error.if(!e.success){ alert('Sorry we encountered an error.'), return; }
e.placeCount
property provides the number of place objects returned. Generally, this is a number between 0
and 12
depending on the accuracy. If no places are returned, alert the user that the address was not found.if(e.placeCount === 0){ alert('Unable to find your address.'), return; }
placeHelpers
.address method. This method provides a formatted address string that is then presented to the user in the Ti.UI.TextField txtAddress
.txtAddress.value = placeHelpers.address(e.places[0]); };
CurrentGeoLocation
proxy is created. This proxy contains methods to perform geolocation operations using the device's current coordinates.var currentGeo = my.basicGeo.createCurrentGeolocation();
setCache
method can be called. This enables the basicGeo
module to use the last best location cached by the device. This provides faster lookup speeds, but can result in less accurate location information.if(my.isAndroid){ currentGeo.setCache(true); }
getCurrentPlace
method. This method performs a reverse geolocation lookup using the device's coordinates and provides a collection of places to the provide
callback method. The following snippet demonstrates how to call this method using the resultsCallback
as the callback argument.currentGeo.getCurrentPlace(resultsCallback); });
searchTextAddressButton Ti.UI.Button
performs a forward geolocation lookup using the native device API.var addressOnMapButton = Ti.UI.createButton({ right:5, left:5, height:40, title:'Show address on Map',top:110 }); win.add(searchTextAddressButton);
searchTextAddressButton Ti.UI.Button
on click event performs a forward geolocation lookup using the address entered in the txtAddress Ti.UI.TextField
.searchTextAddressButton.addEventListener('click',function(e){
txtAddress Ti.UI.TextField
.if(txtAddress.value.length==0){ alert('Please enter an address to display'), }
forwardGeoCallback
method is created to handle the results returned by the forwardGeocoder
method. The result from the forwardGeocoder
method is provided to the e
argument.function forwardGeoCallback(e){ if(!e.success){ alert('Sorry we encountered an error.'), return; } if(e.placeCount === 0){ alert('Unable to find address entered.'), return; }
addToMap
method is creating a call using the first place in the places collection. This method will create a pin on the Ti.Map.View
with the place object details.placeHelpers.addToMap(e.places[0]); };
forwardGeocoder
method and provide a callback method as shown in the following line:var geoCoder = my.basicGeo.createGeocoder();
txtAddress.value
and forwardGeoCallback
are provided to the forwardGeocoder
method. The results of the forward geolocation lookup will be provided to the forwardGeoCallback
function as discussed earlier in this recipe.geoCoder.forwardGeocoder(txtAddress.value, forwardGeoCallback); });
Follow these steps to perform a device capability check:
Ti.UI.Window
, the Availability
object created earlier in this recipe is used to alert the user if his/her device can support running this recipe.win.addEventListener('open',function(e){
reverseGeoSupported
property is checked to determine if the device running the recipe can support running the recipe.if(!my.available.reverseGeoSupported){
if(my.isAndroid){ alert("Configuration isn't supported."); }else{ alert('iOS 5 or greater is required'), } } }); win.open({modal:true});
basicGeo
module to perform native geolocation. For licensing, source code, and to learn more about this project, please visit https://github.com/benbahrenburg/benCoding.BasicGeo.3.129.15.99