Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In this chapter, you'll learn how to use Titanium's Geolocation API to retrieve GPS positioning and heading information from mobile devices. In addition youYou'll learn best practices with respect to using the APIiOS, Android, and Mobile Web specifics that will help you best balance accuracy with battery consumption. And you'll learn how to manage Geolocation listeners with respect to your application's lifecycle.

Contents

The position and heading APIs are part of the Ti.Geolocation module, which contains all the functions, properties, and events necessary to handle location information. That namespace is further divided into the Ti.Geolocation.Android and Ti.Geolocation.MobileWeb namespaces, which provide platform-specific features. In the following sections, you'll learn how to use this API to perform the following activities:

...

You'll also learn best practices and caveats to consider when using location services in your apps. But first, let's dive into some platform specific considerations when using these services.

Development considerations

iOS Development Considerations

When using location services with iOS, there's one thing you must do in every Titanium app. iOS, as of version 4.0, requires that you specify a 'purpose' when attempting to access a device's location. To make things simple for developers, Titanium provides iOS users are prompted to grant or deny permission when your application attempts to use geolocation information. The system provides a generic prompt for that request. However, according to Apple's guidelines, you should provide a customized message to more clearly tell users why you're requesting their location. You should set the Ti.Geolocation.purpose property . This property equal to the string that will be presented shown to end users in a permissions dialog when they elect to enable location services for your app.

Any valid string is an acceptable value for Ti.Geolocation.purpose. Here's one simple example of setting this property.

Code Block
langjavascript
// set to a message meaningful to your users
Ti.Geolocation.purpose = 'Determine Current Location';
Android Development Considerations

In general, testing geolocation code should be done on a device so that you accurately and realistically test your app in an environment close to a real-world usage scenario. If you plan to test your code in the emulator, you must ensure that the AVD includes GPS emulation, and you'll need to send simulated location coordinates to that AVD.

Adding GPS Support to

...

an AVD

The Android emulator, by default, may not be equipped to handle location services. In order to make sure you have location services enabled for your Titanium Android emulator, follow emulated virtual devices (AVDs) created by Titanium Studio include geolocation hardware emulation. However, if you're using an AVD you defined yourself, such hardware emulation might not be provided. You can enable GPS emulation within the AVD by following these steps:

  • Open the Android SDK and AVD Manager (found at ANDROID_SDK/tools/android)
  • Select your Titanium Android emulator and click the "Edit.." button
  • In the "Hardware" section, see if "GPS support" is listed
    ** If it is, make sure the "Value" field it set to "yes"
    • If not, click the "New..." button
      • From the "property" list, select "GPS support"
      • Click "OK"
      • Make sure the "Value" field for "GPS support" it set to "yes"
  • Click "Edit AVD" then click "OK" in the resulting dialog
  • Restart your Android emulator, if necessary

You have now enabled location services for your Android emulator. But there's still one more thing to consider when testing location services on the Android emulator. It doesn't generate GPS positions itself. You'l need to manually enter via the Dalvik Debug Monitor Service (DDMS).

Sending GPS info via DDMS

In order to send mock locations to the Android emulator, we need to assert that Android has appropriate permissions to do so. Titanium will take care of this automatically, but you can confirm that these permissions are present by going into your project's build/android directory and checking the AndroidManifest.xml file. Within the <manifest> section, you should see a line that looks like this:

Code Block
langxml

<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>

...

Setting a Simulated Location with DDMS

By default, the AVDs (emulators) do not have a default mock location. You must specify a location to use during testing. This also technically a requirement on a device, however the likelihood is very high that you have used some app that has set a location already.

You use DDMS (the Dalvik Debug Manager) to send mock locations to the Android emulator. To do so, follow these steps:

...

To get more information about providing mock locations to your Android emulator, be sure to check out the official Android documentation on the subject. It gives you details not only on manual mock locations, but also using the GPX and KML formats.

Once you've set the mock location, you must grant your app permissions to read that mock location data. You do this by adding an entry to the AndroidManifest.xml file. Fortunately, Titanium will take care of this automatically for you. You can confirm that these permissions are present by going into your project's build/android directory and checking the AndroidManifest.xml file. Within the <manifest> section, you should see a line that looks like this:

