See Also: CLLocationManager Members
Starting with iOS 8, developers that want to request access to the location information must request permission from the user to do so before they can receive events. This is done by calling either the CLLocationManager.RequestWhenInUseAuthorization or the CLLocationManager.RequestAlwaysAuthorization methods. When these methods are invoked, the system will prompt the user for authorization, and if he grants it, the CLLocationManager.AuthorizationChanged event will be raised if set (or if you are using the Delegate idiom, the CLLocationManagerDelegate.AuthorizationChanged method will be invoked.
Additionally, developers must add one or both of the keys NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription in their app's info.plist. These keys are strings that can be used to describe why the app needs location access.
Developers should use an idiom like this:
c# Example
var manager = new CLLocationManager(); manager.AuthorizationChanged += (sender, args) => { Console.WriteLine ("Authorization changed to: {0}", args.Status); }; if (UIDevice.CurrentDevice.CheckSystemVersion(8,0)) manager.RequestWhenInUseAuthorization();
The most common use-case for the CoreLocation.CLLocationManager is tracking the device while the application is in the foreground. (See also "Background Updating and Deferred Mode" below.)
Application developers may use either C#-style events or Apple's delegate-object pattern to track foreground location updating. For C#-style events, developers can use the CLLocationManager.LocationsUpdated event:
C# Example
var mgr = new CLLocationManager(); mgr.LocationsUpdated += (sender, e) => { foreach(var loc in e.Locations) { Console.WriteLine(loc); } }; mgr.StartUpdatingLocation();
F# Example
let mgr = new CLLocationManager() mgr.LocationsUpdated.Add( fun e -> e.Locations |> Seq.map Console.WriteLine |> ignore ) mgr.StartUpdatingLocations()
While C#-style events are more concise, the CoreLocation.CLLocationManager must use the delegate-object pattern for certain behaviors (for instance, deferred updating), and it may be more consistent for an application to use the delegate-object pattern even when C#-style events are available. The delegate-object pattern consists of assigning a customized CoreLocation.CLLocationManagerDelegate object to the CLLocationManager.Delegate property of the CoreLocation.CLLocationManager:
C# Example
var mgr = new CLLocationManager(); mgr.Delegate = new MyLocationDelegate(); mgr.StartUpdatingLocation(); //...etc... public class MyLocationDelegate : CLLocationManagerDelegate { public override void LocationsUpdated (CLLocationManager manager, CLLocation[] locations) { foreach(var loc in locations) { Console.WriteLine(loc); } } }
F# Example
let mgr = new CLLocationManager() mgr.Delegate <- new MyLocationDelegate() mgr.StartUpdatingLocation() //...etc... type MyLocationDelegate () = inherit CLLocationManagerDelegate() override this.LocationsUpdated ( manager : CLLocationManager, locations : CLLocation[] ) = locations |> Seq.map Console.WriteLine |> ignore
The CoreLocation.CLLocationManager can track the device's entry and exit from geographical regions (geofences). A region will be a subtype of CoreLocation.CLRegion : either a CoreLocation.CLCircularRegion or a region associated with an iBeacon, of type CoreLocation.CLBeaconRegion.
CoreLocation.CLRegion identity should only be compared via the CoreLocation.CLRegion.Identifier property. Regions are monitored at the operating-system level and new CoreLocation.CLRegion objects with the specified CoreLocation.CLRegion.Identifier may be instantiated by the system when the device enters or exists an area; these CoreLocation.CLRegions will be different objects (myExpectedRegion != myReceivedRegion) but will have the same CoreLocation.CLRegion.Identifier (myExpectedRegion.Identifier.Equals(myReceivedRegion.Identifier, StringComparison.Ordinal)).
Application developers can use either C#-style events or Apple's delegate-object pattern:
C# Example
var rgn = new CLCircularRegion(new CLLocationCoordinate2D(latitude, longitude), 50, "target"); mgr = new CLLocationManager(); mgr.RegionEntered += (s,e) => Console.WriteLine("Entered region " + e.Region.Identifier); mgr.RegionLeft += (s,e) => Console.WriteLine("Left region " + e.Region.Identifier); mgr.StartMonitoring(rgn);
F# Example
let rgn = new CLCircularRegion(new CLLocationCoordinate2D(latitude, longitude), 50, "target") let mgr = new CLLocationManager() mgr.RegionEntered.Add( fun e -> Console.WriteLine("Entered region " + e.Region.Identifier)) mgr.RegionLeft.Add( fun e -> Console.WriteLine("Left region " + e.Region.Identifier)) mgr.StartMonitoring(rgn)
C# Example
var rgn = new CLCircularRegion(new CLLocationCoordinate2D(latitude, longitude), 50, "target"); mgr = new CLLocationManager(); var del = new MyLocationDelegate(); mgr.Delegate = del; mgr.StartMonitoring(rgn); //...etc... public class MyLocationDelegate : CLLocationManagerDelegate { public override void RegionEntered (CLLocationManager mgr, CLRegion rgn) { Console.WriteLine ("Entered region " + rgn.Identifier); } public override void RegionLeft (CLLocationManager mgr, CLRegion rgn) { Console.WriteLine ("Left region " + rgn.Identifier); } }
F# Example
let rgn = new CLCircularRegion(new CLLocationCoordinate2D(latitude, longitude), 50, "target") let mgr = new CLLocationManager() mgr.Delegate <- new MyLocationDelegate() mgr.StartMonitoring(rgn) //...etc... type MyLocationDelegate () = inherit CLLocationManagerDelegate() override this.RegionEntered ( mgr : CLLocationManager, rgn : CLRegion ) = Console.WriteLine ("Entered region " + rgn.Identifier) override this.RegionLeft ( mgr : CLLocationManager, rgn : CLRegion ) = Console.WriteLine ("Left region " + rgn.Identifier)
In iOS 7, Apple introduced iBeacons, which combine region-processing using server and GPS services and nearby promixity ranging using Bluetooth Low-Energy (BLE) signaling.
Once within a CoreLocation.CLBeaconRegion (see previous section), applications may track "ranging" events relating to fine-grained changes in the distance between the device and nearby iBeacons. iBeacon ranging is primarily a function of radio signal strength, which can vary significantly based on environment, electrical noise, etc. Application developers should not attempt to estimate precise distances from the CLBeacon.Proximity or CLBeacon.RSSI properties.
Ranging is done with code similar to:
iBeacons also support "ranging" for determining physical proximity with a higher precision with the Foundation.CLBeacon.Proximity property. The following example shows how ranging should be used as a qualitative measure:
C# Example
locationManager.DidRangeBeacons += (lm, rangeEvents) => { switch(rangeEvents.Beacons[0].Proximity){ case CLProximity.Far : Console.WriteLine("You're getting colder!"); break; case CLProximity.Near : Console.WriteLine("You're getting warmer!"); break; case CLProximity.Immediate : Console.WriteLine("You're red hot!"); break;
F# Example
locationManager.DidRangeBeacons.Add(fun rangeEvents -> let s = match rangeEvents.Beacons.[0].Proximity with | CLProximity.Far -> "You're getting colder!" | CLProximity.Near -> "You're getting warmer!" | CLProximity.Immediate -> "You're red hot!" | CLProximity.Unknown -> "I can't tell" | _ -> raise(ArgumentOutOfRangeException("Unknown argument")) Console.WriteLine(s) ) locationManager.StartRangingBeacons(beaconRegion)
Locations can be updated while the application is in the background. This requires that the info.plist be modified using either Xamarin Studio's visual editor:
Or by adding the key manually:
C# Example
<key>UIBackgroundModes</key> <array> <string>location</string> </array>
Power consumption is an important consideration for all backgrounding scenarios. In the case of location data, GPS-enabled hardware may be able to record and cache accurate location but defer the delivery to the application for some amount of time. This "deferred mode" has several constraints:
If those conditions are satisfied, the application can request deferred delivery when backgrounded by calling the CLLocationManager.AllowDeferredLocationUpdatesUntil method.
Generally, when using Xamarin.iOS, developers can freely choose whether to use C# events or Apple-style "delegate objects" to react to object lifecycle events. Several CoreLocation.CLLocationManager methods, however, require the delegate-object pattern. For instance, CLLocationManager.AllowDeferredLocationUpdatesUntil will raise a runtime exception if the CLLocationManager.Delegate property is not set to an object whose class implements CLLocationManagerDelegate.LocationsUpdated method.