New in SwiftUI and iOS 15: LocationButton

DevTechie Inc
Apr 6, 2022

User’s location is probably the most sought out permission after notifications but its also the most sensitive piece of information. Over the years, Apple has invested lots of time to make sure that user’s information is not shared without their knowledge.

This also mean that when apps need user’s location permission they have to jump though many hoops to make it possible. While it is worth investing time when app relies on location for the most part like map based apps, but what about apps who need location permission just once:

  • Maybe you are digitally signing a form and for legal reasons, your app wants to capture location of user where form was signed
  • Or getting your location once so you can share it with your friend, you are meeting in a park or concert.
For all these one time scenarios, Apple introduced LocationButton in iOS 15 for both SwiftUI and UIKit. We will talk about SwiftUI’s LocationButton in this article.

LocationButton makes it easy to request one-time location authorization. When user taps on the button, app requests one-time temporary access to user’s location data. User is presented with permission dialog like below:

CoreLocation framework is still responsible for managing location related information including querying the location data but this button simplifies the process of requesting authorization and when user taps “OK”, app gets temporary access to their location with temporary CLAuthorizationStatus.authorizedWhenInUse authorization. This authorization expires when app is no longer in use.

To better understand, we will put together a simple example which will show user’s current location on map. Like mentioned before, CoreLocation is still responsible for managing location API calls so we will first create an observable LocationManager class which will publish location updates.

Frameworks we will need to import:

import CoreLocation
import CoreLocationUI
import MapKit
import SwiftUI
LocationManager class

class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    let manager = CLLocationManager()
    private static let locationDistance: CLLocationDistance = 10000
    
    @Published var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 37.779541987632896, longitude: -122.43090553769848), latitudinalMeters: LocationManager.locationDistance, longitudinalMeters: LocationManager.locationDistance)
    
    override init() {
        super.init()
        manager.activityType = .automotiveNavigation
        manager.delegate = self
    }
    
    func requestLocation() {
        manager.requestLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.first else { return }
        
        DispatchQueue.main.async {
            self.region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: Self.locationDistance, longitudinalMeters: Self.locationDistance)
        }
        
        print("\(location)")
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error.localizedDescription)
    }
}
In this class we are initializing default region with San Francisco’s coordinates and then we are updating the region based on user’s location when requestLocation method is called from UI.

struct LocationButtonExample: View {
    
    @StateObject var locationManager = LocationManager()
    
    var body: some View {
        ZStack(alignment: .bottom) {
            Map(coordinateRegion: $locationManager.region, showsUserLocation: true)
                .edgesIgnoringSafeArea(.all)
            
            LocationButton {
                locationManager.requestLocation()
            }
            .cornerRadius(20)
            .labelStyle(.titleAndIcon)
            .symbolVariant(.fill)
            .foregroundColor(Color.white)
        }
    }
}
Output:


With that, we have reached the end of this article. Thank you once again for reading, if you liked it, don’t forget to subscribe our newsletter.