見出し画像

【IT技術】【Swift】指定した場所の近くに着いた時にアラームを起動して通知する

こんにちは。ラフアンドレディ(株)iOS大好き 春蔵です。

今回は地図系アプリでよくある、テキスト入力された場所の近くに到達した時に、アラームを起動する処理をご紹介します。

地図の表示や座標の取得などの処理は、下記の記事を参照してください。

また、スマホで位置情報を特定するためのGPS機能は、地下やトンネル内では使用できない事が殆どです。
アプリの公開時には、その旨を注意事項として書くことをお薦めします。

サンプルアプリの動作説明


検索欄に目的地を入力後、📍ボタンを押下すると、現在地の監視が始まります。サンプルアプリをバックグラウンド状態にし、現在地を目的地に変更すると通知が行われます。
現在地を目的地に変更する方法は、また別の記事で紹介したいと思います。

なお、位置によるアラーム機能はバグのせいか、シミュレータでは動作しないです。。。
実機によるデバッグをお薦めします。(2023年1月時点)


バックグラウンド時に位置情報を取得を許可する

Location Updatesにチェックを入れます。

使用許諾の文言を設定

バックグラウンドで位置情報を取得する旨の使用許諾の文言を以下のキーで設定します。(括弧内は多言語対応していた場合、InfoPlist.stringsに設定するキー)

  • Privacy - Location When In Use Usage Description (NSLocationWhenInUseUsageDescription)

  • Privacy - Location Always Usage Description  (NSLocationAlwaysUsageDescription)

  • Privacy - Location Always and When In Use Usage Description (NSLocationAlwaysAndWhenInUseUsageDescription)


位置情報の使用許諾を要求

・・・
    /// ロケーションマネージャー
    let locationManager = CLLocationManager()
・・・
    /// 通知の許可
    func requestAuthorization(){
        // 通知の許可
        UNUserNotificationCenter.current().requestAuthorization(
        options: [.alert, .sound]){
            (granted, _) in
            if granted{
                // 使用中に位置情報の取得を許可
                self.locationManager.requestWhenInUseAuthorization()
            }
        }
    }

ユーザーに通知の許可、アプリの使用中に位置情報の監視の許可を要求します。


既存通知の削除

    // 通知の削除
    func remove(_ id : String){
        print("remove notification identifier:" + String(id))

        // 通知の取得
        for identifier in getAll(){
            // 文字列の部分一致
            if(identifier.hasPrefix(id)){
                print("remove notification identifier:" + String(identifier))
                
                // ペンディング中の通知の削除
                UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [identifier])
                // 通知済の通知の削除
                UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [identifier])
            }
        }
        
        // ロケーション監視の停止
        stopRegionMonitoring(id)
    }

後述の通知の作成と重複して通知情報が作成されないよう、既存の通知の削除を行います。(同じ場所に対して重複した通知がされない等、作成するアプリの仕様によります。)

通知は、まだ発行されていないペンディング中の通知、通知済の通知の2種類があります。
通知ID指定で、ペンディング中、通知済の通知より削除します。

特定の座標に入った時、アラームを起動する

   /// 場所通知
    /// - Parameters:
    ///   - latitude: 緯度
    ///   - longitude: 軽度
    ///   - radius: 半径
    ///   - identifier: identifier
    ///   - sound: サウンドファイル名
    ///   - message: メッセージ
    func locateNotification(latitude:Double , longitude:Double , radius:Double ,identifier :String
                            , sound:String , message : String){
        print("Notification latitude:\(latitude) , longitude:\(longitude) , radius:\(radius), sound:\(sound) , message:\(message)")
        
        // ロケーション作成
        let coordinate = CLLocationCoordinate2DMake(latitude, longitude)
        // 範囲を作成
        let region = CLCircularRegion.init(center: coordinate, radius: radius, identifier: identifier)
        // 範囲の中から外への移動は通知しないが、範囲の外から中へは通知する設定
        region.notifyOnExit = false
        region.notifyOnEntry = true
        // 作成した範囲に入った時に通知をするトリガーを作成
        let trigger = UNLocationNotificationTrigger(region: region, repeats: false)

        //通知する内容を作成
        let content = UNMutableNotificationContent()
        let notificationSound = UNNotificationSoundName(rawValue: sound)
        
        content.title = self.appName
        content.body = message
        content.sound = UNNotificationSound(named: notificationSound)
        content.categoryIdentifier = appName

        // 通知要求
        let request = UNNotificationRequest(identifier: identifier,
                                            content: content,
                                            trigger: trigger)
        
        // 通知追加
        UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)

        /// モニタリング開始
        startUpdatingLocation(region)
    }

UNLocationNotificationTriggerのパラメータであるregionで経度、緯度、範囲を指定し、その範囲に入った時にアラームが起動するトリガー(UNLocationNotificationTrigger)を作成します。
そのトリガーをもとに、通知ID、通知メッセージ、通知サウンドを指定したUNNotificationRequestを作成し、通知情報を追加します。

位置情報の監視開始

   /// ロケーション監視開始
    func startUpdatingLocation(_ region:CLCircularRegion? = nil){
        // 既に開始済みの場合、開始しない
        if status == .start { return }
        // ステータス設定
        status = .start
        // Backgroundでの位置情報の更新を許可する
        locationManager.allowsBackgroundLocationUpdates = true
        // 精度-10m以内
        locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        // 更新頻度(m)
        locationManager.distanceFilter = 10
        // 移動タイプ
        locationManager.activityType = .automotiveNavigation
        // 位置情報の監視開始
        locationManager.startUpdatingLocation()

        if let region = region {
            locationManager.startMonitoring(for: region)
        }
    }

アプリで現在の位置情報の監視を行います。その際、精度、更新頻度を指定します。
バッテリーの消耗に関わるパラメータなので、アプリの使用目的に合わせたパラメータの設定をお薦めします。

位置情報の監視停止

    /// ロケーション監視停止
    func stopUpdatingLocation() {
        // ロケーションの監視停止
        locationManager.stopUpdatingLocation()
        // ステータス変更
        status = .stop
    }

現在の位置情報の監視の停止を行います。位置情報の監視はバッテリーの消耗に関わるので、通知を行う必要がない場合は、監視の停止を行います。


コードサンプル

今回紹介したサンプルの全コードです

サンプルアプリケーション

今回紹介した位置情報の技術を利用したiOSアプリです。


それではまた!楽しいSwiftライフを!

春蔵のSwift講座

───-- - - - 

フォロー Me!
↓ ↓
Twitter : @RandR_inc

◆───-- - - - 

ラフアンドレディでの採用はこちら ↓ ↓ ↓

ラフアンドレディでは、みんなのびのびと仕事をしています!エンジニアが長く幸せに活躍できる環境で、仲間と楽しく働いてみませんか?

この記事が参加している募集

つくってみた

この記事が気に入ったらサポートをしてみませんか?