Code Block
langxml

<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>

Mobile Web considerations

For geolocation to work with Mobile Web, the user must be running a browser that supports the W3C's Geolocation API. The actual implementation of geolocation, and accuracy provided, is also a function of the user's browser as well as the device on which they're running that browser. As with iOS, Mobile Web apps will prompt users to grant permission to access your location. However, you cannot change the message displayed to users. That message is dependent on the browser he or she uses, but typically follows the form "www.example.com Would like to use your current location."

Using Location Services in your App

Using location services generally follows these three stages:

  1. Determine if location services are enabled and available.
  2. Configure the accuracy and listener mechanisms to use.
  3. Grab a one-time location or enable a location-listener to continually monitor a user's location.
  4. With a location-listener, actively manage the listener in coordination with the app's lifecycle.

Using location services can have a significant impact on a device's battery life, so it's important to use them in the most efficient manner possible. Power consumption is strongly influenced by the accuracy and frequency of location updates required by your application. The higher the accuracy you request, and the more frequently you request location updates, the more battery power that will be consumed.

Detect if Location Services are Available

To determine whether or not location services will be available to you on the current mobile device, you simply need to check the boolean property Ti.Geolocation.locationServicesEnabled. Keep in mind, though, that on Android 2.2 and above, a low-precision "passive" location provider is enabled at all times, even when the user disables both the GPS and Network location providers. Therefore, this method always returns true on such devices. With this in mind, the base skeleton of a locations based app might look something like this.

Code Block
langjavascript
if (Ti.Geolocation.locationServicesEnabled) {
    // perform other operations with Ti.Geolocation
} else {
    alert('Please enable location services');
}

Configure the Accuracy and Frequency

The location services systems of the underlying platforms are very different, so there are significant implementation differences between the platforms. The basic methods of requesting location information and receiving location updates are essentially the same on all platforms. However, the method of configuring the accuracy and frequency of location updates is different for each platform.

iOS Geo Configuration

In iOS, the accuracy (and power consumption) of location services is primarily determined by the Ti.Geolocation.accuracy property setting. You can set this property to one of the following values:

  • ACCURACY_BEST (highest accuracy and power consumption)
  • ACCURACY_NEAREST_TEN_METERS
  • ACCURACY_HUNDRED_METERS
  • ACCURACY_KILOMETER
  • ACCURACY_THREE_KILOMETERS (lowest accuracy and power consumption).

(Note that the constants ACCURACY_HIGH and ACCURACY_LOW are Android-specific and may not be used with iOS.)

Based on the accuracy you choose, iOS uses its own logic to select location providers and filter location updates to provide location updates that meet your accuracy requirements. You can further limit power consumption on iOS by setting the Ti.Geolocation.distanceFilter property to eliminate position updates when the user is not moving. That property accepts a distance in meters; when the user has moved approximately that distance, your app will receive location update events.

  • accuracy - The target accuracy of all location data received. The following Ti.Geolocation constants represent the valid values for this property:
    • ACCURACY_BEST - Location data will be of the highest possible accuracy of which the device is capable
    • ACCURACY_HUNDRED_METERS - Location data will be accurate within 100 meters
    • ACCURACY_KILOMETER - Location data will be accurate within 1 kilometer
    • ACCURACY_NEAREST_TEN_METERS - Location data will be accurate within 10 meters
    • ACCURACY_THREE_KILOMETERS_ - Location data will be accurate within 3 kilometers
  • distanceFilter - The minimum change of position (in meters) before a location event is fired. The default is 0, meaning that location events are continuously generated.
  • headingFilter - The minium change of heading (in degrees) before a heading event is fired. The default is 0, meaning that heading events are continuously generated.
  • preferredProvider - Allows you to specify the preferred method for receiving a location. The following Ti.Geolocation constants represent your possible choices:
    • PROVIDER_NETWORK - Give the network based location provider preference
    • PROVIDER_GPS - Give the GPS location preference

Using the event-driven location example at the beginning of this chapter, let's modify it to use some of the above properties.

Code Block
titleGeolocation configuration on iOS
langjavascript

