Mobile Tutorial: Using Location Sensors (iOS and Android)
Go Up to Mobile Tutorials: Mobile Application Development (iOS and Android)
Contents
- 1 Design the User Interface
- 2 The Location Sensor
- 3 Read Location Information (Latitude, Longitude) from the LocationSensor Component
- 4 Show the Current Location Using Google Maps via a TWebBrowser Component
- 5 Use Reverse Geocoding
- 6 Show a Readable Address in the ListBox Component
- 7 Describing Why Your Application Needs the User Location
- 8 See Also
Before starting this tutorial, you should read and perform the following tutorial sessions:
- Mobile Tutorial: Using ListBox Components to Display a Table View (iOS and Android)
- Mobile Tutorial: Using the Web Browser Component (iOS and Android)
- Mobile Tutorial: Using Layout to Adjust Different Form Sizes or Orientations (iOS and Android)
Note: On Android devices, TLocationSensor requires specific Uses Permissions to be set, specifically Access coarse location and Access fine location.
This tutorial describes the basic steps to locate your mobile device (using latitude and longitude), and to use Reverse Geocoding to convert to a readable address, such as in the following picture:
Design the User Interface
This demo application is designed with two major components: a TListBox (on the left-hand side) and a TWebBrowser.
Note: Before proceeding with this scenario, in the Project Manager, set the active target platform to
iOS Device
orAndroid
. Otherwise, you cannot add the TWebBrowser component.
Drop a TListBox and a TWebBrowser component on the form.
- In the TListBox, set the Align property to
Left
to reserve the left side of the UI. Then create the following subcomponents under the ListBox:- A TListBoxHeader component with the following sub-components:
- A TLabel component with the text "Location Demo"
- A TSwitch (Switch1) component to select on/off of TLocationSensor
- A TListBoxGroupHeader with the text "Your Location"
- A TListBoxItem with the name "ListBoxItemLatitude" and "Latitude" as text
- A TListBoxItem with the name "ListBoxItemLongitude" and "Longitude" as text
- A TListBoxGroupHeader with the text "Current Address"
- A TListBoxItem with the name "ListBoxItemAdminArea" and "AdminArea" as text
- A TListBoxItem with the name "ListBoxItemCountryCode" and "CountryCode" as text
- A TListBoxItem with the name "ListBoxItemCountryName" and "CountryName" as text
- A TListBoxItem with the name "ListBoxItemFeatureName" and "FeatureName" as text
- A TListBoxItem with the name "ListBoxItemLocality" and "Locality" as text
- A TListBoxItem with the name "ListBoxItemPostalCode" and "PostalCode" as text
- A TListBoxItem with the name "ListBoxItemSubAdminArea" and "SubAdminArea" as text
- A TListBoxItem with the name "ListBoxItemSubLocality" and "SubLocality" as text
- A TListBoxItem with the name "ListBoxItemSubThoroughfare" and "SubThoroughfare" as text
- A TListBoxItem with the name "ListBoxItemThoroughfare" and "Thoroughfare" as text
- A TListBoxHeader component with the following sub-components:
- A TWebBrowser component (WebBrowser1) to show the Web Page (Google Maps). Set the Align property to
Client
.
After you create these components, select all TListBoxItem items and select listboxitemleftdetail in the StyleLookup property. This allows TListBoxItem to show both a label and detailed text.
The Location Sensor
The location sensor is wrapped by the TLocationSensor component.
TLocationSensor fires an OnLocationChanged event when the device detects movement. You can adjust the sensitivity of TLocationSensor using the Distance and Accuracy properties.
- The Distance property specifies the minimum distance (in meters) by which the device must move in order to make the location sensor relocate the device and return new location information. For example, if you set Distance to "10", TLocationSensor fires an OnLocationChanged event when you move "10 meters".
- The Accuracy property represents the level of precision (in meters) by which the sensor locates the device geographically, relative to the geographical point at which the device is actually located.
- Tip: You should specify the lowest accuracy that works for your application; the higher the accuracy, the more time and power that the sensor requires to determine the location. The recommended values: Distance=0; Accuracy=0.
Read Location Information (Latitude, Longitude) from the LocationSensor Component
The TLocationSensor component needs to be activated for use. You can turn on/off TLocationSensor based on your input, such as a TSwitch component, or other Application events.
- Place a TLocationSensor component from the Tool Palette.
- On the Form Designer, select the TSwitch component.
- In the Object Inspector, in the Events tab double-click OnSwitch event.
- Add the following code to the OnSwitch event handler:
Delphi:
procedure TForm1.Switch1Switch(Sender: TObject);
begin
LocationSensor1.Active := Switch1.IsChecked;
end;
C++:
void __fastcall TForm1::Switch1Switch(TObject *Sender)
{
LocationSensor1->Active = Switch1->IsChecked;
}
As discussed earlier, TLocationSensor fires an OnLocationChanged event when you move the mobile device. You can show the current location (Latitude and Longitude) using parameters with an event handler.
- On the Form Designer, select the TLocationSensor.
- In the Object Inspector, in the Events tab double-click OnLocationChange event.
- Add the following code to the OnLocationChange event handler:
Delphi:
procedure TForm1.LocationSensor1LocationChanged(Sender: TObject;
const OldLocation, NewLocation: TLocationCoord2D);
var
LDecSeparator: String;
begin
LDecSeparator := FormatSettings.DecimalSeparator;
FormatSettings.DecimalSeparator := '.';
// Show current location
ListBoxItemLatitude.ItemData.Detail := Format('%2.6f', [NewLocation.Latitude]);
ListBoxItemLongitude.ItemData.Detail := Format('%2.6f', [NewLocation.Longitude]);
end;
C++:
void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
const TLocationCoord2D &NewLocation)
{
char LDecSeparator = FormatSettings.DecimalSeparator;
FormatSettings.DecimalSeparator = '.';
// Show current location
ListBoxItemLatitude->ItemData->Detail = ListBoxItemLatitude->ItemData->Detail.sprintf(L"%2.6f", NewLocation.Latitude);
ListBoxItemLongitude->ItemData->Detail = ListBoxItemLongitude->ItemData->Detail.sprintf(L"%2.6f", NewLocation.Longitude);
}
Show the Current Location Using Google Maps via a TWebBrowser Component
As discussed in the Mobile Tutorial: Using the Web Browser Component (iOS and Android), the TWebBrowser component wraps a Web browser for mobile platforms.
You can call Google Maps from the TWebBrowser component with the following URL parameters:
https://maps.google.com/maps?q=(Latitude-value),(Longitude-value)
So you can add this URL to your previously created event handler OnLocationChanged as follows:
Delphi:
procedure TForm1.LocationSensor1LocationChanged(Sender: TObject;
const OldLocation, NewLocation: TLocationCoord2D);
var
URLString: String;
begin
// code for previous step goes here
// Show Map using Google Maps
URLString := Format(
'https://maps.google.com/maps?q=%s,%s',
[Format('%2.6f', [NewLocation.Latitude]), Format('%2.6f', [NewLocation.Longitude])]);
WebBrowser1.Navigate(URLString);
end;
C++:
void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
const TLocationCoord2D &NewLocation)
{
// code for previous step goes here
// Show Map using Google Maps
String LLongitude = FloatToStr(NewLocation.Longitude, FormatSettings);
String URLString = "";
URLString = URLString.sprintf(L"https://maps.google.com/maps?q=%2.6f,%2.6f",
NewLocation.Latitude, NewLocation.Longitude);
FormatSettings.DecimalSeparator = LDecSeparator;
WebBrowser1->Navigate(URLString);
}
Use Reverse Geocoding
TGeocoder is an object which wraps the Geocoding (or Reverse Geocoding) service.
Geocoding is the process of transforming geographic data, such as the address and zip code, into geographic coordinates. Reverse geocoding is the process of transforming geographical coordinates into other geographical data, such as the address.
In this case, we use TGeocoder to "Reverse Geocode" our location (in Latitude and Longitude) to readable address information.
Here is the basic sequence of actions with TGeocoder:
- Create an instance of TGeocoder.
- Define an event OnGeocodeReverse so that you can receive the event later.
- Set data to execute "Reverse Geocoding".
- TGeocoder accesses the service on the network to resolve the address information.
- TGeocoder fires an OnGeocodeReverse event.
- Your iOS App receives the address information through the parameter on the OnGeocodeReverse event and updates the user interface.
- Note: As TGeocoder is not a component (this is just a class), you need to define these steps through your code (you cannot drop a component, nor assign an event handler through the Object Inspector).
First, define a new field "FGeocoder" in the private section of the form. You can also define an "OnGeocodeReverseEvent procedure" as in the following code snippets.
Delphi:
type
TForm1 = class(TForm)
// IDE defines visible (or non-visual) components here automatically
private
{ Private declarations }
FGeocoder: TGeocoder;
procedure OnGeocodeReverseEvent(const Address: TCivicAddress);
public
{ Public declarations }
end;
C++:
- Note: Place this code snippet in the header file (.h)
class TForm1 : public TForm
{
// IDE defines visible (or non-visual) components here automatically
private: // User declarations
TGeocoder *FGeocoder;
void __fastcall OnGeocodeReverseEvent(TCivicAddress* const Address);
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
Now you can create an instance of TGeocoder and set it up with data with the following Delphi or C++ code.
TGeocoder.Current gives the type of class that actually implements the Geocoding Service. The code in "TGeocoder.Current.Create
" calls the constructor (Create) for the specified type, and saves it to the FGeocoder field. You also need to specify an event handler, which is fired when TGeocoder completes Reverse Geocoding. Assign OnGeocodeReverseEvent (which you just defined in the previous step) to FGeocoder.OnGeocodeReverse.
Finally, if you successfully created an instance of TGeocoder, and TGeocoder is not running, call TGeocoder.GeocodeReverse with location information. After TGeocoder receives data, the OnGeocodeReverseEvent event is fired.
Delphi:
procedure TForm1.LocationSensor1LocationChanged(Sender: TObject;
const OldLocation, NewLocation: TLocationCoord2D);
begin
// code for previous steps goes here
try
// Setup an instance of TGeocoder
if not Assigned(FGeocoder) then
begin
if Assigned(TGeocoder.Current) then
FGeocoder := TGeocoder.Current.Create;
if Assigned(FGeocoder) then
FGeocoder.OnGeocodeReverse := OnGeocodeReverseEvent;
end;
// Translate location to address
if Assigned(FGeocoder) and not FGeocoder.Geocoding then
FGeocoder.GeocodeReverse(NewLocation);
except
ListBoxGroupHeader1.Text := 'Geocoder service error';
end;
end;
C++:
void __fastcall TForm1::LocationSensor1LocationChanged(TObject *Sender, const TLocationCoord2D &OldLocation,
const TLocationCoord2D &NewLocation)
{
// code for previous steps goes here
// Setup an instance of TGeocoder
try {
if (FGeocoder == NULL) {
if (TGeocoder::Current != NULL) {
FGeocoder = (TGeocoder*)new TGeocoderClass(TGeocoder::Current);
}
if (FGeocoder != NULL) {
FGeocoder->OnGeocodeReverse = OnGeocodeReverseEvent;
}
}
// Translate location to address
if ((FGeocoder != NULL) && (!(FGeocoder->Geocoding()))) {
FGeocoder->GeocodeReverse(NewLocation);
}
}
catch (...) {
ListBoxGroupHeader1->Text = "Geocoder service error";
}
}
Show a Readable Address in the ListBox Component
As described earlier, after Reverse Geocoding is completed, an OnGeocodeReverseEvent is fired.
Next, assign properties in the TCivicAddress address parameter to show readable address information in the list box fields:
Delphi:
procedure TForm1.OnGeocodeReverseEvent(const Address: TCivicAddress);
begin
ListBoxItemAdminArea.ItemData.Detail := Address.AdminArea;
ListBoxItemCountryCode.ItemData.Detail := Address.CountryCode;
ListBoxItemCountryName.ItemData.Detail := Address.CountryName;
ListBoxItemFeatureName.ItemData.Detail := Address.FeatureName;
ListBoxItemLocality.ItemData.Detail := Address.Locality;
ListBoxItemPostalCode.ItemData.Detail := Address.PostalCode;
ListBoxItemSubAdminArea.ItemData.Detail := Address.SubAdminArea;
ListBoxItemSubLocality.ItemData.Detail := Address.SubLocality;
ListBoxItemSubThoroughfare.ItemData.Detail := Address.SubThoroughfare;
ListBoxItemThoroughfare.ItemData.Detail := Address.Thoroughfare;
end;
C++:
void __fastcall TForm1::OnGeocodeReverseEvent(TCivicAddress* const Address)
{
if (Address != NULL){
ListBoxItemAdminArea->ItemData->Detail = Address->AdminArea;
ListBoxItemCountryCode->ItemData->Detail = Address->CountryCode;
ListBoxItemCountryName->ItemData->Detail = Address->CountryName;
ListBoxItemFeatureName->ItemData->Detail = Address->FeatureName;
ListBoxItemLocality->ItemData->Detail = Address->Locality;
ListBoxItemPostalCode->ItemData->Detail = Address->PostalCode;
ListBoxItemSubAdminArea->ItemData->Detail = Address->SubAdminArea;
ListBoxItemSubLocality->ItemData->Detail = Address->SubLocality;
ListBoxItemSubThoroughfare->ItemData->Detail = Address->SubThoroughfare;
ListBoxItemThoroughfare->ItemData->Detail = Address->Thoroughfare;
}
}
Describing Why Your Application Needs the User Location
Before you deploy your final application you should select Project > Options > Version Info, with iOS Device as target, and update the values of NSLocationAlwaysUsageDescription
and NSLocationWhenInUseUsageDescription
with a message that explains why your application is asking for the user location. Your users see this message when your application asks them to authorize iOS to provide the location of the iOS device to your application.
See Also
- Mobile Tutorial: Using Layout to Adjust Different Form Sizes or Orientations (iOS and Android)
- Mobile Tutorial: Using Notifications (iOS and Android)
- Mobile Tutorial: Using Remote Notifications (iOS and Android)
- System.Sensors.TGeocoder
- System.Sensors.Components.TLocationSensor
- Mobile Code Snippets: Notifications
Samples
- Location sample
- VCL Sensors sample