« MBS @ FMTraining.TV -… | Home | MBS Plugin Advent cal… »

MBS Plugin Advent calendar: 8 - Determine your own position

Door 8 - Determine your own position (for Mac users)

Fact of the day
A man from Munich parked his car in a parking lot in 2015 and was unable to find it again. The car was reported stolen in the meantime. After around 6 months, he was informed by the parking garage company that his car was still in the parking lot. This man should have remembered his location ;-)

Today I would like to show you how you can determine your own position as a Mac or iOS SDK user. The CoreLocation component is available for this purpose.

If you want to use this option in your apps, we need authorization. We can request various authorizations. The Always authorization requests permission to use location services whenever the app is running. The next weaker authorization is the when in use authorization. It Requests permission to use location services while the app is in the foreground. There is also the temporary full accuracy authorization. This access will expire automatically, but it won't expire while the user is still engaged with your app. In our example, we use the Always authorization. If the authorization fails, please check the settings in Security. You can check whether the authorization was successful using the CoreLocation.authorizationStatus function. It displays the current authorization status. The following responses are possible.

notDetermined The user has not yet made a choice regarding whether this app can use location services.
restricted This app is not authorized to use location services.
denied The user explicitly denied the use of location services for this app or location services are currently disabled in Settings.
authorizedAlways This app is authorized to start location services at any time.
authorizedWhenInUse This app is authorized to start most location services while running in the foreground.

In the example, I will show you how you can deal with a situation where the authorization does not correspond to the desired one.

Set Variable [ $r ; Value: MBS("CoreLocation.requestAlwaysAuthorization") ] 
Set Variable [ $status ; Value: MBS( "CoreLocation.authorizationStatus" ) ] 
If [ $status = "denied" ] 
	Show Custom Dialog [ "No authorization" ; "We do not have an authorization. Take a look to security settings." ] 
	Exit Script [ Text Result:    ] 
End If

If the authorization was successful, we can start querying the current position. The CoreLocation.startUpdatingLocation function is available for this purpose. You can then use the CoreLocation.hasLocation function to test whether a location has been found. Now we can query several pieces of information about the location. First of all, the time at which this position was determined. To do this, we use the CoreLocation.timestamp function, which, as the name suggests, returns a timestamp. We can also determine the longitude and latitude. We can find out exactly how these are specified using the CoreLocation.horizontalAccuracy function. We get back the radius in meters in which the location is located.

However, not only longitude and latitude can be determined, but also the height at which we are currently located. This information makes sense on a hike, for example. Use the CoreLocation.altitude function for this. Here, too, there is a function that returns the accuracy of this information (CoreLocation.verticalAccuracy).

...
Set Variable [ $r ; Value: MBS( "CoreLocation.startUpdatingLocation" ) ] 
If [ MBS("CoreLocation.hasLocation") ] 
	Set Field [ DoorEight::Time ; MBS("CoreLocation.timestamp") ] 
	Set Variable [ $Lat ; Value: MBS("CoreLocation.latitude") ] 
	Set Field [ DoorEight::Latitude ; $Lat ] 
	Set Variable [ $lon ; Value: MBS("CoreLocation.longitude") ] 
	Set Field [ DoorEight::Longitude ; $lon ] 
	Set Field [ DoorEight::Horizontal accuracy ; MBS("CoreLocation.horizontalAccuracy") ] 
	Set Field [ DoorEight::Altitude ; MBS("CoreLocation.altitude") ] 
	Set Field [ DoorEight::Vertical accuracy ; MBS("CoreLocation.verticalAccuracy") ] 
...

People who are gifted with miracles may be able to determine exactly where they are with the latitude and longitude information, but for most people it would be very useful if we additionally got an address. This is also possible with the CLGeocoder component from the plugin. The geocoder can provide the appropriate coordinates for an address, but also an address for coordinates. We use the CLGeocoder.ReverseGeocodeLocation for this. This function gives us a reference to the GeoCoder, from which we receive a JSON using the CLGeocoder.JSON function.

{
  "location" : {
    "verticalAccuracy" : -1,
    "longitude" : 7.2572950031855843,
    "horizontalAccuracy" : 100,
    "latitude" : 50.545874889063896,
    "timestamp" : "2023-12-03 16:30:29 +0000"
  },
  "region" : {
    "radius" : 70.756292662272614,
    "longitude" : 7.2574633999999998,
    "latitude" : 50.545909899999998,
    "identifier" : "<+50.54590990,+7.25746340> radius 70.76"
  },
  "cancelled" : 0,
  "timeZone" : {
    "abbreviation" : "CET",
    "secondsFromGMT" : 3600,
    "name" : "Europe\/Berlin"
  },
  "address" : "Lindenstraße 4\n53489 Sinzig\nGermany",
  "placemarks" : [
    {
      "ISOcountryCode" : "DE",
      "subThoroughfare" : "4",
      "areasOfInterest" : null,
      "subLocality" : "Sinzig",
      "administrativeArea" : "Rhineland-Palatinate",
      "country" : "Germany",
      "thoroughfare" : "Lindenstraße",
      "ocean" : null,
      "name" : "Lindenstraße 4",
      "postalCode" : "53489",
      "inlandWater" : null,
      "locality" : "Sinzig",
      "subAdministrativeArea" : "Ahrweiler"
    }
  ],
  "key" : "24002",
  "addressString" : null,
  "done" : 1,
  "error" : null,
  "started" : 1
}

We can then read out the address under the key "address". We then release the geocoder reference again by calling the CLGeocoder.Close function.

...
	If [ $Lat ≠ "" and $lon ≠ "" ] 
		Set Variable [ $Geo ; Value: MBS("CLGeocoder.ReverseGeocodeLocation"; $Lat; $lon; 1) ] 
		Set Variable [ $GeoJSON ; Value: MBS("CLGeocoder.JSON"; $Geo) ] 
		Set Variable [ $address ; Value: JSONGetElement ( $GeoJSON ; "address") ] 
		Set Variable [ $r ; Value: MBS("CLGeocoder.Close"; $Geo) ] 
		Set Field [ DoorEight::address ; $address ] 
	End If
...

A location like this can change from time to time if the device we are querying moves. We can use the functions CoreLocation.SetUpdateLocationEvaluate and CoreLocation.SetUpdateLocationHandler to specify an expression or a script that is executed when a new location has been detected. For a moving device, there is also other interesting information, such as the speed or the direction that you can query. If you no longer require new location updates, stop this process with CoreLocation.stopUpdatingLocation.

I hope this door helped you a little with your orientation. Maybe we'll read each other again tomorrow.


Monkeybread Software Logo with Monkey with Santa hat
7 👈 8 of 24 👉 9
08 12 23 - 10:05