if (Ti.Geolocation.locationServicesEnabled) {
    Ti.Geolocation.purpose = 'Get Current Location';
    Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_BEST;
    Ti.Geolocation.distanceFilter = 10;
    Ti.Geolocation.preferredProvider = Ti.Geolocation.PROVIDER_GPS;

    Ti.Geolocation.addEventListener('location', function(e) {
        if (e.error) {
            alert('Error: ' + e.error);
        } else {
            Ti.API.info(e.coords);
        }
    });
} else {
    alert('Please enable location services');
}
Android Geo Configuration

Prior to Titanium Mobile 2.0, Titanium attempted to follow the iOS model on Android, but this didn't fit the native Android model well. Android offers a much richer geolocation model, with multiple location providers, distance filters, update frequencies, and so forth. In Release 2.0, three different location service mode are supported on Android: legacy, manual, and simple.

  • Legacy mode is the mode that existed prior to 2.0. Legacy mode is used when you set the accuracy property to one of the iOS ACCURACY constants (see above).
    This mode is deprecated on Android and should not be used for new development. In legacy mode, the specified accuracy value determines the minimum distance between location updates. If accuracy is set to ACCURACY_BEST, no distance filter is used on updates. In legacy mode, only a single location provider (GPS, network, or passive) is enabled at a time. You can specify a the location provider using the Ti.Geolocation.preferredProvider property. You can also specifying a desired update frequency using the frequency property. The preferredProvider and frequency properties are not used in any other mode.
  • Manual mode gives developers low-level control of location updates, including enabling individual location providers and filtering updates, for the best combination of accuracy and battery life. Manual mode is used when the Titanium.Geolocation.Android.manualMode flag is set to true. In manual mode, the accuracy property is not used, and all configuration is done through the Titanium.Geolocation.Android module.
  • Simple mode provides a compromise mode that provides adequate support for undemanding location applications without requiring developers to write a lot of Android-specific code. Setting Ti.Geolocation.accuracy to either ACCURACY_HIGH or ACCURACY_LOW enables simple mode. In this mode the platform handles enabling and disabling location providers and filtering location updates.
Code Block
1Geolocation configuration in Android
langjavascript

// demonstrates manual mode:
var providerGps = Ti.Geolocation.Android.createLocationProvider({
    name: Ti.Geolocation.PROVIDER_GPS,
    minUpdateDistance: 0.0,
    minUpdateTime: 0
});
Ti.Geolocation.Android.addLocationProvider(providerGps);
Ti.Geolocation.Android.manualMode = true;
var locationCallback = function(e) {
    if (!e.success || e.error) {
        Ti.API.info('error:' + JSON.stringify(e.error));
    } else {
		Ti.API.info('coords: ' + JSON.stringify(e.coords));
	}
};
Titanium.Geolocation.addEventListener('location', locationCallback);

See the http://developer.appcelerator.com/apidoc/mobile/latest/Titanium.Geolocation.Android-module.html for further Android-specific information.

Mobile Web Geo Configuration

Location services on Mobile Web operate similarly to the simple mode operations on Android. Setting accuracy property to ACCURACY_HIGH yields the best available location updates, with the highest power consumption. Using ACCURACY_LOW provides lower-quality location updates with lower power consumption. In addition to the accuracy setting, there are several Mobile Web-specific settings.

Code Block
titleGeolocation configuration on Mobile Web
langjavascript

if (Ti.Geolocation.locationServicesEnabled) {
    Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_HIGH;
	Ti.Geolocation.MobileWeb.maximumLocationAge = 15000; // in milliseconds
    Ti.Geolocation.addEventListener('location', function(e) {
        if (e.error) {
            alert('Error: ' + e.error);
        } else {
            Ti.API.info(e.coords);
        }
    });
} else {
    alert('Please enable location services');
}

See the http://developer.appcelerator.com/apidoc/mobile/latest/Titanium.Geolocation.MobileWeb-module.html for further Mobile Web-specific information.

Obtain the Current GPS Position

With your app configured to use the appropriate level of platform-specific geolocation configuration, you're ready to work with location data. Many apps only infrequently need to use location services. Whether it's at app startup, on a button click, or at a timed interval, developers have a multitude of opportunities to actively query for location information.

