Native geolocation using basicGeo

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:

Native geolocation using basicGeo

Getting ready

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:

Getting ready

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:

Getting ready

How to do it...

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'
};

Adding availability helpers

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();

Adding the location services purpose

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';

Building the recipe UI

This following code snippet describes how to create the UI shown in this recipe's earlier screenshots:

  1. The first step is to create the 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
    });
  2. Next a 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);
  3. The next step in this recipe is to add a 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);

Working with place objects

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 = {
  1. The 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){
  2. The Android reverse geolocation API provides an address field already formatted.
          return place.address;
        }else{
  3. In iOS, the address information is provided as an array of lines. The following method converts these address lines into a formatted string:
          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;
        }
      },
  4. The 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);
  5. A region is created using the latitude and longitude information from the 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);
      }
    };

Finding current location

Perform the following steps to find the current location:

  1. The 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);
  2. On the click event of the findButton, the getCurrentPlace method is called on the basicGeo module's currentGeoLocation proxy.
    findButton.addEventListener('click',function(e){
  3. The 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){
  4. The 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;
        }
  5. The 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;
        }
  6. The first place in the places collection is provided to the 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]);
      };
  7. A new instance of the CurrentGeoLocation proxy is created. This proxy contains methods to perform geolocation operations using the device's current coordinates.
      var currentGeo = my.basicGeo.createCurrentGeolocation();
  8. If the recipe is running on an Android device, the 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);
      }
  9. The final step in returning the device's current address is to call the 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);
    });

Forward location lookup

  1. The 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);
  2. The 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){
  3. The first step in the forward geolocation lookup is to verify that the user entered an address in the txtAddress Ti.UI.TextField.
      if(txtAddress.value.length==0){
        alert('Please enter an address to display'),
      }
  4. The 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;
        }
  5. The 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]);
      };
  6. The next step in performing a forward geolocation lookup, is to call the forwardGeocoder method and provide a callback method as shown in the following line:
      var geoCoder = my.basicGeo.createGeocoder();
  7. In the sample, the 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);
    });

Device capability check

Follow these steps to perform a device capability check:

  1. This recipe requires that the device supports reverse and forward geolocation operations. On load of the main recipe's 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){
  2. The reverseGeoSupported property is checked to determine if the device running the recipe can support running the recipe.
      if(!my.available.reverseGeoSupported){
  3. If the device does not support reverse geolocation, the user is alerted of the possible issues.
        if(my.isAndroid){
          alert("Configuration isn't supported.");
        }else{
          alert('iOS 5 or greater is required'),
        }
      }	
    });	
    win.open({modal:true});

    Tip

    This recipe requires Android 4.0 or greater when running in the emulator due to an Android emulator defect.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.15.99