Providing Location Service Using DependencyService in Xamarin.Forms
In my previous article "Using Native Platform Features in Xamarin.Forms Through DependencyService," you learned how to implement native features on the iOS and Android mobile platforms, using the three-step design pattern of DependencyService:
- Define an interface.
- Implement it in each platform.
- Use it in your Xamarin.Forms project.
In this article, you will see a concrete use of the DependencyService—getting location information. You will learn how you can display the latitude and longitude of the user from within your Xamarin.Forms application, implemented using the native location service of each platform.
Creating the Project and Declaring the Interface
To begin the project, we will combine the first two steps in the design pattern. Follow these steps:
- Using Xamarin Studio, create a new Blank Xamarin.Forms App project and name it LBS, as shown in Figure 1. Click Next.
- Add an interface file to the LBS project and name it IMyLocation.cs (see Figure 2).
- Populate the IMyLocation.cs file as follows:
Figure 1 Creating and naming the project.
Figure 2 Adding an interface class to the project.
using System; namespace LBS { public interface IMyLocation { void ObtainMyLocation(); event EventHandler<ILocationEventArgs> locationObtained; } public interface ILocationEventArgs { double lat { get; set;} double lng { get; set;} } }
The IMyLocation interface contains the following:
- A method named ObtainMyLocation(), which tries to obtain the user's location on the platform.
- An event named locationObtained, with an argument of type ILocationEventArgs. This event will be called when the platform obtains a new location.
The ILocationEventArgs interface defines a class with two properties—lat (for latitude) and lng (for longitude). This class is for returning the result of the location service.
Implementing Location Service in Android
The following steps implement location service in Android:
- Add a Class file to the LBS.Droid project and name it GetMyLocation.cs (see Figure 3).
- Populate the GetMyLocation.cs file as follows:
- Implement the ILocationEventArgs interface, using the LocationEventArgs class.
- Implement the IMyLocation interface, using the GetMyLocation class.
- In Android, the LocationManager class helps in obtaining location information; hence, the GetMyLocation class also implements the ILocationListener interface.
- Implement four methods of the ILocationListener interface in the GetMyLocation class:
- OnProviderDisabled. Fired when the location service provider has been disabled by the user.
- OnProviderEnabled. Fired when the location service provider has been enabled by the user.
- OnStatusChanged. Fired when the location service provider's status has changed.
- OnLocationChanged. Fired when the location changes.
- Whenever there is a change in location, create an instance of the LocationEventArgs class and set its lat and lng properties. Then call the locationObtained event, passing it a copy of LocationEventArgs.
- The ObtainMyLocation method starts the LocationManager in order to obtain the current location.
- For this example, use the NetworkProvider (using cellular network and WiFi) to obtain the location.
- Double-click the LBS.Droid project and select Android Application (see Figure 4). Select the AccessFineLocation permission.
Figure 3 Adding a class to the project.
using System; using Android.Content; using LBS.Droid; using Xamarin.Forms; using Android.Locations; [assembly: Xamarin.Forms.Dependency(typeof(GetMyLocation))] namespace LBS.Droid { //---event arguments containing lat and lng--- public class LocationEventArgs: EventArgs, ILocationEventArgs { public double lat { get; set;} public double lng { get; set;} } public class GetMyLocation: Java.Lang.Object, IMyLocation, ILocationListener { LocationManager lm; public void OnProviderDisabled (string provider) { } public void OnProviderEnabled (string provider) { } public void OnStatusChanged (string provider, Availability status, Android.OS.Bundle extras) { } //---fired whenever there is a change in location--- public void OnLocationChanged (Location location) { if (location != null) { LocationEventArgs args = new LocationEventArgs(); args.lat = location.Latitude; args.lng = location.Longitude; locationObtained(this, args); }; } //---an EventHandler delegate that is called when a location // is obtained--- public event EventHandler<ILocationEventArgs> locationObtained; //---custom event accessor that is invoked when client // subscribes to the event--- event EventHandler<ILocationEventArgs> IMyLocation.locationObtained { add { locationObtained += value; } remove { locationObtained -= value; } } //---method to call to start getting location--- public void ObtainMyLocation () { lm = (LocationManager) Forms.Context.GetSystemService( Context.LocationService); lm.RequestLocationUpdates( LocationManager.NetworkProvider, 0, //---time in ms--- 0, //---distance in metres--- this); } //---stop the location update when the object is set to // null--- ~GetMyLocation() { lm.RemoveUpdates (this); } } }
The code above performs the following tasks:
Figure 4 Adding a permission to the project.
That's it for the Android project.
Implementing Location Service in iOS
Follow these steps to implement location service on iOS:
- Add a Class file to the LBS.iOS project and name it GetMyLocation.cs (see Figure 5).
- Populate the GetMyLocation.cs file as follows:
- The code above performs the following tasks:
- Implement the ILocationEventArgs interface, using the LocationEventArgs class.
- Implement the IMyLocation interface, using the GetMyLocation class.
- iOS uses the CLLocationManager class to obtain location information. To obtain the user's location, request the user's approval by calling the RequestWhenInUseAuthorization() method.
- When authorization is given, call the AuthorizationChanged event of the CLLocationManager class. Then start updating the locations.
- When a new location is obtained, fire the LocationsUpdated event. Pass the locations in through an array, with the last element being the most recent location. Create an instance of the LocationEventArgs class and set its lat and lng properties. Call the locationObtained event and pass a copy of LocationEventArgs to it.
- In the Info.plist file of the LBS.iOS project, add a new key and set its value as shown in Figure 6.
Figure 5 Adding a class to the project.
using System; using CoreLocation; using LBS.iOS; [assembly: Xamarin.Forms.Dependency(typeof(GetMyLocation))] namespace LBS.iOS { //---event arguments containing lat and lng--- public class LocationEventArgs: EventArgs, ILocationEventArgs { public double lat { get; set;} public double lng { get; set;} } public class GetMyLocation: IMyLocation { CLLocationManager lm; //---an EventHandler delegate that is called when a // location is obtained--- public event EventHandler<ILocationEventArgs> locationObtained; //---custom event accessor when client subscribes // to the event--- event EventHandler<ILocationEventArgs> IMyLocation.locationObtained { add { locationObtained += value; } remove { locationObtained -= value; } } //---method to call to start getting location--- public void ObtainMyLocation () { lm = new CLLocationManager(); lm.DesiredAccuracy = CLLocation.AccuracyBest; lm.DistanceFilter = CLLocationDistance.FilterNone; //---fired whenever there is a change in location--- lm.LocationsUpdated += (object sender, CLLocationsUpdatedEventArgs e) => { var locations = e.Locations; var strLocation = locations[locations.Length-1]. Coordinate.Latitude.ToString(); strLocation = strLocation + "," + locations[locations.Length-1]. Coordinate.Longitude.ToString(); LocationEventArgs args = new LocationEventArgs(); args.lat = locations[locations.Length-1]. Coordinate.Latitude; args.lng = locations[locations.Length-1]. Coordinate.Longitude; locationObtained(this, args); }; lm.AuthorizationChanged += (object sender, CLAuthorizationChangedEventArgs e) => { if (e.Status == CLAuthorizationStatus.AuthorizedWhenInUse) { lm.StartUpdatingLocation(); } }; lm.RequestWhenInUseAuthorization (); } //---stop the location update when the object is set to // null--- ~GetMyLocation() { lm.StopUpdatingLocation(); } } }
Figure 6 Adding a new key to the Info.plist file.
This key is needed to obtain permission from the user so that your app can obtain location information.
Using the GetMyLocation Class
Now that both platforms have implemented the IMyLocation interface, you are ready to use them in your Xamarin.Forms project. Follow these steps:
- Add the following statements in bold to the LBS.cs file:
- The code above performs the following tasks:
- Add two Label views on the ContentPage to display the latitude and longitude of the location.
- Obtain an instance of the implementation of the IMyLocation interface in the OnStart() method.
- Handle the locationObtained event and display the location details in the two Label views whenever a new location is obtained.
- Call the ObtainMyLocation() method to start getting location information.
using System; using Xamarin.Forms; namespace LBS { public class App : Application { Label lblLat, lblLng; IMyLocation loc; public App () { lblLat = new Label { XAlign = TextAlignment.Center, Text = "Lat", }; lblLng = new Label { XAlign = TextAlignment.Center, Text = "Lng", }; // The root page of your application MainPage = new ContentPage { Content = new StackLayout { VerticalOptions = LayoutOptions.Center, Children = { new Label { XAlign = TextAlignment.Center, Text = "Current Location" }, lblLat, lblLng } } }; } protected override void OnStart () { // Handle when your app starts loc = DependencyService.Get<IMyLocation> (); loc.locationObtained += (object sender, ILocationEventArgs e) => { var lat = e.lat; var lng = e.lng; lblLat.Text = lat.ToString(); lblLng.Text = lng.ToString(); }; loc.ObtainMyLocation (); } protected override void OnSleep () { // Handle when your app sleeps loc = null; } protected override void OnResume () { // Handle when your app resumes } } }
Testing the App
To test the application on the iPhone Simulator, right-click the LBS.iOS project and select Run With > iPhone 6 iOS 8.3. You will be prompted for your permission to access your location (see Figure 7). Click Allow.
Figure 7 Testing the application on the iPhone Simulator.
To simulate getting locations on the iPhone Simulator, select Debug > Location > Freeway Drive. In Figure 8, the iPhone Simulator shows the locations it obtained.
Figure 8 Obtaining the locations on the iPhone Simulator.
You can test the Android project on a real Android device. Right-click the LBS.Droid project and select Run With > <Android Device Name>. Figure 9 shows the application displaying the locations it obtained.
Figure 9 Testing the application on an Android device.
Summary
In this article, you learned how location services can be implemented in Xamarin.Forms. While Xamarin.Forms focuses on the user interface, it also provides an elegant way for platforms to invoke native features, and location service is one such example. In the next article in this series, I will show how you can add a map to display your current location.