[iOS 8] Location Notification を使って領域観測で通知する

iOS8

Location Notification

iOS 8 から Location Notification という新しいユーザー通知が定義されました。Location Notification とは、位置情報を使った領域観測でユーザーに情報を通知する機能のことです。これまで同様の機能を実装するためには Core Location フレームワークの CLLocationManager や CLLocationManagerDelegate などを使って実装していましたが、iOS 8 では UILocalNotification を使って簡単に実装できるようになりました。

ということで、Location Notification を実装する手順を解説したいと思います。

2014/11/14 更新
サンプルアプリを GitHub で公開しました!ぜひ参考にしてください。
suwa-yuki/LocationNotificationSample

プロジェクトの設定

Location Notification を使うためには Core Location フレームワーク が必要です。まずは何も考えずにプロジェクトの設定から追加しましょう。

location_notification01

位置情報の許可

さて、実装です。まず Location Notification を使うには、ユーザーに位置情報の利用を許可してもらう必要があります。AppDelegate などでリクエストする処理を実装します。

import UIKit
import CoreLocation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
                            
    var window: UIWindow?
    var manager: CLLocationManager!
    
    // MARK: - UIApplicationDelegate

    func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
        
        let settings = UIUserNotificationSettings(forTypes: .Alert | .Sound | .Badge, categories: nil)
        application.registerUserNotificationSettings(settings)
        
        self.manager = CLLocationManager()
        self.manager.delegate = self;
        self.manager.requestAlwaysAuthorization()
        
        return true
    }
    
    // MARK: - CLLocationManagerDelegate
    
    func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        switch status {
        case .Authorized, .AuthorizedWhenInUse:
            println("位置情報利用可")
            // Local Notificationを実行
            self.notification()
        default:
            println("位置情報利用不可")
        }
    }

}

なお、iOS 8 より CLAuthorizationStatus.AuthorizedWhenInUse という位置情報の許可の種類が増えました。CLAuthorizationStatus.AuthorizedWhenInUse が設定されている場合は、標準位置情報サービスと iBeacon のレンジング(距離観測) のみ利用可能です。iOS 7 までの実装方法で利用している場合は常に許可されているステータスになります。

この通知で表示されるメッセージは Info.plist でカスタマイズ可能です。NSLocationWhenInUseUsageDescription というキーを追加し、値にメッセージを設定します。なお、アプリ起動時のみ許可したい場合は NSLocationWhenInUseUsageDescription というキーを追加し、requestWhenInUseAuthorization() を呼ぶようにします。

location_notification02

実行すると、次のようなアラートが表示されます。

location_notification03

この位置情報の許可設定は設定の中にあるアプリ設定からアクセス可能です。

location_notification04

2014/11/18 追記
Local Notification は When In Use (アプリ利用時のみ許可) または Always (常に許可) のどちらのステータスでも受け取れます(UILocalNotification.h ヘッダ内に "in order to use region-triggered notifications, applications must have "when-in-use" authorization through CoreLocation." という記載があります)。情報を提供くださいましたkoogawaさん、ありがとうございました!

Location Notification の実装

Location Notification で通知するには UILocalNotification を利用します。

func notification() {
    
    println("scheduled notification")
    
    let coordinate = CLLocationCoordinate2DMake(35.697239, 139.774719)
    let radius = 100.0
    let identifier = "sample"
    
    let notification = UILocalNotification()
    notification.alertBody = "たどり着いた!"
    notification.regionTriggersOnce = true
    notification.region = CLCircularRegion(circularRegionWithCenter: coordinate, radius: radius, identifier: identifier)
    
    UIApplication.sharedApplication().scheduleLocalNotification(notification)
    
}

regionTriggersOnce はリージョン(領域)に入った時に繰り返し呼ぶか、という設定です。true の場合はリージョンに入った時に1度だけ通知され、false の場合はリージョンに入るたびに通知されます。region には開始対象のリージョンを指定します。ちなみに fireDate と一緒に指定するとエラーで強制終了します。

実行すると、次のように通知されます。

location_notification05

まとめ

UILocalNotification から通知できるようになったことで、ジオフェンシングから通知を送るような処理はより簡単になりました。一方で、位置情報のプライバシー許可の種類は増えているので注意して実装しましょう。

参考

  • koogawa

    いつもわかりやすい記事をありがとうございます。
    こちらの記事を参考にLocation Notification を実装しているのですが、なぜか領域観測が動作せずハマっております。(Objective-C で書いたからかも?)
    もしこの設定は注意した方が良い、などポイントがあれば教えて頂けないでしょうか?
    また、もし差し支えなければこちらの記事で使用したサンプルソース全体を見せて頂くことは可能でしょうか?
    お手数おかけしますが、よろしくお願い致しますm(_ _)m

    • suwa.yuki

      コメントいただきまして、ありがとうございます!

      注意点としましては、以下のような点が挙げられます。
      ・起動したデバイスの場所が指定した領域内の場合、通知されません。領域外で起動してから領域内に入ると通知されると思います。シミュレータで試すのが楽です。
      ・アプリの設定で、位置情報の許可が「常に許可」になっていないとバックグラウンドで通知されません。

      なお、サンプルソースを GitHub で公開しました(記事の本文中に掲載しました)。
      このアプリでシミュレータ、実機ともに動作を確認しています。

      ぜひご参考にしていただければと思います!

      • koogawa

        諏訪さん、ありがとうございます!
        無事通知ができました!

        私のソースがうまく動かなかった原因はまず
        scheduleLocalNotification(notification)
        のタイミングが早すぎたようです。
        (requestAlwaysAuthorizationの直後にセットしていました)

        諏訪さんのソース通り、
        didChangeAuthorizationStatus
        デリゲートが呼ばれたタイミングでNotificationをセットすることでうまくいきました。

        また、
        let settings = UIUserNotificationSettings(forTypes: .Alert | .Sound | .Badge, categories: nil)
        application.registerUserNotificationSettings(settings)
        これがなかったのも原因でした。

        本当にありがとうございました!m(_ _)m

        • suwa.yuki

          コメントありがとうございます!
          無事に動作したようで良かったです!

          なるほど、ユーザー認証周りの流れに問題があったのですね。
          記事のソースコードが足りなかったですね。。申し訳ありませんでした。
          後ほど修正いたします。

          貴重な情報ありがとうございました!

          • koogawa

            追加でわかったことを共有させて頂きます

            > アプリの設定で、位置情報の許可が「常に許可」になっていないとバックグラウンドで通知されません。

            「使用中のみ許可」でも通知されるようです(動作確認済み)

            UILocalNotification.h ヘッダ内にも

            “in order to use region-triggered notifications, applications must have “when-in-use” authorization through CoreLocation.”

            という表記がありました!

          • suwa.yuki

            情報を共有いただきまして、ありがとうございます!

            こちらでも動作を確認いたしました。
            koogawaさんの仰るとおり、確かに”When In Use”のときでも通知が受け取れますね。
            上記の情報をブログに追記いたしました。

            この度は、誠にありがとうございましたm(_ _)m

      • Guest

        追加でわかったことを共有させて頂きます

        > ・アプリの設定で、位置情報の許可が「常に許可」になっていないとバックグラウンドで通知されません。

        「使用中のみ許可」でも通知されるようです(動作確認済み)

        UILocalNotification.h ヘッダ内にも

        “in order to use region-triggered notifications, applications must have “when-in-use” authorization through CoreLocation.”

        という表記がありました!

        • koogawa

          ↑誤操作で未ログインのまま投稿してしまいましたm(_ _)m ※可能であれば削除をお願いします