基本的な流れは、最初に「通知の許可を取る」で、その後に「通知をすることを決めたタイミングで位置情報を元に通知のリクエストを登録する」です。
サンプルでは、「アプリがバックグラウンドに入った時に通知のリクエストを登録」しています。
サンプルでは半径15メートルの領域(region)に入ったら通知をするに設定していますが、試してみると結構大雑把で範囲は思っているよりも広い感じです。
位置情報を元に通知をする肝はUNLocationNotificationTriggerです。
また、他のサイトのサンプルでは、UNUserNotificationCenterをクラス変数に保存してないのですが、私の場合はそれではうまく動かなかったのでクラス変数に保存して、その変数に対して変更を加えています。
SceneDelegate.swift
import UIKit import UserNotifications import CoreLocation class SceneDelegate: UIResponder, UIWindowSceneDelegate, UNUserNotificationCenterDelegate { var window: UIWindow? //クラス変数を作っておく var center: UNUserNotificationCenter! func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let _ = (scene as? UIWindowScene) else { return } //このサンプルは実際には13以上 if #available(iOS 10.0, *) { //iOS 10 //クラス変数に保存 center = UNUserNotificationCenter.current() //ユーザに通知の許可を求める center.requestAuthorization(options: [.badge,.sound,.alert], completionHandler: { (granted, error) in if error != nil { return } if granted { print("通知許可") center.delegate = self } else { print("通知拒否") } }) } else { //iOS 9 } } func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). } func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). print("sceneWillResignActive") //この部分は一例です。 //ユーザデフォルトに保存してある位置を読み込んでいます。 let config = UserDefaults.standard var dLatitude: Double var dLongitude: Doublea dLatitude = config.double(forKey: "Latitude") dLongitude = config.double(forKey: "Longitude") //保存したのを読み込んだ位置から作りだす let coordinate = CLLocationCoordinate2DMake(dLatitude, dLongitude) print("\(dLatitude), \(dLongitude)") //範囲を作成。ここでは半径15メートルの範囲 let region = CLCircularRegion.init(center: coordinate, radius: 15, identifier: "MY_NOTIFICATION") //範囲の中から外への移動は通知しないが、範囲の外から中へは通知する設定 region.notifyOnExit = false region.notifyOnEntry = true //作成した範囲に入った時に通知をするトリガーを作成 let trigger: UNNotificationTrigger = UNLocationNotificationTrigger(region: region, repeats: false) //通知する内容を作成 let content = UNMutableNotificationContent() content.title = "" content.body = "通知ですよ。" //通知の時に音を設定 content.sound = UNNotificationSound.default //通知のリクエストを作成 let request = UNNotificationRequest(identifier: "uuid", content: content, trigger: trigger) //通知のリクエストを登録 self.center.add(request, withCompletionHandler: nil) } func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } func sceneDidEnterBackground(_ scene: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. print("sceneDidEnterBackground") } }