Location Notifications with UNLocationNotificationTrigger
Learn how to use UNLocationNotificationTrigger to set up location-triggered notifications for your iOS app. By Graham Connolly.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Location Notifications with UNLocationNotificationTrigger
30 mins
- Getting Started
- What Is Core Location?
- Setting Up Core Location
- Creating a Geofence
- Placing an Order
- Monitoring User Location
- Location Authorization
- Requesting Location Authorization
- Triggering a Location Notification on Arrival
- Notification Authorization
- Using UNLocationNotificationTrigger to Notify the User
- Handling Notification Action
- Simulating User Movement
- Connecting to a physical device
- Simulating the Journey
- Handling a Geofence Entry Event
- Alerting the Kitchen
- Getting Background Updates
- Where to Go From Here?
Geofencing, often called region monitoring, alerts your app when it enters or exits a geographical region. An example of this is an app that alerts users of offers when entering their favorite coffee shop, or an app that alerts the user to check-in on arriving at the dentist. Geofencing in iOS is a powerful feature, and you can use it to drive location-triggered notifications, using UNLocationNotificationTrigger. The feature works when an app is active, in the background, suspended or terminated — all without requiring users to always provide access to their location and sacrifice their privacy.
In this tutorial, you’ll add region monitoring to Swifty TakeOut, which is a simple app that allows users to place an order for pickup.
You’ll enhance the app by alerting users when they arrive using UNLocationNotificationTrigger
. Users can then notify the kitchen they are “here” to collect their order.
Along the way, you’ll not only learn what Core Location is, but also how to:
- Set up Core Location.
- Register a geofence.
- Ask the user for permission to use location services.
- Enable the location update background mode capability.
- Notify users of a geofence entry event.
- Register a
UNLocationNotificationTrigger
.
Getting Started
Download the starter project by clicking the Download Materials button at the top or bottom of the tutorial.
In the starter project, you’ll find Swifty TakeOut, an app that displays a list of takeout items available for order. Users can later pick up their orders at the Swifty TakeOut location.
Build and run to check out the app:
The app allows users to select a food item:
It also lets them place an order:
In Xcode, look at the main files you’ll be working with:
-
TakeOutStore.swift contains a
struct
representing the takeout store. -
LocationManager.swift contains an
ObservableObject
, which is where the magic happens. -
MenuItem.swift contains a
struct
representing a menu item and an array of menu items. - MenuListView.swift displays a list of items available for order.
- MenuListRow.swift represents a row item for the menu.
- DetailView.swift displays the details of the selected item.
In this tutorial, you’ll learn how to show an alert when a user arrives at the Swifty TakeOut restaurant. You’ll do this by registering a geofence and using UNLocationNotificationTrigger
set to trigger on that geofence.
But first, you’ll learn a bit more about Core Location.
What Is Core Location?
Core Location is an Apple framework that provides many services to get geographical information from a user’s device. Using the API, you can determine the device’s location, altitude, heading and orientation. Additionally, if any iBeacons (Bluetooth advertisements) are in the vicinity, you can detect and locate them.
The geographic information comes from the device’s hardware components. Where available, that includes Wi-Fi, GPS, Bluetooth, magnetometer, barometer and cellular radio.
Everything revolves around CLLocationManager. You’ll use it to start, stop and configure the delivery of location events in Swifty TakeOut. You can also set its properties to different accuracies and use region monitoring to watch for a user entering or leaving distinct areas.
Setting Up Core Location
Before you can detect if a user enters a geographical region, you’ll need to set up Core Location. To do so, you’ll create an instance of CLLocationManager
.
Open LocationManager.swift and add the following code under the location
property, inside LocationManager
:
// 1
lazy var locationManager = makeLocationManager()
// 2
private func makeLocationManager() -> CLLocationManager {
// 3
let manager = CLLocationManager()
// 4
return manager
}
Here’s what this code does:
- Adds an instance property to store the location manager. A
lazy
property delays initialization until it’s first used. - Declares a method that creates and configures
CLLocationManager
. - Creates an instance of the location manager.
- Returns the configured
CLLocationManager
object.
With a location manager configured, you’ll now register your geographical point of interest.
CLLocationManager
to the property rather than use the method, but some additional configuration of the CLLocationManager
object is needed later.
Creating a Geofence
To create a geofence in iOS, you need to configure a CLCircularRegion. This object consists of a center point and a radius, in meters. An entry event will notify your app when the device moves from outside to inside the radius.
An exit event gets triggered when going from inside to outside the radius.
Next, while still in LocationManager.swift, configure your region by adding the following code under makeLocationManager()
:
// 1
private func makeStoreRegion() -> CLCircularRegion {
// 2
let region = CLCircularRegion(
center: location,
radius: 2,
identifier: UUID().uuidString)
// 3
region.notifyOnEntry = true
// 4
return region
}
Here’s what this code does:
- Declares a method that creates a
CLCircularRegion
. - Creates a
CLCircularRegion
instance. The center point islocation
, which is the latitude and longitude of Swifty TakeOut. The radius is two meters, and a unique identifier is associated. - Configures
region
to trigger a notification when an entry event occurs. - Returns the configured region.
With that added, configure a property to use this returned value. Add the code below the location
property:
lazy var storeRegion = makeStoreRegion()
Now that you have set up this utility methods, you need to get the user’s permission to use location information. You’ll do that next.
Placing an Order
The main functionality of Swifty TakeOut is ordering food. When users place a food order, they receive a confirmation alert. This confirmation alert also asks if they’d like to get notified on arrival. Some restaurants offer to bring food out to your car if you select curbside pickup when ordering. When you arrive, you have to tell the restaurant “I’m here!”, so they can bring the food out to your car. In the next few sections, you’ll add this functionality.
Monitoring User Location
For notifications when a region boundary is crossed, you need to start tracking the location of the device. To do this, you’ll need to request authorization from the user.
Back in LocationManager.swift, add the following method under makeStoreRegion()
:
// 1
func validateLocationAuthorizationStatus() {
// 2
switch locationManager.authorizationStatus {
// 3
case .notDetermined, .denied, .restricted:
// 4
print("Location Services Not Authorized")
// 5
case .authorizedWhenInUse, .authorizedAlways:
// 6
print("Location Services Authorized")
default:
break
}
}
Here, you’ve added code that:
- Creates a method named
validateLocationAuthorizationStatus()
that determines the app’s authorization status for using location services. - Configures a
switch
statement on the current authorization status of the app. - Validates the current authorization value against
.notDetermined
,.denied
or.restricted
. If there’s a match, then the code block for thiscase
gets executed. - Prints to the debugger if location services isn’t authorized.
- Checks the current authorization value matches
.authorizedWhenInUse
or.authorizedAlways
. - Prints to the debugger if authorized.
You will request to track the user’s location after they place an order. The user’s location is then used to determine if the geofence has been breached.
Next, open DetailView.swift. requestNotification()
is called if the user agrees to get notified on arrival. Update this method to confirm the location services authorization status:
func requestNotification() {
locationManager.validateLocationAuthorizationStatus()
}
With this code added, it’s time to test out what you’ve added.
Build and run:
- Select a food item.
- Place an order.
- Tap Yes to get notified on arrival.
You should see the following printed to the debugger:
Next, you’ll request the user’s permission to allow Swifty TakeOut to use location services.