Let's take a look at a very basic example. After asserting that location services are enabled, the Ti.Geolocation.getCurrentPosition() function is used to query for location information. This function takes a single paramaterparameter; a callback function whose event object contains the requested location in its coords property. This is an asynchronous call as the GPS functionality may take a moment to work, especially if this is the first time your app is accessing location. Also worth noting is that the location services will might return a cached location is your current position cannot be determined(depending on the platform and the configuration choices you have made).

Code Block
langjavascript
if (Ti.Geolocation.locationServicesEnabled) {
    Titanium.Geolocation.purpose = 'Get Current Location';
    Titanium.Geolocation.getCurrentPosition(function(e) {
        if (e.error) {
            Ti.API.error('Error: ' + e.error);
        } else {
            Ti.API.info(e.coords);
        }
    });
} else {
    alert('Please enable location services');
}

...

In order to manage our location events such that we only receive them while our app is active, we need to take advantage of Titanium's access to the Android lifecycle events. There are 3 events that are significantthree events of significance, each of which can be handled via addEventListener() on the Ti.Android.currentActivity object:

...

Just as with location, Titanium has events and functions for both continual and one-time monitoring of heading. Also, check the API docs for platform-specific configuration information of heading options. For continual monitoring, the heading event needs to be registered with the Ti.Geolocation module. In the case of needing only the current heading, a simple call to the Ti.Geolocation.getCurrentHeading() function is necessary. As you may have noticed, this is very similar to how location is handled.

...

Code Block
{
    "accuracy": 3,
    "magneticHeading": 34.421875,      // degrees east of magnetic north
    "timestamp": 1318447443692,
    "trueHeading": 43.595027923583984, // degrees east of true north
    "type": "heading",
    "x": 34.421875,
    "y": -69.296875,
    "z": -1.140625
}

Configure Location Service Properties

You may find when continually monitoring location services that you need additional control over their delivery. With the default configuration, the amount of data returned from location and heading events may be overwhelming. To help this situation, Titanium offers the following properties of the Ti.Geolocation module:

  • accuracy - The target accuracy of all location data received. The following Ti.Geolocation constants represent the valid values for this property:
    • ACCURACY_BEST - Location data will be of the highest possible accuracy of which the device is capable
    • ACCURACY_HUNDRED_METERS - Location data will be accurate within 100 meters
    • ACCURACY_KILOMETER - Location data will be accurate within 1 kilometer
    • ACCURACY_NEAREST_TEN_METERS - Location data will be accurate within 10 meters
    • ACCURACY_THREE_KILOMETERS_ - Location data will be accurate within 3 kilometers
  • distanceFilter - The minimum change of position (in meters) before a location event is fired. The default is 0, meaning that location events are continuously generated.
  • headingFilter - The minium change of heading (in degrees) before a heading event is fired. The default is 0, meaning that heading events are continuously generated.
  • preferredProvider - Allows you to specify the preferred method for receiving a location. The following Ti.Geolocation constants represent your possible choices:
    • PROVIDER_NETWORK - Give the network based location provider preference
    • PROVIDER_GPS - Give the GPS location preference

Using the event-driven location example at the beginning of this chapter, let's modify it to use some of the above properties.

Code Block
langjavascript

if (Ti.Geolocation.locationServicesEnabled) {
    Ti.Geolocation.purpose = 'Get Current Location';
    Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_BEST;
    Ti.Geolocation.distanceFilter = 10;
    Ti.Geolocation.preferredProvider = Ti.Geolocation.PROVIDER_GPS;

    Ti.Geolocation.addEventListener('location', function(e) {
        if (e.error) {
            alert('Error: ' + e.error);
        } else {
            Ti.API.info(e.coords);
        }
    });
} else {
    alert('Please enable location services');
}

Forward and Reverse Geocoding

...

While the above output shows only one place, you'll notice that the places property is an array. This means that on any given call to Ti.Gelocation.reverseGeocoder() you may receive a number of entries in the places property, if multiple places are found in the area of your query.

References

Summary

In this chapter we learned how we can leverage a mobile device's native location services to add the context of a physical location to our apps. Using Titanium's APIs we are able to proactively query or passively listen for a device's current GPS position and heading. By using the configuration properties found in the Ti.Geolocation module like accuracy and distanceFilter we can further refine a location based experience.

...